PostgreSQL Source Code git master
aclchk.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * aclchk.c
4 * Routines to check access control permissions.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/catalog/aclchk.c
12 *
13 * NOTES
14 * See acl.h.
15 *
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.
20 *
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.
26 *
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.
32 *
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.
36 *
37 *-------------------------------------------------------------------------
38 */
39#include "postgres.h"
40
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"
48#include "catalog/catalog.h"
49#include "catalog/dependency.h"
50#include "catalog/indexing.h"
52#include "catalog/pg_authid.h"
53#include "catalog/pg_class.h"
54#include "catalog/pg_database.h"
59#include "catalog/pg_language.h"
64#include "catalog/pg_proc.h"
66#include "catalog/pg_type.h"
67#include "commands/defrem.h"
69#include "commands/extension.h"
70#include "commands/proclang.h"
71#include "commands/tablespace.h"
72#include "foreign/foreign.h"
73#include "miscadmin.h"
74#include "nodes/makefuncs.h"
75#include "parser/parse_func.h"
76#include "parser/parse_type.h"
77#include "storage/lmgr.h"
78#include "utils/acl.h"
80#include "utils/builtins.h"
81#include "utils/fmgroids.h"
82#include "utils/guc.h"
83#include "utils/lsyscache.h"
84#include "utils/rel.h"
85#include "utils/syscache.h"
86
87/*
88 * Internal format used by ALTER DEFAULT PRIVILEGES.
89 */
90typedef struct
91{
92 Oid roleid; /* owning role */
93 Oid nspid; /* namespace, or InvalidOid if none */
94 /* remaining fields are same as in InternalGrant: */
103
104/*
105 * When performing a binary-upgrade, pg_dump will call a function to set
106 * this variable to let us know that we need to populate the pg_init_privs
107 * table for the GRANT/REVOKE commands while this variable is set to true.
108 */
110
111static void ExecGrantStmt_oids(InternalGrant *istmt);
112static void ExecGrant_Relation(InternalGrant *istmt);
113static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
114 void (*object_check) (InternalGrant *istmt, HeapTuple tuple));
115static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple);
116static void ExecGrant_Largeobject(InternalGrant *istmt);
117static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple);
118static void ExecGrant_Parameter(InternalGrant *istmt);
119
120static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
121static void SetDefaultACL(InternalDefaultACL *iacls);
122
123static List *objectNamesToOids(ObjectType objtype, List *objnames,
124 bool is_grant);
125static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
126static List *getRelationsInNamespace(Oid namespaceId, char relkind);
127static void expand_col_privileges(List *colnames, Oid table_oid,
128 AclMode this_privileges,
129 AclMode *col_privileges,
130 int num_col_privileges);
131static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
132 AclMode this_privileges,
133 AclMode *col_privileges,
134 int num_col_privileges);
135static AclMode string_to_privilege(const char *privname);
136static const char *privilege_to_string(AclMode privilege);
137static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
138 bool all_privs, AclMode privileges,
139 Oid objectId, Oid grantorId,
140 ObjectType objtype, const char *objname,
141 AttrNumber att_number, const char *colname);
142static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum,
143 Oid roleid, AclMode mask, AclMaskHow how);
144static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid,
145 AclMode mask, AclMaskHow how);
146static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
147 AclMode mask, AclMaskHow how,
148 bool *is_missing);
150 Oid roleid, AclMode mask, AclMaskHow how);
152 Oid roleid, AclMode mask,
153 AclMaskHow how, bool *is_missing);
154static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid,
155 AclMode mask, AclMaskHow how,
156 bool *is_missing);
157static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
158 AclMode mask, AclMaskHow how);
159static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
160 AclMode mask, AclMaskHow how, Snapshot snapshot);
161static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
162 AclMode mask, AclMaskHow how,
163 bool *is_missing);
164static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid,
165 AclMode mask, AclMaskHow how,
166 bool *is_missing);
167static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
168 Acl *new_acl);
169static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
170 Acl *new_acl);
171
172
173/*
174 * If is_grant is true, adds the given privileges for the list of
175 * grantees to the existing old_acl. If is_grant is false, the
176 * privileges for the given grantees are removed from old_acl.
177 *
178 * NB: the original old_acl is pfree'd.
179 */
180static Acl *
181merge_acl_with_grant(Acl *old_acl, bool is_grant,
182 bool grant_option, DropBehavior behavior,
183 List *grantees, AclMode privileges,
184 Oid grantorId, Oid ownerId)
185{
186 unsigned modechg;
187 ListCell *j;
188 Acl *new_acl;
189
190 modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
191
192 new_acl = old_acl;
193
194 foreach(j, grantees)
195 {
196 AclItem aclitem;
197 Acl *newer_acl;
198
199 aclitem.ai_grantee = lfirst_oid(j);
200
201 /*
202 * Grant options can only be granted to individual roles, not PUBLIC.
203 * The reason is that if a user would re-grant a privilege that he
204 * held through PUBLIC, and later the user is removed, the situation
205 * is impossible to clean up.
206 */
207 if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
209 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
210 errmsg("grant options can only be granted to roles")));
211
212 aclitem.ai_grantor = grantorId;
213
214 /*
215 * The asymmetry in the conditions here comes from the spec. In
216 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
217 * to grant both the basic privilege and its grant option. But in
218 * REVOKE, plain revoke revokes both the basic privilege and its grant
219 * option, while REVOKE GRANT OPTION revokes only the option.
220 */
222 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
223 (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
224
225 newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
226
227 /* avoid memory leak when there are many grantees */
228 pfree(new_acl);
229 new_acl = newer_acl;
230 }
231
232 return new_acl;
233}
234
235/*
236 * Restrict the privileges to what we can actually grant, and emit
237 * the standards-mandated warning and error messages.
238 */
239static AclMode
240restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
241 AclMode privileges, Oid objectId, Oid grantorId,
242 ObjectType objtype, const char *objname,
243 AttrNumber att_number, const char *colname)
244{
245 AclMode this_privileges;
246 AclMode whole_mask;
247
248 switch (objtype)
249 {
250 case OBJECT_COLUMN:
251 whole_mask = ACL_ALL_RIGHTS_COLUMN;
252 break;
253 case OBJECT_TABLE:
254 whole_mask = ACL_ALL_RIGHTS_RELATION;
255 break;
256 case OBJECT_SEQUENCE:
257 whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
258 break;
259 case OBJECT_DATABASE:
260 whole_mask = ACL_ALL_RIGHTS_DATABASE;
261 break;
262 case OBJECT_FUNCTION:
263 whole_mask = ACL_ALL_RIGHTS_FUNCTION;
264 break;
265 case OBJECT_LANGUAGE:
266 whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
267 break;
269 whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
270 break;
271 case OBJECT_SCHEMA:
272 whole_mask = ACL_ALL_RIGHTS_SCHEMA;
273 break;
275 whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
276 break;
277 case OBJECT_FDW:
278 whole_mask = ACL_ALL_RIGHTS_FDW;
279 break;
282 break;
284 elog(ERROR, "grantable rights not supported for event triggers");
285 /* not reached, but keep compiler quiet */
286 return ACL_NO_RIGHTS;
287 case OBJECT_TYPE:
288 whole_mask = ACL_ALL_RIGHTS_TYPE;
289 break;
291 whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
292 break;
293 default:
294 elog(ERROR, "unrecognized object type: %d", objtype);
295 /* not reached, but keep compiler quiet */
296 return ACL_NO_RIGHTS;
297 }
298
299 /*
300 * If we found no grant options, consider whether to issue a hard error.
301 * Per spec, having any privilege at all on the object will get you by
302 * here.
303 */
304 if (avail_goptions == ACL_NO_RIGHTS)
305 {
306 if (pg_aclmask(objtype, objectId, att_number, grantorId,
307 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
309 {
310 if (objtype == OBJECT_COLUMN && colname)
311 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
312 else
313 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
314 }
315 }
316
317 /*
318 * Restrict the operation to what we can actually grant or revoke, and
319 * issue a warning if appropriate. (For REVOKE this isn't quite what the
320 * spec says to do: the spec seems to want a warning only if no privilege
321 * bits actually change in the ACL. In practice that behavior seems much
322 * too noisy, as well as inconsistent with the GRANT case.)
323 */
324 this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
325 if (is_grant)
326 {
327 if (this_privileges == 0)
328 {
329 if (objtype == OBJECT_COLUMN && colname)
331 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
332 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
333 colname, objname)));
334 else
336 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
337 errmsg("no privileges were granted for \"%s\"",
338 objname)));
339 }
340 else if (!all_privs && this_privileges != privileges)
341 {
342 if (objtype == OBJECT_COLUMN && colname)
344 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
345 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
346 colname, objname)));
347 else
349 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
350 errmsg("not all privileges were granted for \"%s\"",
351 objname)));
352 }
353 }
354 else
355 {
356 if (this_privileges == 0)
357 {
358 if (objtype == OBJECT_COLUMN && colname)
360 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
361 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
362 colname, objname)));
363 else
365 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
366 errmsg("no privileges could be revoked for \"%s\"",
367 objname)));
368 }
369 else if (!all_privs && this_privileges != privileges)
370 {
371 if (objtype == OBJECT_COLUMN && colname)
373 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
374 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
375 colname, objname)));
376 else
378 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
379 errmsg("not all privileges could be revoked for \"%s\"",
380 objname)));
381 }
382 }
383
384 return this_privileges;
385}
386
387/*
388 * Called to execute the utility commands GRANT and REVOKE
389 */
390void
392{
393 InternalGrant istmt;
394 ListCell *cell;
395 const char *errormsg;
396 AclMode all_privileges;
397
398 if (stmt->grantor)
399 {
400 Oid grantor;
401
402 grantor = get_rolespec_oid(stmt->grantor, false);
403
404 /*
405 * Currently, this clause is only for SQL compatibility, not very
406 * interesting otherwise.
407 */
408 if (grantor != GetUserId())
410 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
411 errmsg("grantor must be current user")));
412 }
413
414 /*
415 * Turn the regular GrantStmt into the InternalGrant form.
416 */
417 istmt.is_grant = stmt->is_grant;
418 istmt.objtype = stmt->objtype;
419
420 /* Collect the OIDs of the target objects */
421 switch (stmt->targtype)
422 {
424 istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
425 stmt->is_grant);
426 break;
428 istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
429 break;
430 /* ACL_TARGET_DEFAULTS should not be seen here */
431 default:
432 elog(ERROR, "unrecognized GrantStmt.targtype: %d",
433 (int) stmt->targtype);
434 }
435
436 /* all_privs to be filled below */
437 /* privileges to be filled below */
438 istmt.col_privs = NIL; /* may get filled below */
439 istmt.grantees = NIL; /* filled below */
440 istmt.grant_option = stmt->grant_option;
441 istmt.behavior = stmt->behavior;
442
443 /*
444 * Convert the RoleSpec list into an Oid list. Note that at this point we
445 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
446 * there shouldn't be any additional work needed to support this case.
447 */
448 foreach(cell, stmt->grantees)
449 {
450 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
451 Oid grantee_uid;
452
453 switch (grantee->roletype)
454 {
455 case ROLESPEC_PUBLIC:
456 grantee_uid = ACL_ID_PUBLIC;
457 break;
458 default:
459 grantee_uid = get_rolespec_oid(grantee, false);
460 break;
461 }
462 istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
463 }
464
465 /*
466 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
467 * bitmask. Note: objtype can't be OBJECT_COLUMN.
468 */
469 switch (stmt->objtype)
470 {
471 case OBJECT_TABLE:
472
473 /*
474 * Because this might be a sequence, we test both relation and
475 * sequence bits, and later do a more limited test when we know
476 * the object type.
477 */
479 errormsg = gettext_noop("invalid privilege type %s for relation");
480 break;
481 case OBJECT_SEQUENCE:
482 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
483 errormsg = gettext_noop("invalid privilege type %s for sequence");
484 break;
485 case OBJECT_DATABASE:
486 all_privileges = ACL_ALL_RIGHTS_DATABASE;
487 errormsg = gettext_noop("invalid privilege type %s for database");
488 break;
489 case OBJECT_DOMAIN:
490 all_privileges = ACL_ALL_RIGHTS_TYPE;
491 errormsg = gettext_noop("invalid privilege type %s for domain");
492 break;
493 case OBJECT_FUNCTION:
494 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
495 errormsg = gettext_noop("invalid privilege type %s for function");
496 break;
497 case OBJECT_LANGUAGE:
498 all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
499 errormsg = gettext_noop("invalid privilege type %s for language");
500 break;
502 all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
503 errormsg = gettext_noop("invalid privilege type %s for large object");
504 break;
505 case OBJECT_SCHEMA:
506 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
507 errormsg = gettext_noop("invalid privilege type %s for schema");
508 break;
509 case OBJECT_PROCEDURE:
510 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
511 errormsg = gettext_noop("invalid privilege type %s for procedure");
512 break;
513 case OBJECT_ROUTINE:
514 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
515 errormsg = gettext_noop("invalid privilege type %s for routine");
516 break;
518 all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
519 errormsg = gettext_noop("invalid privilege type %s for tablespace");
520 break;
521 case OBJECT_TYPE:
522 all_privileges = ACL_ALL_RIGHTS_TYPE;
523 errormsg = gettext_noop("invalid privilege type %s for type");
524 break;
525 case OBJECT_FDW:
526 all_privileges = ACL_ALL_RIGHTS_FDW;
527 errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
528 break;
530 all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
531 errormsg = gettext_noop("invalid privilege type %s for foreign server");
532 break;
534 all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
535 errormsg = gettext_noop("invalid privilege type %s for parameter");
536 break;
537 default:
538 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
539 (int) stmt->objtype);
540 /* keep compiler quiet */
541 all_privileges = ACL_NO_RIGHTS;
542 errormsg = NULL;
543 }
544
545 if (stmt->privileges == NIL)
546 {
547 istmt.all_privs = true;
548
549 /*
550 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
551 * depending on the object type
552 */
554 }
555 else
556 {
557 istmt.all_privs = false;
559
560 foreach(cell, stmt->privileges)
561 {
562 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
563 AclMode priv;
564
565 /*
566 * If it's a column-level specification, we just set it aside in
567 * col_privs for the moment; but insist it's for a relation.
568 */
569 if (privnode->cols)
570 {
571 if (stmt->objtype != OBJECT_TABLE)
573 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
574 errmsg("column privileges are only valid for relations")));
575 istmt.col_privs = lappend(istmt.col_privs, privnode);
576 continue;
577 }
578
579 if (privnode->priv_name == NULL) /* parser mistake? */
580 elog(ERROR, "AccessPriv node must specify privilege or columns");
581 priv = string_to_privilege(privnode->priv_name);
582
583 if (priv & ~all_privileges)
585 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
586 errmsg(errormsg, privilege_to_string(priv))));
587
588 istmt.privileges |= priv;
589 }
590 }
591
592 ExecGrantStmt_oids(&istmt);
593}
594
595/*
596 * ExecGrantStmt_oids
597 *
598 * Internal entry point for granting and revoking privileges.
599 */
600static void
602{
603 switch (istmt->objtype)
604 {
605 case OBJECT_TABLE:
606 case OBJECT_SEQUENCE:
607 ExecGrant_Relation(istmt);
608 break;
609 case OBJECT_DATABASE:
610 ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
611 break;
612 case OBJECT_DOMAIN:
613 case OBJECT_TYPE:
615 break;
616 case OBJECT_FDW:
617 ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
618 break;
620 ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
621 break;
622 case OBJECT_FUNCTION:
623 case OBJECT_PROCEDURE:
624 case OBJECT_ROUTINE:
625 ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
626 break;
627 case OBJECT_LANGUAGE:
629 break;
632 break;
633 case OBJECT_SCHEMA:
634 ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
635 break;
637 ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
638 break;
640 ExecGrant_Parameter(istmt);
641 break;
642 default:
643 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
644 (int) istmt->objtype);
645 }
646
647 /*
648 * Pass the info to event triggers about the just-executed GRANT. Note
649 * that we prefer to do it after actually executing it, because that gives
650 * the functions a chance to adjust the istmt with privileges actually
651 * granted.
652 */
655}
656
657/*
658 * objectNamesToOids
659 *
660 * Turn a list of object names of a given type into an Oid list.
661 *
662 * XXX This function intentionally takes only an AccessShareLock. In the face
663 * of concurrent DDL, we might easily latch onto an old version of an object,
664 * causing the GRANT or REVOKE statement to fail. But it does prevent the
665 * object from disappearing altogether. To do better, we would need to use a
666 * self-exclusive lock, perhaps ShareUpdateExclusiveLock, here and before
667 * *every* CatalogTupleUpdate() of a row that GRANT/REVOKE can affect.
668 * Besides that additional work, this could have operational costs. For
669 * example, it would make GRANT ALL TABLES IN SCHEMA terminate every
670 * autovacuum running in the schema and consume a shared lock table entry per
671 * table in the schema. The user-visible benefit of that additional work is
672 * just changing "ERROR: tuple concurrently updated" to blocking. That's not
673 * nothing, but it might not outweigh autovacuum termination and lock table
674 * consumption spikes.
675 */
676static List *
677objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
678{
679 List *objects = NIL;
680 ListCell *cell;
681 const LOCKMODE lockmode = AccessShareLock;
682
683 Assert(objnames != NIL);
684
685 switch (objtype)
686 {
687 default:
688
689 /*
690 * For most object types, we use get_object_address() directly.
691 */
692 foreach(cell, objnames)
693 {
694 ObjectAddress address;
695
696 address = get_object_address(objtype, lfirst(cell), NULL, lockmode, false);
697 objects = lappend_oid(objects, address.objectId);
698 }
699 break;
700
701 case OBJECT_TABLE:
702 case OBJECT_SEQUENCE:
703
704 /*
705 * Here, we don't use get_object_address(). It requires that the
706 * specified object type match the actual type of the object, but
707 * in GRANT/REVOKE, all table-like things are addressed as TABLE.
708 */
709 foreach(cell, objnames)
710 {
711 RangeVar *relvar = (RangeVar *) lfirst(cell);
712 Oid relOid;
713
714 relOid = RangeVarGetRelid(relvar, lockmode, false);
715 objects = lappend_oid(objects, relOid);
716 }
717 break;
718
719 case OBJECT_DOMAIN:
720 case OBJECT_TYPE:
721
722 /*
723 * The parse representation of types and domains in privilege
724 * targets is different from that expected by get_object_address()
725 * (for parse conflict reasons), so we have to do a bit of
726 * conversion here.
727 */
728 foreach(cell, objnames)
729 {
730 List *typname = (List *) lfirst(cell);
732 ObjectAddress address;
733 Relation relation;
734
735 address = get_object_address(objtype, (Node *) tn, &relation, lockmode, false);
736 Assert(relation == NULL);
737 objects = lappend_oid(objects, address.objectId);
738 }
739 break;
740
742
743 /*
744 * Parameters are handled completely differently.
745 */
746 foreach(cell, objnames)
747 {
748 /*
749 * In this code we represent a GUC by the OID of its entry in
750 * pg_parameter_acl, which we have to manufacture here if it
751 * doesn't exist yet. (That's a hack for sure, but it avoids
752 * messing with all the GRANT/REVOKE infrastructure that
753 * expects to use OIDs for object identities.) However, if
754 * this is a REVOKE, we can instead just ignore any GUCs that
755 * don't have such an entry, as they must not have any
756 * privileges needing removal.
757 */
758 char *parameter = strVal(lfirst(cell));
759 Oid parameterId = ParameterAclLookup(parameter, true);
760
761 if (!OidIsValid(parameterId) && is_grant)
762 {
763 parameterId = ParameterAclCreate(parameter);
764
765 /*
766 * Prevent error when processing duplicate objects, and
767 * make this new entry visible so that ExecGrant_Parameter
768 * can update it.
769 */
771 }
772 if (OidIsValid(parameterId))
773 objects = lappend_oid(objects, parameterId);
774 }
775 break;
776 }
777
778 return objects;
779}
780
781/*
782 * objectsInSchemaToOids
783 *
784 * Find all objects of a given type in specified schemas, and make a list
785 * of their Oids. We check USAGE privilege on the schemas, but there is
786 * no privilege checking on the individual objects here.
787 */
788static List *
790{
791 List *objects = NIL;
792 ListCell *cell;
793
794 foreach(cell, nspnames)
795 {
796 char *nspname = strVal(lfirst(cell));
797 Oid namespaceId;
798 List *objs;
799
800 namespaceId = LookupExplicitNamespace(nspname, false);
801
802 switch (objtype)
803 {
804 case OBJECT_TABLE:
805 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
806 objects = list_concat(objects, objs);
807 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
808 objects = list_concat(objects, objs);
809 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
810 objects = list_concat(objects, objs);
811 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
812 objects = list_concat(objects, objs);
813 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
814 objects = list_concat(objects, objs);
815 break;
816 case OBJECT_SEQUENCE:
817 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
818 objects = list_concat(objects, objs);
819 break;
820 case OBJECT_FUNCTION:
821 case OBJECT_PROCEDURE:
822 case OBJECT_ROUTINE:
823 {
824 ScanKeyData key[2];
825 int keycount;
826 Relation rel;
827 TableScanDesc scan;
828 HeapTuple tuple;
829
830 keycount = 0;
831 ScanKeyInit(&key[keycount++],
832 Anum_pg_proc_pronamespace,
833 BTEqualStrategyNumber, F_OIDEQ,
834 ObjectIdGetDatum(namespaceId));
835
836 if (objtype == OBJECT_FUNCTION)
837 /* includes aggregates and window functions */
838 ScanKeyInit(&key[keycount++],
839 Anum_pg_proc_prokind,
840 BTEqualStrategyNumber, F_CHARNE,
841 CharGetDatum(PROKIND_PROCEDURE));
842 else if (objtype == OBJECT_PROCEDURE)
843 ScanKeyInit(&key[keycount++],
844 Anum_pg_proc_prokind,
845 BTEqualStrategyNumber, F_CHAREQ,
846 CharGetDatum(PROKIND_PROCEDURE));
847
848 rel = table_open(ProcedureRelationId, AccessShareLock);
849 scan = table_beginscan_catalog(rel, keycount, key);
850
851 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
852 {
853 Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
854
855 objects = lappend_oid(objects, oid);
856 }
857
858 table_endscan(scan);
860 }
861 break;
862 default:
863 /* should not happen */
864 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
865 (int) objtype);
866 }
867 }
868
869 return objects;
870}
871
872/*
873 * getRelationsInNamespace
874 *
875 * Return Oid list of relations in given namespace filtered by relation kind
876 */
877static List *
878getRelationsInNamespace(Oid namespaceId, char relkind)
879{
880 List *relations = NIL;
881 ScanKeyData key[2];
882 Relation rel;
883 TableScanDesc scan;
884 HeapTuple tuple;
885
886 ScanKeyInit(&key[0],
887 Anum_pg_class_relnamespace,
888 BTEqualStrategyNumber, F_OIDEQ,
889 ObjectIdGetDatum(namespaceId));
890 ScanKeyInit(&key[1],
891 Anum_pg_class_relkind,
892 BTEqualStrategyNumber, F_CHAREQ,
893 CharGetDatum(relkind));
894
895 rel = table_open(RelationRelationId, AccessShareLock);
896 scan = table_beginscan_catalog(rel, 2, key);
897
898 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
899 {
900 Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
901
902 relations = lappend_oid(relations, oid);
903 }
904
905 table_endscan(scan);
907
908 return relations;
909}
910
911
912/*
913 * ALTER DEFAULT PRIVILEGES statement
914 */
915void
917{
918 GrantStmt *action = stmt->action;
919 InternalDefaultACL iacls;
920 ListCell *cell;
921 List *rolespecs = NIL;
922 List *nspnames = NIL;
923 DefElem *drolespecs = NULL;
924 DefElem *dnspnames = NULL;
925 AclMode all_privileges;
926 const char *errormsg;
927
928 /* Deconstruct the "options" part of the statement */
929 foreach(cell, stmt->options)
930 {
931 DefElem *defel = (DefElem *) lfirst(cell);
932
933 if (strcmp(defel->defname, "schemas") == 0)
934 {
935 if (dnspnames)
936 errorConflictingDefElem(defel, pstate);
937 dnspnames = defel;
938 }
939 else if (strcmp(defel->defname, "roles") == 0)
940 {
941 if (drolespecs)
942 errorConflictingDefElem(defel, pstate);
943 drolespecs = defel;
944 }
945 else
946 elog(ERROR, "option \"%s\" not recognized", defel->defname);
947 }
948
949 if (dnspnames)
950 nspnames = (List *) dnspnames->arg;
951 if (drolespecs)
952 rolespecs = (List *) drolespecs->arg;
953
954 /* Prepare the InternalDefaultACL representation of the statement */
955 /* roleid to be filled below */
956 /* nspid to be filled in SetDefaultACLsInSchemas */
957 iacls.is_grant = action->is_grant;
958 iacls.objtype = action->objtype;
959 /* all_privs to be filled below */
960 /* privileges to be filled below */
961 iacls.grantees = NIL; /* filled below */
962 iacls.grant_option = action->grant_option;
963 iacls.behavior = action->behavior;
964
965 /*
966 * Convert the RoleSpec list into an Oid list. Note that at this point we
967 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
968 * there shouldn't be any additional work needed to support this case.
969 */
970 foreach(cell, action->grantees)
971 {
972 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
973 Oid grantee_uid;
974
975 switch (grantee->roletype)
976 {
977 case ROLESPEC_PUBLIC:
978 grantee_uid = ACL_ID_PUBLIC;
979 break;
980 default:
981 grantee_uid = get_rolespec_oid(grantee, false);
982 break;
983 }
984 iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
985 }
986
987 /*
988 * Convert action->privileges, a list of privilege strings, into an
989 * AclMode bitmask.
990 */
991 switch (action->objtype)
992 {
993 case OBJECT_TABLE:
994 all_privileges = ACL_ALL_RIGHTS_RELATION;
995 errormsg = gettext_noop("invalid privilege type %s for relation");
996 break;
997 case OBJECT_SEQUENCE:
998 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
999 errormsg = gettext_noop("invalid privilege type %s for sequence");
1000 break;
1001 case OBJECT_FUNCTION:
1002 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1003 errormsg = gettext_noop("invalid privilege type %s for function");
1004 break;
1005 case OBJECT_PROCEDURE:
1006 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1007 errormsg = gettext_noop("invalid privilege type %s for procedure");
1008 break;
1009 case OBJECT_ROUTINE:
1010 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1011 errormsg = gettext_noop("invalid privilege type %s for routine");
1012 break;
1013 case OBJECT_TYPE:
1014 all_privileges = ACL_ALL_RIGHTS_TYPE;
1015 errormsg = gettext_noop("invalid privilege type %s for type");
1016 break;
1017 case OBJECT_SCHEMA:
1018 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
1019 errormsg = gettext_noop("invalid privilege type %s for schema");
1020 break;
1021 case OBJECT_LARGEOBJECT:
1022 all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
1023 errormsg = gettext_noop("invalid privilege type %s for large object");
1024 break;
1025 default:
1026 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1027 (int) action->objtype);
1028 /* keep compiler quiet */
1029 all_privileges = ACL_NO_RIGHTS;
1030 errormsg = NULL;
1031 }
1032
1033 if (action->privileges == NIL)
1034 {
1035 iacls.all_privs = true;
1036
1037 /*
1038 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1039 * depending on the object type
1040 */
1041 iacls.privileges = ACL_NO_RIGHTS;
1042 }
1043 else
1044 {
1045 iacls.all_privs = false;
1046 iacls.privileges = ACL_NO_RIGHTS;
1047
1048 foreach(cell, action->privileges)
1049 {
1050 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1051 AclMode priv;
1052
1053 if (privnode->cols)
1054 ereport(ERROR,
1055 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1056 errmsg("default privileges cannot be set for columns")));
1057
1058 if (privnode->priv_name == NULL) /* parser mistake? */
1059 elog(ERROR, "AccessPriv node must specify privilege");
1060 priv = string_to_privilege(privnode->priv_name);
1061
1062 if (priv & ~all_privileges)
1063 ereport(ERROR,
1064 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1065 errmsg(errormsg, privilege_to_string(priv))));
1066
1067 iacls.privileges |= priv;
1068 }
1069 }
1070
1071 if (rolespecs == NIL)
1072 {
1073 /* Set permissions for myself */
1074 iacls.roleid = GetUserId();
1075
1076 SetDefaultACLsInSchemas(&iacls, nspnames);
1077 }
1078 else
1079 {
1080 /* Look up the role OIDs and do permissions checks */
1081 ListCell *rolecell;
1082
1083 foreach(rolecell, rolespecs)
1084 {
1085 RoleSpec *rolespec = lfirst(rolecell);
1086
1087 iacls.roleid = get_rolespec_oid(rolespec, false);
1088
1089 if (!has_privs_of_role(GetUserId(), iacls.roleid))
1090 ereport(ERROR,
1091 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1092 errmsg("permission denied to change default privileges")));
1093
1094 SetDefaultACLsInSchemas(&iacls, nspnames);
1095 }
1096 }
1097}
1098
1099/*
1100 * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1101 *
1102 * All fields of *iacls except nspid were filled already
1103 */
1104static void
1106{
1107 if (nspnames == NIL)
1108 {
1109 /* Set database-wide permissions if no schema was specified */
1110 iacls->nspid = InvalidOid;
1111
1112 SetDefaultACL(iacls);
1113 }
1114 else
1115 {
1116 /* Look up the schema OIDs and set permissions for each one */
1117 ListCell *nspcell;
1118
1119 foreach(nspcell, nspnames)
1120 {
1121 char *nspname = strVal(lfirst(nspcell));
1122
1123 iacls->nspid = get_namespace_oid(nspname, false);
1124
1125 /*
1126 * We used to insist that the target role have CREATE privileges
1127 * on the schema, since without that it wouldn't be able to create
1128 * an object for which these default privileges would apply.
1129 * However, this check proved to be more confusing than helpful,
1130 * and it also caused certain database states to not be
1131 * dumpable/restorable, since revoking CREATE doesn't cause
1132 * default privileges for the schema to go away. So now, we just
1133 * allow the ALTER; if the user lacks CREATE he'll find out when
1134 * he tries to create an object.
1135 */
1136
1137 SetDefaultACL(iacls);
1138 }
1139 }
1140}
1141
1142
1143/*
1144 * Create or update a pg_default_acl entry
1145 */
1146static void
1148{
1149 AclMode this_privileges = iacls->privileges;
1150 char objtype;
1151 Relation rel;
1152 HeapTuple tuple;
1153 bool isNew;
1154 Acl *def_acl;
1155 Acl *old_acl;
1156 Acl *new_acl;
1157 HeapTuple newtuple;
1158 int noldmembers;
1159 int nnewmembers;
1160 Oid *oldmembers;
1161 Oid *newmembers;
1162
1163 rel = table_open(DefaultAclRelationId, RowExclusiveLock);
1164
1165 /*
1166 * The default for a global entry is the hard-wired default ACL for the
1167 * particular object type. The default for non-global entries is an empty
1168 * ACL. This must be so because global entries replace the hard-wired
1169 * defaults, while others are added on.
1170 */
1171 if (!OidIsValid(iacls->nspid))
1172 def_acl = acldefault(iacls->objtype, iacls->roleid);
1173 else
1174 def_acl = make_empty_acl();
1175
1176 /*
1177 * Convert ACL object type to pg_default_acl object type and handle
1178 * all_privs option
1179 */
1180 switch (iacls->objtype)
1181 {
1182 case OBJECT_TABLE:
1183 objtype = DEFACLOBJ_RELATION;
1184 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1185 this_privileges = ACL_ALL_RIGHTS_RELATION;
1186 break;
1187
1188 case OBJECT_SEQUENCE:
1189 objtype = DEFACLOBJ_SEQUENCE;
1190 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1191 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1192 break;
1193
1194 case OBJECT_FUNCTION:
1195 objtype = DEFACLOBJ_FUNCTION;
1196 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1197 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
1198 break;
1199
1200 case OBJECT_TYPE:
1201 objtype = DEFACLOBJ_TYPE;
1202 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1203 this_privileges = ACL_ALL_RIGHTS_TYPE;
1204 break;
1205
1206 case OBJECT_SCHEMA:
1207 if (OidIsValid(iacls->nspid))
1208 ereport(ERROR,
1209 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1210 errmsg("cannot use IN SCHEMA clause when using %s",
1211 "GRANT/REVOKE ON SCHEMAS")));
1212 objtype = DEFACLOBJ_NAMESPACE;
1213 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1214 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1215 break;
1216
1217 case OBJECT_LARGEOBJECT:
1218 if (OidIsValid(iacls->nspid))
1219 ereport(ERROR,
1220 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1221 errmsg("cannot use IN SCHEMA clause when using %s",
1222 "GRANT/REVOKE ON LARGE OBJECTS")));
1223 objtype = DEFACLOBJ_LARGEOBJECT;
1224 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1225 this_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
1226 break;
1227
1228 default:
1229 elog(ERROR, "unrecognized object type: %d",
1230 (int) iacls->objtype);
1231 objtype = 0; /* keep compiler quiet */
1232 break;
1233 }
1234
1235 /* Search for existing row for this object type in catalog */
1236 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1237 ObjectIdGetDatum(iacls->roleid),
1238 ObjectIdGetDatum(iacls->nspid),
1239 CharGetDatum(objtype));
1240
1241 if (HeapTupleIsValid(tuple))
1242 {
1243 Datum aclDatum;
1244 bool isNull;
1245
1246 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1247 Anum_pg_default_acl_defaclacl,
1248 &isNull);
1249 if (!isNull)
1250 old_acl = DatumGetAclPCopy(aclDatum);
1251 else
1252 old_acl = NULL; /* this case shouldn't happen, probably */
1253 isNew = false;
1254 }
1255 else
1256 {
1257 old_acl = NULL;
1258 isNew = true;
1259 }
1260
1261 if (old_acl != NULL)
1262 {
1263 /*
1264 * We need the members of both old and new ACLs so we can correct the
1265 * shared dependency information. Collect data before
1266 * merge_acl_with_grant throws away old_acl.
1267 */
1268 noldmembers = aclmembers(old_acl, &oldmembers);
1269 }
1270 else
1271 {
1272 /* If no or null entry, start with the default ACL value */
1273 old_acl = aclcopy(def_acl);
1274 /* There are no old member roles according to the catalogs */
1275 noldmembers = 0;
1276 oldmembers = NULL;
1277 }
1278
1279 /*
1280 * Generate new ACL. Grantor of rights is always the same as the target
1281 * role.
1282 */
1283 new_acl = merge_acl_with_grant(old_acl,
1284 iacls->is_grant,
1285 iacls->grant_option,
1286 iacls->behavior,
1287 iacls->grantees,
1288 this_privileges,
1289 iacls->roleid,
1290 iacls->roleid);
1291
1292 /*
1293 * If the result is the same as the default value, we do not need an
1294 * explicit pg_default_acl entry, and should in fact remove the entry if
1295 * it exists. Must sort both arrays to compare properly.
1296 */
1297 aclitemsort(new_acl);
1298 aclitemsort(def_acl);
1299 if (aclequal(new_acl, def_acl))
1300 {
1301 /* delete old entry, if indeed there is one */
1302 if (!isNew)
1303 {
1304 ObjectAddress myself;
1305
1306 /*
1307 * The dependency machinery will take care of removing all
1308 * associated dependency entries. We use DROP_RESTRICT since
1309 * there shouldn't be anything depending on this entry.
1310 */
1311 myself.classId = DefaultAclRelationId;
1312 myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1313 myself.objectSubId = 0;
1314
1315 performDeletion(&myself, DROP_RESTRICT, 0);
1316 }
1317 }
1318 else
1319 {
1320 Datum values[Natts_pg_default_acl] = {0};
1321 bool nulls[Natts_pg_default_acl] = {0};
1322 bool replaces[Natts_pg_default_acl] = {0};
1323 Oid defAclOid;
1324
1325 if (isNew)
1326 {
1327 /* insert new entry */
1328 defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1329 Anum_pg_default_acl_oid);
1330 values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1331 values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1332 values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1333 values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1334 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1335
1336 newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1337 CatalogTupleInsert(rel, newtuple);
1338 }
1339 else
1340 {
1341 defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1342
1343 /* update existing entry */
1344 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1345 replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1346
1347 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1348 values, nulls, replaces);
1349 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1350 }
1351
1352 /* these dependencies don't change in an update */
1353 if (isNew)
1354 {
1355 /* dependency on role */
1356 recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1357 iacls->roleid);
1358
1359 /* dependency on namespace */
1360 if (OidIsValid(iacls->nspid))
1361 {
1362 ObjectAddress myself,
1363 referenced;
1364
1365 myself.classId = DefaultAclRelationId;
1366 myself.objectId = defAclOid;
1367 myself.objectSubId = 0;
1368
1369 referenced.classId = NamespaceRelationId;
1370 referenced.objectId = iacls->nspid;
1371 referenced.objectSubId = 0;
1372
1373 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1374 }
1375 }
1376
1377 /*
1378 * Update the shared dependency ACL info
1379 */
1380 nnewmembers = aclmembers(new_acl, &newmembers);
1381
1382 updateAclDependencies(DefaultAclRelationId,
1383 defAclOid, 0,
1384 iacls->roleid,
1385 noldmembers, oldmembers,
1386 nnewmembers, newmembers);
1387
1388 if (isNew)
1389 InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1390 else
1391 InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1392 }
1393
1394 if (HeapTupleIsValid(tuple))
1395 ReleaseSysCache(tuple);
1396
1398
1399 /* prevent error when processing duplicate objects */
1401}
1402
1403
1404/*
1405 * RemoveRoleFromObjectACL
1406 *
1407 * Used by shdepDropOwned to remove mentions of a role in ACLs.
1408 *
1409 * Notice that this doesn't accept an objsubid parameter, which is a bit bogus
1410 * since the pg_shdepend record that caused us to call it certainly had one.
1411 * If, for example, pg_shdepend records the existence of a permission on
1412 * mytable.mycol, this function will effectively issue a REVOKE ALL ON TABLE
1413 * mytable. That gets the job done because (per SQL spec) such a REVOKE also
1414 * revokes per-column permissions. We could not recreate a situation where
1415 * the role has table-level but not column-level permissions; but it's okay
1416 * (for now anyway) because this is only used when we're dropping the role
1417 * and so all its permissions everywhere must go away. At worst it's a bit
1418 * inefficient if the role has column permissions on several columns of the
1419 * same table.
1420 */
1421void
1422RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1423{
1424 if (classid == DefaultAclRelationId)
1425 {
1426 InternalDefaultACL iacls;
1427 Form_pg_default_acl pg_default_acl_tuple;
1428 Relation rel;
1429 ScanKeyData skey[1];
1430 SysScanDesc scan;
1431 HeapTuple tuple;
1432
1433 /* first fetch info needed by SetDefaultACL */
1434 rel = table_open(DefaultAclRelationId, AccessShareLock);
1435
1436 ScanKeyInit(&skey[0],
1437 Anum_pg_default_acl_oid,
1438 BTEqualStrategyNumber, F_OIDEQ,
1439 ObjectIdGetDatum(objid));
1440
1441 scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1442 NULL, 1, skey);
1443
1444 tuple = systable_getnext(scan);
1445
1446 if (!HeapTupleIsValid(tuple))
1447 elog(ERROR, "could not find tuple for default ACL %u", objid);
1448
1449 pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1450
1451 iacls.roleid = pg_default_acl_tuple->defaclrole;
1452 iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1453
1454 switch (pg_default_acl_tuple->defaclobjtype)
1455 {
1456 case DEFACLOBJ_RELATION:
1457 iacls.objtype = OBJECT_TABLE;
1458 break;
1459 case DEFACLOBJ_SEQUENCE:
1460 iacls.objtype = OBJECT_SEQUENCE;
1461 break;
1462 case DEFACLOBJ_FUNCTION:
1463 iacls.objtype = OBJECT_FUNCTION;
1464 break;
1465 case DEFACLOBJ_TYPE:
1466 iacls.objtype = OBJECT_TYPE;
1467 break;
1468 case DEFACLOBJ_NAMESPACE:
1469 iacls.objtype = OBJECT_SCHEMA;
1470 break;
1471 case DEFACLOBJ_LARGEOBJECT:
1473 break;
1474 default:
1475 /* Shouldn't get here */
1476 elog(ERROR, "unexpected default ACL type: %d",
1477 (int) pg_default_acl_tuple->defaclobjtype);
1478 break;
1479 }
1480
1481 systable_endscan(scan);
1483
1484 iacls.is_grant = false;
1485 iacls.all_privs = true;
1486 iacls.privileges = ACL_NO_RIGHTS;
1487 iacls.grantees = list_make1_oid(roleid);
1488 iacls.grant_option = false;
1489 iacls.behavior = DROP_CASCADE;
1490
1491 /* Do it */
1492 SetDefaultACL(&iacls);
1493 }
1494 else
1495 {
1496 InternalGrant istmt;
1497
1498 switch (classid)
1499 {
1500 case RelationRelationId:
1501 /* it's OK to use TABLE for a sequence */
1502 istmt.objtype = OBJECT_TABLE;
1503 break;
1504 case DatabaseRelationId:
1505 istmt.objtype = OBJECT_DATABASE;
1506 break;
1507 case TypeRelationId:
1508 istmt.objtype = OBJECT_TYPE;
1509 break;
1510 case ProcedureRelationId:
1511 istmt.objtype = OBJECT_ROUTINE;
1512 break;
1513 case LanguageRelationId:
1514 istmt.objtype = OBJECT_LANGUAGE;
1515 break;
1516 case LargeObjectRelationId:
1518 break;
1519 case NamespaceRelationId:
1520 istmt.objtype = OBJECT_SCHEMA;
1521 break;
1522 case TableSpaceRelationId:
1523 istmt.objtype = OBJECT_TABLESPACE;
1524 break;
1525 case ForeignServerRelationId:
1527 break;
1528 case ForeignDataWrapperRelationId:
1529 istmt.objtype = OBJECT_FDW;
1530 break;
1531 case ParameterAclRelationId:
1533 break;
1534 default:
1535 elog(ERROR, "unexpected object class %u", classid);
1536 break;
1537 }
1538 istmt.is_grant = false;
1539 istmt.objects = list_make1_oid(objid);
1540 istmt.all_privs = true;
1541 istmt.privileges = ACL_NO_RIGHTS;
1542 istmt.col_privs = NIL;
1543 istmt.grantees = list_make1_oid(roleid);
1544 istmt.grant_option = false;
1545 istmt.behavior = DROP_CASCADE;
1546
1547 ExecGrantStmt_oids(&istmt);
1548 }
1549}
1550
1551
1552/*
1553 * expand_col_privileges
1554 *
1555 * OR the specified privilege(s) into per-column array entries for each
1556 * specified attribute. The per-column array is indexed starting at
1557 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1558 */
1559static void
1560expand_col_privileges(List *colnames, Oid table_oid,
1561 AclMode this_privileges,
1562 AclMode *col_privileges,
1563 int num_col_privileges)
1564{
1565 ListCell *cell;
1566
1567 foreach(cell, colnames)
1568 {
1569 char *colname = strVal(lfirst(cell));
1571
1572 attnum = get_attnum(table_oid, colname);
1574 ereport(ERROR,
1575 (errcode(ERRCODE_UNDEFINED_COLUMN),
1576 errmsg("column \"%s\" of relation \"%s\" does not exist",
1577 colname, get_rel_name(table_oid))));
1579 if (attnum <= 0 || attnum >= num_col_privileges)
1580 elog(ERROR, "column number out of range"); /* safety check */
1581 col_privileges[attnum] |= this_privileges;
1582 }
1583}
1584
1585/*
1586 * expand_all_col_privileges
1587 *
1588 * OR the specified privilege(s) into per-column array entries for each valid
1589 * attribute of a relation. The per-column array is indexed starting at
1590 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1591 */
1592static void
1594 AclMode this_privileges,
1595 AclMode *col_privileges,
1596 int num_col_privileges)
1597{
1598 AttrNumber curr_att;
1599
1600 Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1601 for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1602 curr_att <= classForm->relnatts;
1603 curr_att++)
1604 {
1605 HeapTuple attTuple;
1606 bool isdropped;
1607
1608 if (curr_att == InvalidAttrNumber)
1609 continue;
1610
1611 /* Views don't have any system columns at all */
1612 if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1613 continue;
1614
1615 attTuple = SearchSysCache2(ATTNUM,
1616 ObjectIdGetDatum(table_oid),
1617 Int16GetDatum(curr_att));
1618 if (!HeapTupleIsValid(attTuple))
1619 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1620 curr_att, table_oid);
1621
1622 isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1623
1624 ReleaseSysCache(attTuple);
1625
1626 /* ignore dropped columns */
1627 if (isdropped)
1628 continue;
1629
1630 col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1631 }
1632}
1633
1634/*
1635 * This processes attributes, but expects to be called from
1636 * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1637 */
1638static void
1639ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1640 AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1641 Relation attRelation, const Acl *old_rel_acl)
1642{
1643 HeapTuple attr_tuple;
1644 Form_pg_attribute pg_attribute_tuple;
1645 Acl *old_acl;
1646 Acl *new_acl;
1647 Acl *merged_acl;
1648 Datum aclDatum;
1649 bool isNull;
1650 Oid grantorId;
1651 AclMode avail_goptions;
1652 bool need_update;
1653 HeapTuple newtuple;
1654 Datum values[Natts_pg_attribute] = {0};
1655 bool nulls[Natts_pg_attribute] = {0};
1656 bool replaces[Natts_pg_attribute] = {0};
1657 int noldmembers;
1658 int nnewmembers;
1659 Oid *oldmembers;
1660 Oid *newmembers;
1661
1662 attr_tuple = SearchSysCache2(ATTNUM,
1663 ObjectIdGetDatum(relOid),
1665 if (!HeapTupleIsValid(attr_tuple))
1666 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1667 attnum, relOid);
1668 pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1669
1670 /*
1671 * Get working copy of existing ACL. If there's no ACL, substitute the
1672 * proper default.
1673 */
1674 aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1675 &isNull);
1676 if (isNull)
1677 {
1678 old_acl = acldefault(OBJECT_COLUMN, ownerId);
1679 /* There are no old member roles according to the catalogs */
1680 noldmembers = 0;
1681 oldmembers = NULL;
1682 }
1683 else
1684 {
1685 old_acl = DatumGetAclPCopy(aclDatum);
1686 /* Get the roles mentioned in the existing ACL */
1687 noldmembers = aclmembers(old_acl, &oldmembers);
1688 }
1689
1690 /*
1691 * In select_best_grantor we should consider existing table-level ACL bits
1692 * as well as the per-column ACL. Build a new ACL that is their
1693 * concatenation. (This is a bit cheap and dirty compared to merging them
1694 * properly with no duplications, but it's all we need here.)
1695 */
1696 merged_acl = aclconcat(old_rel_acl, old_acl);
1697
1698 /* Determine ID to do the grant as, and available grant options */
1699 select_best_grantor(GetUserId(), col_privileges,
1700 merged_acl, ownerId,
1701 &grantorId, &avail_goptions);
1702
1703 pfree(merged_acl);
1704
1705 /*
1706 * Restrict the privileges to what we can actually grant, and emit the
1707 * standards-mandated warning and error messages. Note: we don't track
1708 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1709 * each column; we just approximate it by whether all the possible
1710 * privileges are specified now. Since the all_privs flag only determines
1711 * whether a warning is issued, this seems close enough.
1712 */
1713 col_privileges =
1714 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1715 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1716 col_privileges,
1717 relOid, grantorId, OBJECT_COLUMN,
1718 relname, attnum,
1719 NameStr(pg_attribute_tuple->attname));
1720
1721 /*
1722 * Generate new ACL.
1723 */
1724 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1725 istmt->grant_option,
1726 istmt->behavior, istmt->grantees,
1727 col_privileges, grantorId,
1728 ownerId);
1729
1730 /*
1731 * We need the members of both old and new ACLs so we can correct the
1732 * shared dependency information.
1733 */
1734 nnewmembers = aclmembers(new_acl, &newmembers);
1735
1736 /* finished building new ACL value, now insert it */
1737
1738 /*
1739 * If the updated ACL is empty, we can set attacl to null, and maybe even
1740 * avoid an update of the pg_attribute row. This is worth testing because
1741 * we'll come through here multiple times for any relation-level REVOKE,
1742 * even if there were never any column GRANTs. Note we are assuming that
1743 * the "default" ACL state for columns is empty.
1744 */
1745 if (ACL_NUM(new_acl) > 0)
1746 {
1747 values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1748 need_update = true;
1749 }
1750 else
1751 {
1752 nulls[Anum_pg_attribute_attacl - 1] = true;
1753 need_update = !isNull;
1754 }
1755 replaces[Anum_pg_attribute_attacl - 1] = true;
1756
1757 if (need_update)
1758 {
1759 newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1760 values, nulls, replaces);
1761
1762 CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1763
1764 /* Update initial privileges for extensions */
1765 recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1766 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1767
1768 /* Update the shared dependency ACL info */
1769 updateAclDependencies(RelationRelationId, relOid, attnum,
1770 ownerId,
1771 noldmembers, oldmembers,
1772 nnewmembers, newmembers);
1773 }
1774
1775 pfree(new_acl);
1776
1777 ReleaseSysCache(attr_tuple);
1778}
1779
1780/*
1781 * This processes both sequences and non-sequences.
1782 */
1783static void
1785{
1786 Relation relation;
1787 Relation attRelation;
1788 ListCell *cell;
1789
1790 relation = table_open(RelationRelationId, RowExclusiveLock);
1791 attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1792
1793 foreach(cell, istmt->objects)
1794 {
1795 Oid relOid = lfirst_oid(cell);
1796 Datum aclDatum;
1797 Form_pg_class pg_class_tuple;
1798 bool isNull;
1799 AclMode this_privileges;
1800 AclMode *col_privileges;
1801 int num_col_privileges;
1802 bool have_col_privileges;
1803 Acl *old_acl;
1804 Acl *old_rel_acl;
1805 int noldmembers;
1806 Oid *oldmembers;
1807 Oid ownerId;
1808 HeapTuple tuple;
1809 ListCell *cell_colprivs;
1810
1811 tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relOid));
1812 if (!HeapTupleIsValid(tuple))
1813 elog(ERROR, "cache lookup failed for relation %u", relOid);
1814 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1815
1816 /* Not sensible to grant on an index */
1817 if (pg_class_tuple->relkind == RELKIND_INDEX ||
1818 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1819 ereport(ERROR,
1820 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1821 errmsg("\"%s\" is an index",
1822 NameStr(pg_class_tuple->relname))));
1823
1824 /* Composite types aren't tables either */
1825 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1826 ereport(ERROR,
1827 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1828 errmsg("\"%s\" is a composite type",
1829 NameStr(pg_class_tuple->relname))));
1830
1831 /* Used GRANT SEQUENCE on a non-sequence? */
1832 if (istmt->objtype == OBJECT_SEQUENCE &&
1833 pg_class_tuple->relkind != RELKIND_SEQUENCE)
1834 ereport(ERROR,
1835 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1836 errmsg("\"%s\" is not a sequence",
1837 NameStr(pg_class_tuple->relname))));
1838
1839 /* Adjust the default permissions based on object type */
1840 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1841 {
1842 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1843 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1844 else
1845 this_privileges = ACL_ALL_RIGHTS_RELATION;
1846 }
1847 else
1848 this_privileges = istmt->privileges;
1849
1850 /*
1851 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1852 * so we have to look at the relkind to determine the supported
1853 * permissions. The OR of table and sequence permissions were already
1854 * checked.
1855 */
1856 if (istmt->objtype == OBJECT_TABLE)
1857 {
1858 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1859 {
1860 /*
1861 * For backward compatibility, just throw a warning for
1862 * invalid sequence permissions when using the non-sequence
1863 * GRANT syntax.
1864 */
1865 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1866 {
1867 /*
1868 * Mention the object name because the user needs to know
1869 * which operations succeeded. This is required because
1870 * WARNING allows the command to continue.
1871 */
1873 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1874 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1875 NameStr(pg_class_tuple->relname))));
1876 this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1877 }
1878 }
1879 else
1880 {
1881 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1882 {
1883 /*
1884 * USAGE is the only permission supported by sequences but
1885 * not by non-sequences. Don't mention the object name
1886 * because we didn't in the combined TABLE | SEQUENCE
1887 * check.
1888 */
1889 ereport(ERROR,
1890 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1891 errmsg("invalid privilege type %s for table",
1892 "USAGE")));
1893 }
1894 }
1895 }
1896
1897 /*
1898 * Set up array in which we'll accumulate any column privilege bits
1899 * that need modification. The array is indexed such that entry [0]
1900 * corresponds to FirstLowInvalidHeapAttributeNumber.
1901 */
1902 num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1903 col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1904 have_col_privileges = false;
1905
1906 /*
1907 * If we are revoking relation privileges that are also column
1908 * privileges, we must implicitly revoke them from each column too,
1909 * per SQL spec. (We don't need to implicitly add column privileges
1910 * during GRANT because the permissions-checking code always checks
1911 * both relation and per-column privileges.)
1912 */
1913 if (!istmt->is_grant &&
1914 (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1915 {
1916 expand_all_col_privileges(relOid, pg_class_tuple,
1917 this_privileges & ACL_ALL_RIGHTS_COLUMN,
1918 col_privileges,
1919 num_col_privileges);
1920 have_col_privileges = true;
1921 }
1922
1923 /*
1924 * Get owner ID and working copy of existing ACL. If there's no ACL,
1925 * substitute the proper default.
1926 */
1927 ownerId = pg_class_tuple->relowner;
1928 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1929 &isNull);
1930 if (isNull)
1931 {
1932 switch (pg_class_tuple->relkind)
1933 {
1934 case RELKIND_SEQUENCE:
1935 old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1936 break;
1937 default:
1938 old_acl = acldefault(OBJECT_TABLE, ownerId);
1939 break;
1940 }
1941 /* There are no old member roles according to the catalogs */
1942 noldmembers = 0;
1943 oldmembers = NULL;
1944 }
1945 else
1946 {
1947 old_acl = DatumGetAclPCopy(aclDatum);
1948 /* Get the roles mentioned in the existing ACL */
1949 noldmembers = aclmembers(old_acl, &oldmembers);
1950 }
1951
1952 /* Need an extra copy of original rel ACL for column handling */
1953 old_rel_acl = aclcopy(old_acl);
1954
1955 /*
1956 * Handle relation-level privileges, if any were specified
1957 */
1958 if (this_privileges != ACL_NO_RIGHTS)
1959 {
1960 AclMode avail_goptions;
1961 Acl *new_acl;
1962 Oid grantorId;
1963 HeapTuple newtuple;
1964 Datum values[Natts_pg_class] = {0};
1965 bool nulls[Natts_pg_class] = {0};
1966 bool replaces[Natts_pg_class] = {0};
1967 int nnewmembers;
1968 Oid *newmembers;
1969 ObjectType objtype;
1970
1971 /* Determine ID to do the grant as, and available grant options */
1972 select_best_grantor(GetUserId(), this_privileges,
1973 old_acl, ownerId,
1974 &grantorId, &avail_goptions);
1975
1976 switch (pg_class_tuple->relkind)
1977 {
1978 case RELKIND_SEQUENCE:
1979 objtype = OBJECT_SEQUENCE;
1980 break;
1981 default:
1982 objtype = OBJECT_TABLE;
1983 break;
1984 }
1985
1986 /*
1987 * Restrict the privileges to what we can actually grant, and emit
1988 * the standards-mandated warning and error messages.
1989 */
1990 this_privileges =
1991 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1992 istmt->all_privs, this_privileges,
1993 relOid, grantorId, objtype,
1994 NameStr(pg_class_tuple->relname),
1995 0, NULL);
1996
1997 /*
1998 * Generate new ACL.
1999 */
2000 new_acl = merge_acl_with_grant(old_acl,
2001 istmt->is_grant,
2002 istmt->grant_option,
2003 istmt->behavior,
2004 istmt->grantees,
2005 this_privileges,
2006 grantorId,
2007 ownerId);
2008
2009 /*
2010 * We need the members of both old and new ACLs so we can correct
2011 * the shared dependency information.
2012 */
2013 nnewmembers = aclmembers(new_acl, &newmembers);
2014
2015 /* finished building new ACL value, now insert it */
2016 replaces[Anum_pg_class_relacl - 1] = true;
2017 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
2018
2019 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2020 values, nulls, replaces);
2021
2022 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2023 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2024
2025 /* Update initial privileges for extensions */
2026 recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2027
2028 /* Update the shared dependency ACL info */
2029 updateAclDependencies(RelationRelationId, relOid, 0,
2030 ownerId,
2031 noldmembers, oldmembers,
2032 nnewmembers, newmembers);
2033
2034 pfree(new_acl);
2035 }
2036 else
2037 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2038
2039 /*
2040 * Handle column-level privileges, if any were specified or implied.
2041 * We first expand the user-specified column privileges into the
2042 * array, and then iterate over all nonempty array entries.
2043 */
2044 foreach(cell_colprivs, istmt->col_privs)
2045 {
2046 AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2047
2048 if (col_privs->priv_name == NULL)
2049 this_privileges = ACL_ALL_RIGHTS_COLUMN;
2050 else
2051 this_privileges = string_to_privilege(col_privs->priv_name);
2052
2053 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2054 ereport(ERROR,
2055 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2056 errmsg("invalid privilege type %s for column",
2057 privilege_to_string(this_privileges))));
2058
2059 if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2060 this_privileges & ~((AclMode) ACL_SELECT))
2061 {
2062 /*
2063 * The only column privilege allowed on sequences is SELECT.
2064 * This is a warning not error because we do it that way for
2065 * relation-level privileges.
2066 */
2068 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2069 errmsg("sequence \"%s\" only supports SELECT column privileges",
2070 NameStr(pg_class_tuple->relname))));
2071
2072 this_privileges &= (AclMode) ACL_SELECT;
2073 }
2074
2075 expand_col_privileges(col_privs->cols, relOid,
2076 this_privileges,
2077 col_privileges,
2078 num_col_privileges);
2079 have_col_privileges = true;
2080 }
2081
2082 if (have_col_privileges)
2083 {
2084 AttrNumber i;
2085
2086 for (i = 0; i < num_col_privileges; i++)
2087 {
2088 if (col_privileges[i] == ACL_NO_RIGHTS)
2089 continue;
2090 ExecGrant_Attribute(istmt,
2091 relOid,
2092 NameStr(pg_class_tuple->relname),
2094 ownerId,
2095 col_privileges[i],
2096 attRelation,
2097 old_rel_acl);
2098 }
2099 }
2100
2101 pfree(old_rel_acl);
2102 pfree(col_privileges);
2103
2104 ReleaseSysCache(tuple);
2105
2106 /* prevent error when processing duplicate objects */
2108 }
2109
2110 table_close(attRelation, RowExclusiveLock);
2111 table_close(relation, RowExclusiveLock);
2112}
2113
2114static void
2115ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
2116 void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
2117{
2118 int cacheid;
2119 Relation relation;
2120 ListCell *cell;
2121
2122 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2123 istmt->privileges = default_privs;
2124
2125 cacheid = get_object_catcache_oid(classid);
2126
2127 relation = table_open(classid, RowExclusiveLock);
2128
2129 foreach(cell, istmt->objects)
2130 {
2131 Oid objectid = lfirst_oid(cell);
2132 Datum aclDatum;
2133 Datum nameDatum;
2134 bool isNull;
2135 AclMode avail_goptions;
2136 AclMode this_privileges;
2137 Acl *old_acl;
2138 Acl *new_acl;
2139 Oid grantorId;
2140 Oid ownerId;
2141 HeapTuple tuple;
2142 HeapTuple newtuple;
2143 Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2144 bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2145 bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2146 int noldmembers;
2147 int nnewmembers;
2148 Oid *oldmembers;
2149 Oid *newmembers;
2150
2151 tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid));
2152 if (!HeapTupleIsValid(tuple))
2153 elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2154
2155 /*
2156 * Additional object-type-specific checks
2157 */
2158 if (object_check)
2159 object_check(istmt, tuple);
2160
2161 /*
2162 * Get owner ID and working copy of existing ACL. If there's no ACL,
2163 * substitute the proper default.
2164 */
2165 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2166 tuple,
2167 get_object_attnum_owner(classid)));
2168 aclDatum = SysCacheGetAttr(cacheid,
2169 tuple,
2170 get_object_attnum_acl(classid),
2171 &isNull);
2172 if (isNull)
2173 {
2174 old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2175 /* There are no old member roles according to the catalogs */
2176 noldmembers = 0;
2177 oldmembers = NULL;
2178 }
2179 else
2180 {
2181 old_acl = DatumGetAclPCopy(aclDatum);
2182 /* Get the roles mentioned in the existing ACL */
2183 noldmembers = aclmembers(old_acl, &oldmembers);
2184 }
2185
2186 /* Determine ID to do the grant as, and available grant options */
2188 old_acl, ownerId,
2189 &grantorId, &avail_goptions);
2190
2191 nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2192 get_object_attnum_name(classid));
2193
2194 /*
2195 * Restrict the privileges to what we can actually grant, and emit the
2196 * standards-mandated warning and error messages.
2197 */
2198 this_privileges =
2199 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2200 istmt->all_privs, istmt->privileges,
2201 objectid, grantorId, get_object_type(classid, objectid),
2202 NameStr(*DatumGetName(nameDatum)),
2203 0, NULL);
2204
2205 /*
2206 * Generate new ACL.
2207 */
2208 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2209 istmt->grant_option, istmt->behavior,
2210 istmt->grantees, this_privileges,
2211 grantorId, ownerId);
2212
2213 /*
2214 * We need the members of both old and new ACLs so we can correct the
2215 * shared dependency information.
2216 */
2217 nnewmembers = aclmembers(new_acl, &newmembers);
2218
2219 /* finished building new ACL value, now insert it */
2220 replaces[get_object_attnum_acl(classid) - 1] = true;
2221 values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2222
2223 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2224 nulls, replaces);
2225
2226 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2227 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2228
2229 /* Update initial privileges for extensions */
2230 recordExtensionInitPriv(objectid, classid, 0, new_acl);
2231
2232 /* Update the shared dependency ACL info */
2233 updateAclDependencies(classid,
2234 objectid, 0,
2235 ownerId,
2236 noldmembers, oldmembers,
2237 nnewmembers, newmembers);
2238
2239 ReleaseSysCache(tuple);
2240
2241 pfree(new_acl);
2242
2243 /* prevent error when processing duplicate objects */
2245 }
2246
2247 table_close(relation, RowExclusiveLock);
2248}
2249
2250static void
2252{
2253 Form_pg_language pg_language_tuple;
2254
2255 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2256
2257 if (!pg_language_tuple->lanpltrusted)
2258 ereport(ERROR,
2259 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2260 errmsg("language \"%s\" is not trusted",
2261 NameStr(pg_language_tuple->lanname)),
2262 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2263 "because only superusers can use untrusted languages.")));
2264}
2265
2266static void
2268{
2269 Relation relation;
2270 ListCell *cell;
2271
2272 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2274
2275 relation = table_open(LargeObjectMetadataRelationId,
2277
2278 foreach(cell, istmt->objects)
2279 {
2280 Oid loid = lfirst_oid(cell);
2281 Form_pg_largeobject_metadata form_lo_meta;
2282 char loname[NAMEDATALEN];
2283 Datum aclDatum;
2284 bool isNull;
2285 AclMode avail_goptions;
2286 AclMode this_privileges;
2287 Acl *old_acl;
2288 Acl *new_acl;
2289 Oid grantorId;
2290 Oid ownerId;
2291 HeapTuple newtuple;
2292 Datum values[Natts_pg_largeobject_metadata] = {0};
2293 bool nulls[Natts_pg_largeobject_metadata] = {0};
2294 bool replaces[Natts_pg_largeobject_metadata] = {0};
2295 int noldmembers;
2296 int nnewmembers;
2297 Oid *oldmembers;
2298 Oid *newmembers;
2299 ScanKeyData entry[1];
2300 SysScanDesc scan;
2301 HeapTuple tuple;
2302
2303 /* There's no syscache for pg_largeobject_metadata */
2304 ScanKeyInit(&entry[0],
2305 Anum_pg_largeobject_metadata_oid,
2306 BTEqualStrategyNumber, F_OIDEQ,
2307 ObjectIdGetDatum(loid));
2308
2309 scan = systable_beginscan(relation,
2310 LargeObjectMetadataOidIndexId, true,
2311 NULL, 1, entry);
2312
2313 tuple = systable_getnext(scan);
2314 if (!HeapTupleIsValid(tuple))
2315 elog(ERROR, "could not find tuple for large object %u", loid);
2316
2317 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2318
2319 /*
2320 * Get owner ID and working copy of existing ACL. If there's no ACL,
2321 * substitute the proper default.
2322 */
2323 ownerId = form_lo_meta->lomowner;
2324 aclDatum = heap_getattr(tuple,
2325 Anum_pg_largeobject_metadata_lomacl,
2326 RelationGetDescr(relation), &isNull);
2327 if (isNull)
2328 {
2329 old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2330 /* There are no old member roles according to the catalogs */
2331 noldmembers = 0;
2332 oldmembers = NULL;
2333 }
2334 else
2335 {
2336 old_acl = DatumGetAclPCopy(aclDatum);
2337 /* Get the roles mentioned in the existing ACL */
2338 noldmembers = aclmembers(old_acl, &oldmembers);
2339 }
2340
2341 /* Determine ID to do the grant as, and available grant options */
2343 old_acl, ownerId,
2344 &grantorId, &avail_goptions);
2345
2346 /*
2347 * Restrict the privileges to what we can actually grant, and emit the
2348 * standards-mandated warning and error messages.
2349 */
2350 snprintf(loname, sizeof(loname), "large object %u", loid);
2351 this_privileges =
2352 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2353 istmt->all_privs, istmt->privileges,
2354 loid, grantorId, OBJECT_LARGEOBJECT,
2355 loname, 0, NULL);
2356
2357 /*
2358 * Generate new ACL.
2359 */
2360 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2361 istmt->grant_option, istmt->behavior,
2362 istmt->grantees, this_privileges,
2363 grantorId, ownerId);
2364
2365 /*
2366 * We need the members of both old and new ACLs so we can correct the
2367 * shared dependency information.
2368 */
2369 nnewmembers = aclmembers(new_acl, &newmembers);
2370
2371 /* finished building new ACL value, now insert it */
2372 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2373 values[Anum_pg_largeobject_metadata_lomacl - 1]
2374 = PointerGetDatum(new_acl);
2375
2376 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2377 values, nulls, replaces);
2378
2379 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2380
2381 /* Update initial privileges for extensions */
2382 recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2383
2384 /* Update the shared dependency ACL info */
2385 updateAclDependencies(LargeObjectRelationId,
2386 form_lo_meta->oid, 0,
2387 ownerId,
2388 noldmembers, oldmembers,
2389 nnewmembers, newmembers);
2390
2391 systable_endscan(scan);
2392
2393 pfree(new_acl);
2394
2395 /* prevent error when processing duplicate objects */
2397 }
2398
2399 table_close(relation, RowExclusiveLock);
2400}
2401
2402static void
2404{
2405 Form_pg_type pg_type_tuple;
2406
2407 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2408
2409 /* Disallow GRANT on dependent types */
2410 if (IsTrueArrayType(pg_type_tuple))
2411 ereport(ERROR,
2412 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2413 errmsg("cannot set privileges of array types"),
2414 errhint("Set the privileges of the element type instead.")));
2415 if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2416 ereport(ERROR,
2417 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2418 errmsg("cannot set privileges of multirange types"),
2419 errhint("Set the privileges of the range type instead.")));
2420}
2421
2422static void
2424{
2425 Relation relation;
2426 ListCell *cell;
2427
2428 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2430
2431 relation = table_open(ParameterAclRelationId, RowExclusiveLock);
2432
2433 foreach(cell, istmt->objects)
2434 {
2435 Oid parameterId = lfirst_oid(cell);
2436 Datum nameDatum;
2437 const char *parname;
2438 Datum aclDatum;
2439 bool isNull;
2440 AclMode avail_goptions;
2441 AclMode this_privileges;
2442 Acl *old_acl;
2443 Acl *new_acl;
2444 Oid grantorId;
2445 Oid ownerId;
2446 HeapTuple tuple;
2447 int noldmembers;
2448 int nnewmembers;
2449 Oid *oldmembers;
2450 Oid *newmembers;
2451
2452 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
2453 if (!HeapTupleIsValid(tuple))
2454 elog(ERROR, "cache lookup failed for parameter ACL %u",
2455 parameterId);
2456
2457 /* We'll need the GUC's name */
2458 nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
2459 Anum_pg_parameter_acl_parname);
2460 parname = TextDatumGetCString(nameDatum);
2461
2462 /* Treat all parameters as belonging to the bootstrap superuser. */
2463 ownerId = BOOTSTRAP_SUPERUSERID;
2464
2465 /*
2466 * Get working copy of existing ACL. If there's no ACL, substitute the
2467 * proper default.
2468 */
2469 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
2470 Anum_pg_parameter_acl_paracl,
2471 &isNull);
2472
2473 if (isNull)
2474 {
2475 old_acl = acldefault(istmt->objtype, ownerId);
2476 /* There are no old member roles according to the catalogs */
2477 noldmembers = 0;
2478 oldmembers = NULL;
2479 }
2480 else
2481 {
2482 old_acl = DatumGetAclPCopy(aclDatum);
2483 /* Get the roles mentioned in the existing ACL */
2484 noldmembers = aclmembers(old_acl, &oldmembers);
2485 }
2486
2487 /* Determine ID to do the grant as, and available grant options */
2489 old_acl, ownerId,
2490 &grantorId, &avail_goptions);
2491
2492 /*
2493 * Restrict the privileges to what we can actually grant, and emit the
2494 * standards-mandated warning and error messages.
2495 */
2496 this_privileges =
2497 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2498 istmt->all_privs, istmt->privileges,
2499 parameterId, grantorId,
2501 parname,
2502 0, NULL);
2503
2504 /*
2505 * Generate new ACL.
2506 */
2507 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2508 istmt->grant_option, istmt->behavior,
2509 istmt->grantees, this_privileges,
2510 grantorId, ownerId);
2511
2512 /*
2513 * We need the members of both old and new ACLs so we can correct the
2514 * shared dependency information.
2515 */
2516 nnewmembers = aclmembers(new_acl, &newmembers);
2517
2518 /*
2519 * If the new ACL is equal to the default, we don't need the catalog
2520 * entry any longer. Delete it rather than updating it, to avoid
2521 * leaving a degenerate entry.
2522 */
2523 if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
2524 {
2525 CatalogTupleDelete(relation, &tuple->t_self);
2526 }
2527 else
2528 {
2529 /* finished building new ACL value, now insert it */
2530 HeapTuple newtuple;
2531 Datum values[Natts_pg_parameter_acl] = {0};
2532 bool nulls[Natts_pg_parameter_acl] = {0};
2533 bool replaces[Natts_pg_parameter_acl] = {0};
2534
2535 replaces[Anum_pg_parameter_acl_paracl - 1] = true;
2536 values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
2537
2538 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2539 values, nulls, replaces);
2540
2541 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2542 }
2543
2544 /* Update initial privileges for extensions */
2545 recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
2546 new_acl);
2547
2548 /* Update the shared dependency ACL info */
2549 updateAclDependencies(ParameterAclRelationId, parameterId, 0,
2550 ownerId,
2551 noldmembers, oldmembers,
2552 nnewmembers, newmembers);
2553
2554 ReleaseSysCache(tuple);
2555 pfree(new_acl);
2556
2557 /* prevent error when processing duplicate objects */
2559 }
2560
2561 table_close(relation, RowExclusiveLock);
2562}
2563
2564
2565static AclMode
2566string_to_privilege(const char *privname)
2567{
2568 if (strcmp(privname, "insert") == 0)
2569 return ACL_INSERT;
2570 if (strcmp(privname, "select") == 0)
2571 return ACL_SELECT;
2572 if (strcmp(privname, "update") == 0)
2573 return ACL_UPDATE;
2574 if (strcmp(privname, "delete") == 0)
2575 return ACL_DELETE;
2576 if (strcmp(privname, "truncate") == 0)
2577 return ACL_TRUNCATE;
2578 if (strcmp(privname, "references") == 0)
2579 return ACL_REFERENCES;
2580 if (strcmp(privname, "trigger") == 0)
2581 return ACL_TRIGGER;
2582 if (strcmp(privname, "execute") == 0)
2583 return ACL_EXECUTE;
2584 if (strcmp(privname, "usage") == 0)
2585 return ACL_USAGE;
2586 if (strcmp(privname, "create") == 0)
2587 return ACL_CREATE;
2588 if (strcmp(privname, "temporary") == 0)
2589 return ACL_CREATE_TEMP;
2590 if (strcmp(privname, "temp") == 0)
2591 return ACL_CREATE_TEMP;
2592 if (strcmp(privname, "connect") == 0)
2593 return ACL_CONNECT;
2594 if (strcmp(privname, "set") == 0)
2595 return ACL_SET;
2596 if (strcmp(privname, "alter system") == 0)
2597 return ACL_ALTER_SYSTEM;
2598 if (strcmp(privname, "maintain") == 0)
2599 return ACL_MAINTAIN;
2600 ereport(ERROR,
2601 (errcode(ERRCODE_SYNTAX_ERROR),
2602 errmsg("unrecognized privilege type \"%s\"", privname)));
2603 return 0; /* appease compiler */
2604}
2605
2606static const char *
2608{
2609 switch (privilege)
2610 {
2611 case ACL_INSERT:
2612 return "INSERT";
2613 case ACL_SELECT:
2614 return "SELECT";
2615 case ACL_UPDATE:
2616 return "UPDATE";
2617 case ACL_DELETE:
2618 return "DELETE";
2619 case ACL_TRUNCATE:
2620 return "TRUNCATE";
2621 case ACL_REFERENCES:
2622 return "REFERENCES";
2623 case ACL_TRIGGER:
2624 return "TRIGGER";
2625 case ACL_EXECUTE:
2626 return "EXECUTE";
2627 case ACL_USAGE:
2628 return "USAGE";
2629 case ACL_CREATE:
2630 return "CREATE";
2631 case ACL_CREATE_TEMP:
2632 return "TEMP";
2633 case ACL_CONNECT:
2634 return "CONNECT";
2635 case ACL_SET:
2636 return "SET";
2637 case ACL_ALTER_SYSTEM:
2638 return "ALTER SYSTEM";
2639 case ACL_MAINTAIN:
2640 return "MAINTAIN";
2641 default:
2642 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2643 }
2644 return NULL; /* appease compiler */
2645}
2646
2647/*
2648 * Standardized reporting of aclcheck permissions failures.
2649 *
2650 * Note: we do not double-quote the %s's below, because many callers
2651 * supply strings that might be already quoted.
2652 */
2653void
2655 const char *objectname)
2656{
2657 switch (aclerr)
2658 {
2659 case ACLCHECK_OK:
2660 /* no error, so return to caller */
2661 break;
2662 case ACLCHECK_NO_PRIV:
2663 {
2664 const char *msg = "???";
2665
2666 switch (objtype)
2667 {
2668 case OBJECT_AGGREGATE:
2669 msg = gettext_noop("permission denied for aggregate %s");
2670 break;
2671 case OBJECT_COLLATION:
2672 msg = gettext_noop("permission denied for collation %s");
2673 break;
2674 case OBJECT_COLUMN:
2675 msg = gettext_noop("permission denied for column %s");
2676 break;
2677 case OBJECT_CONVERSION:
2678 msg = gettext_noop("permission denied for conversion %s");
2679 break;
2680 case OBJECT_DATABASE:
2681 msg = gettext_noop("permission denied for database %s");
2682 break;
2683 case OBJECT_DOMAIN:
2684 msg = gettext_noop("permission denied for domain %s");
2685 break;
2687 msg = gettext_noop("permission denied for event trigger %s");
2688 break;
2689 case OBJECT_EXTENSION:
2690 msg = gettext_noop("permission denied for extension %s");
2691 break;
2692 case OBJECT_FDW:
2693 msg = gettext_noop("permission denied for foreign-data wrapper %s");
2694 break;
2696 msg = gettext_noop("permission denied for foreign server %s");
2697 break;
2699 msg = gettext_noop("permission denied for foreign table %s");
2700 break;
2701 case OBJECT_FUNCTION:
2702 msg = gettext_noop("permission denied for function %s");
2703 break;
2704 case OBJECT_INDEX:
2705 msg = gettext_noop("permission denied for index %s");
2706 break;
2707 case OBJECT_LANGUAGE:
2708 msg = gettext_noop("permission denied for language %s");
2709 break;
2710 case OBJECT_LARGEOBJECT:
2711 msg = gettext_noop("permission denied for large object %s");
2712 break;
2713 case OBJECT_MATVIEW:
2714 msg = gettext_noop("permission denied for materialized view %s");
2715 break;
2716 case OBJECT_OPCLASS:
2717 msg = gettext_noop("permission denied for operator class %s");
2718 break;
2719 case OBJECT_OPERATOR:
2720 msg = gettext_noop("permission denied for operator %s");
2721 break;
2722 case OBJECT_OPFAMILY:
2723 msg = gettext_noop("permission denied for operator family %s");
2724 break;
2726 msg = gettext_noop("permission denied for parameter %s");
2727 break;
2728 case OBJECT_POLICY:
2729 msg = gettext_noop("permission denied for policy %s");
2730 break;
2731 case OBJECT_PROCEDURE:
2732 msg = gettext_noop("permission denied for procedure %s");
2733 break;
2734 case OBJECT_PUBLICATION:
2735 msg = gettext_noop("permission denied for publication %s");
2736 break;
2737 case OBJECT_ROUTINE:
2738 msg = gettext_noop("permission denied for routine %s");
2739 break;
2740 case OBJECT_SCHEMA:
2741 msg = gettext_noop("permission denied for schema %s");
2742 break;
2743 case OBJECT_SEQUENCE:
2744 msg = gettext_noop("permission denied for sequence %s");
2745 break;
2747 msg = gettext_noop("permission denied for statistics object %s");
2748 break;
2750 msg = gettext_noop("permission denied for subscription %s");
2751 break;
2752 case OBJECT_TABLE:
2753 msg = gettext_noop("permission denied for table %s");
2754 break;
2755 case OBJECT_TABLESPACE:
2756 msg = gettext_noop("permission denied for tablespace %s");
2757 break;
2759 msg = gettext_noop("permission denied for text search configuration %s");
2760 break;
2762 msg = gettext_noop("permission denied for text search dictionary %s");
2763 break;
2764 case OBJECT_TYPE:
2765 msg = gettext_noop("permission denied for type %s");
2766 break;
2767 case OBJECT_VIEW:
2768 msg = gettext_noop("permission denied for view %s");
2769 break;
2770 /* these currently aren't used */
2772 case OBJECT_AMOP:
2773 case OBJECT_AMPROC:
2774 case OBJECT_ATTRIBUTE:
2775 case OBJECT_CAST:
2776 case OBJECT_DEFAULT:
2777 case OBJECT_DEFACL:
2781 case OBJECT_ROLE:
2782 case OBJECT_RULE:
2784 case OBJECT_TRANSFORM:
2785 case OBJECT_TRIGGER:
2786 case OBJECT_TSPARSER:
2787 case OBJECT_TSTEMPLATE:
2789 elog(ERROR, "unsupported object type: %d", objtype);
2790 }
2791
2792 ereport(ERROR,
2793 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2794 errmsg(msg, objectname)));
2795 break;
2796 }
2797 case ACLCHECK_NOT_OWNER:
2798 {
2799 const char *msg = "???";
2800
2801 switch (objtype)
2802 {
2803 case OBJECT_AGGREGATE:
2804 msg = gettext_noop("must be owner of aggregate %s");
2805 break;
2806 case OBJECT_COLLATION:
2807 msg = gettext_noop("must be owner of collation %s");
2808 break;
2809 case OBJECT_CONVERSION:
2810 msg = gettext_noop("must be owner of conversion %s");
2811 break;
2812 case OBJECT_DATABASE:
2813 msg = gettext_noop("must be owner of database %s");
2814 break;
2815 case OBJECT_DOMAIN:
2816 msg = gettext_noop("must be owner of domain %s");
2817 break;
2819 msg = gettext_noop("must be owner of event trigger %s");
2820 break;
2821 case OBJECT_EXTENSION:
2822 msg = gettext_noop("must be owner of extension %s");
2823 break;
2824 case OBJECT_FDW:
2825 msg = gettext_noop("must be owner of foreign-data wrapper %s");
2826 break;
2828 msg = gettext_noop("must be owner of foreign server %s");
2829 break;
2831 msg = gettext_noop("must be owner of foreign table %s");
2832 break;
2833 case OBJECT_FUNCTION:
2834 msg = gettext_noop("must be owner of function %s");
2835 break;
2836 case OBJECT_INDEX:
2837 msg = gettext_noop("must be owner of index %s");
2838 break;
2839 case OBJECT_LANGUAGE:
2840 msg = gettext_noop("must be owner of language %s");
2841 break;
2842 case OBJECT_LARGEOBJECT:
2843 msg = gettext_noop("must be owner of large object %s");
2844 break;
2845 case OBJECT_MATVIEW:
2846 msg = gettext_noop("must be owner of materialized view %s");
2847 break;
2848 case OBJECT_OPCLASS:
2849 msg = gettext_noop("must be owner of operator class %s");
2850 break;
2851 case OBJECT_OPERATOR:
2852 msg = gettext_noop("must be owner of operator %s");
2853 break;
2854 case OBJECT_OPFAMILY:
2855 msg = gettext_noop("must be owner of operator family %s");
2856 break;
2857 case OBJECT_PROCEDURE:
2858 msg = gettext_noop("must be owner of procedure %s");
2859 break;
2860 case OBJECT_PUBLICATION:
2861 msg = gettext_noop("must be owner of publication %s");
2862 break;
2863 case OBJECT_ROUTINE:
2864 msg = gettext_noop("must be owner of routine %s");
2865 break;
2866 case OBJECT_SEQUENCE:
2867 msg = gettext_noop("must be owner of sequence %s");
2868 break;
2870 msg = gettext_noop("must be owner of subscription %s");
2871 break;
2872 case OBJECT_TABLE:
2873 msg = gettext_noop("must be owner of table %s");
2874 break;
2875 case OBJECT_TYPE:
2876 msg = gettext_noop("must be owner of type %s");
2877 break;
2878 case OBJECT_VIEW:
2879 msg = gettext_noop("must be owner of view %s");
2880 break;
2881 case OBJECT_SCHEMA:
2882 msg = gettext_noop("must be owner of schema %s");
2883 break;
2885 msg = gettext_noop("must be owner of statistics object %s");
2886 break;
2887 case OBJECT_TABLESPACE:
2888 msg = gettext_noop("must be owner of tablespace %s");
2889 break;
2891 msg = gettext_noop("must be owner of text search configuration %s");
2892 break;
2894 msg = gettext_noop("must be owner of text search dictionary %s");
2895 break;
2896
2897 /*
2898 * Special cases: For these, the error message talks
2899 * about "relation", because that's where the
2900 * ownership is attached. See also
2901 * check_object_ownership().
2902 */
2903 case OBJECT_COLUMN:
2904 case OBJECT_POLICY:
2905 case OBJECT_RULE:
2907 case OBJECT_TRIGGER:
2908 msg = gettext_noop("must be owner of relation %s");
2909 break;
2910 /* these currently aren't used */
2912 case OBJECT_AMOP:
2913 case OBJECT_AMPROC:
2914 case OBJECT_ATTRIBUTE:
2915 case OBJECT_CAST:
2916 case OBJECT_DEFAULT:
2917 case OBJECT_DEFACL:
2922 case OBJECT_ROLE:
2923 case OBJECT_TRANSFORM:
2924 case OBJECT_TSPARSER:
2925 case OBJECT_TSTEMPLATE:
2927 elog(ERROR, "unsupported object type: %d", objtype);
2928 }
2929
2930 ereport(ERROR,
2931 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2932 errmsg(msg, objectname)));
2933 break;
2934 }
2935 default:
2936 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2937 break;
2938 }
2939}
2940
2941
2942void
2944 const char *objectname, const char *colname)
2945{
2946 switch (aclerr)
2947 {
2948 case ACLCHECK_OK:
2949 /* no error, so return to caller */
2950 break;
2951 case ACLCHECK_NO_PRIV:
2952 ereport(ERROR,
2953 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2954 errmsg("permission denied for column \"%s\" of relation \"%s\"",
2955 colname, objectname)));
2956 break;
2957 case ACLCHECK_NOT_OWNER:
2958 /* relation msg is OK since columns don't have separate owners */
2959 aclcheck_error(aclerr, objtype, objectname);
2960 break;
2961 default:
2962 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2963 break;
2964 }
2965}
2966
2967
2968/*
2969 * Special common handling for types: use element type instead of array type,
2970 * and format nicely
2971 */
2972void
2974{
2975 Oid element_type = get_element_type(typeOid);
2976
2977 aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
2978}
2979
2980
2981/*
2982 * Relay for the various pg_*_mask routines depending on object kind
2983 */
2984static AclMode
2985pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
2986 AclMode mask, AclMaskHow how)
2987{
2988 switch (objtype)
2989 {
2990 case OBJECT_COLUMN:
2991 return
2992 pg_class_aclmask(object_oid, roleid, mask, how) |
2993 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
2994 case OBJECT_TABLE:
2995 case OBJECT_SEQUENCE:
2996 return pg_class_aclmask(object_oid, roleid, mask, how);
2997 case OBJECT_DATABASE:
2998 return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
2999 case OBJECT_FUNCTION:
3000 return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
3001 case OBJECT_LANGUAGE:
3002 return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
3003 case OBJECT_LARGEOBJECT:
3004 return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3005 mask, how, NULL);
3007 return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
3008 case OBJECT_SCHEMA:
3009 return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
3011 elog(ERROR, "grantable rights not supported for statistics objects");
3012 /* not reached, but keep compiler quiet */
3013 return ACL_NO_RIGHTS;
3014 case OBJECT_TABLESPACE:
3015 return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3016 case OBJECT_FDW:
3017 return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3019 return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3021 elog(ERROR, "grantable rights not supported for event triggers");
3022 /* not reached, but keep compiler quiet */
3023 return ACL_NO_RIGHTS;
3024 case OBJECT_TYPE:
3025 return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3026 default:
3027 elog(ERROR, "unrecognized object type: %d",
3028 (int) objtype);
3029 /* not reached, but keep compiler quiet */
3030 return ACL_NO_RIGHTS;
3031 }
3032}
3033
3034
3035/* ****************************************************************
3036 * Exported routines for examining a user's privileges for various objects
3037 *
3038 * See aclmask() for a description of the common API for these functions.
3039 * ****************************************************************
3040 */
3041
3042/*
3043 * Generic routine for examining a user's privileges for an object
3044 */
3045static AclMode
3046object_aclmask(Oid classid, Oid objectid, Oid roleid,
3047 AclMode mask, AclMaskHow how)
3048{
3049 return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3050}
3051
3052/*
3053 * Generic routine for examining a user's privileges for an object,
3054 * with is_missing
3055 */
3056static AclMode
3057object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
3058 AclMode mask, AclMaskHow how,
3059 bool *is_missing)
3060{
3061 int cacheid;
3062 AclMode result;
3063 HeapTuple tuple;
3064 Datum aclDatum;
3065 bool isNull;
3066 Acl *acl;
3067 Oid ownerId;
3068
3069 /* Special cases */
3070 switch (classid)
3071 {
3072 case NamespaceRelationId:
3073 return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
3074 is_missing);
3075 case TypeRelationId:
3076 return pg_type_aclmask_ext(objectid, roleid, mask, how,
3077 is_missing);
3078 }
3079
3080 /* Even more special cases */
3081 Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3082 Assert(classid != LargeObjectMetadataRelationId); /* should use
3083 * pg_largeobject_acl* */
3084
3085 /* Superusers bypass all permission checking. */
3086 if (superuser_arg(roleid))
3087 return mask;
3088
3089 /*
3090 * Get the object's ACL from its catalog
3091 */
3092
3093 cacheid = get_object_catcache_oid(classid);
3094
3095 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3096 if (!HeapTupleIsValid(tuple))
3097 {
3098 if (is_missing != NULL)
3099 {
3100 /* return "no privileges" instead of throwing an error */
3101 *is_missing = true;
3102 return 0;
3103 }
3104 else
3105 elog(ERROR, "cache lookup failed for %s %u",
3106 get_object_class_descr(classid), objectid);
3107 }
3108
3109 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3110 tuple,
3111 get_object_attnum_owner(classid)));
3112
3113 aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3114 &isNull);
3115 if (isNull)
3116 {
3117 /* No ACL, so build default ACL */
3118 acl = acldefault(get_object_type(classid, objectid), ownerId);
3119 aclDatum = (Datum) 0;
3120 }
3121 else
3122 {
3123 /* detoast ACL if necessary */
3124 acl = DatumGetAclP(aclDatum);
3125 }
3126
3127 result = aclmask(acl, roleid, ownerId, mask, how);
3128
3129 /* if we have a detoasted copy, free it */
3130 if (acl && acl != DatumGetPointer(aclDatum))
3131 pfree(acl);
3132
3133 ReleaseSysCache(tuple);
3134
3135 return result;
3136}
3137
3138/*
3139 * Routine for examining a user's privileges for a column
3140 *
3141 * Note: this considers only privileges granted specifically on the column.
3142 * It is caller's responsibility to take relation-level privileges into account
3143 * as appropriate. (For the same reason, we have no special case for
3144 * superuser-ness here.)
3145 */
3146static AclMode
3148 AclMode mask, AclMaskHow how)
3149{
3150 return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3151 mask, how, NULL);
3152}
3153
3154/*
3155 * Routine for examining a user's privileges for a column, with is_missing
3156 */
3157static AclMode
3159 AclMode mask, AclMaskHow how, bool *is_missing)
3160{
3161 AclMode result;
3162 HeapTuple classTuple;
3163 HeapTuple attTuple;
3164 Form_pg_class classForm;
3165 Form_pg_attribute attributeForm;
3166 Datum aclDatum;
3167 bool isNull;
3168 Acl *acl;
3169 Oid ownerId;
3170
3171 /*
3172 * First, get the column's ACL from its pg_attribute entry
3173 */
3174 attTuple = SearchSysCache2(ATTNUM,
3175 ObjectIdGetDatum(table_oid),
3177 if (!HeapTupleIsValid(attTuple))
3178 {
3179 if (is_missing != NULL)
3180 {
3181 /* return "no privileges" instead of throwing an error */
3182 *is_missing = true;
3183 return 0;
3184 }
3185 else
3186 ereport(ERROR,
3187 (errcode(ERRCODE_UNDEFINED_COLUMN),
3188 errmsg("attribute %d of relation with OID %u does not exist",
3189 attnum, table_oid)));
3190 }
3191
3192 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3193
3194 /* Check dropped columns, too */
3195 if (attributeForm->attisdropped)
3196 {
3197 if (is_missing != NULL)
3198 {
3199 /* return "no privileges" instead of throwing an error */
3200 *is_missing = true;
3201 ReleaseSysCache(attTuple);
3202 return 0;
3203 }
3204 else
3205 ereport(ERROR,
3206 (errcode(ERRCODE_UNDEFINED_COLUMN),
3207 errmsg("attribute %d of relation with OID %u does not exist",
3208 attnum, table_oid)));
3209 }
3210
3211 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3212 &isNull);
3213
3214 /*
3215 * Here we hard-wire knowledge that the default ACL for a column grants no
3216 * privileges, so that we can fall out quickly in the very common case
3217 * where attacl is null.
3218 */
3219 if (isNull)
3220 {
3221 ReleaseSysCache(attTuple);
3222 return 0;
3223 }
3224
3225 /*
3226 * Must get the relation's ownerId from pg_class. Since we already found
3227 * a pg_attribute entry, the only likely reason for this to fail is that a
3228 * concurrent DROP of the relation committed since then (which could only
3229 * happen if we don't have lock on the relation). Treat that similarly to
3230 * not finding the attribute entry.
3231 */
3232 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3233 if (!HeapTupleIsValid(classTuple))
3234 {
3235 ReleaseSysCache(attTuple);
3236 if (is_missing != NULL)
3237 {
3238 /* return "no privileges" instead of throwing an error */
3239 *is_missing = true;
3240 return 0;
3241 }
3242 else
3243 ereport(ERROR,
3245 errmsg("relation with OID %u does not exist",
3246 table_oid)));
3247 }
3248 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3249
3250 ownerId = classForm->relowner;
3251
3252 ReleaseSysCache(classTuple);
3253
3254 /* detoast column's ACL if necessary */
3255 acl = DatumGetAclP(aclDatum);
3256
3257 result = aclmask(acl, roleid, ownerId, mask, how);
3258
3259 /* if we have a detoasted copy, free it */
3260 if (acl && acl != DatumGetPointer(aclDatum))
3261 pfree(acl);
3262
3263 ReleaseSysCache(attTuple);
3264
3265 return result;
3266}
3267
3268/*
3269 * Exported routine for examining a user's privileges for a table
3270 */
3271AclMode
3272pg_class_aclmask(Oid table_oid, Oid roleid,
3273 AclMode mask, AclMaskHow how)
3274{
3275 return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3276}
3277
3278/*
3279 * Routine for examining a user's privileges for a table, with is_missing
3280 */
3281static AclMode
3282pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
3283 AclMaskHow how, bool *is_missing)
3284{
3285 AclMode result;
3286 HeapTuple tuple;
3287 Form_pg_class classForm;
3288 Datum aclDatum;
3289 bool isNull;
3290 Acl *acl;
3291 Oid ownerId;
3292
3293 /*
3294 * Must get the relation's tuple from pg_class
3295 */
3296 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3297 if (!HeapTupleIsValid(tuple))
3298 {
3299 if (is_missing != NULL)
3300 {
3301 /* return "no privileges" instead of throwing an error */
3302 *is_missing = true;
3303 return 0;
3304 }
3305 else
3306 ereport(ERROR,
3308 errmsg("relation with OID %u does not exist",
3309 table_oid)));
3310 }
3311
3312 classForm = (Form_pg_class) GETSTRUCT(tuple);
3313
3314 /*
3315 * Deny anyone permission to update a system catalog unless
3316 * pg_authid.rolsuper is set.
3317 *
3318 * As of 7.4 we have some updatable system views; those shouldn't be
3319 * protected in this way. Assume the view rules can take care of
3320 * themselves. ACL_USAGE is if we ever have system sequences.
3321 */
3322 if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3323 IsSystemClass(table_oid, classForm) &&
3324 classForm->relkind != RELKIND_VIEW &&
3325 !superuser_arg(roleid))
3327
3328 /*
3329 * Otherwise, superusers bypass all permission-checking.
3330 */
3331 if (superuser_arg(roleid))
3332 {
3333 ReleaseSysCache(tuple);
3334 return mask;
3335 }
3336
3337 /*
3338 * Normal case: get the relation's ACL from pg_class
3339 */
3340 ownerId = classForm->relowner;
3341
3342 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3343 &isNull);
3344 if (isNull)
3345 {
3346 /* No ACL, so build default ACL */
3347 switch (classForm->relkind)
3348 {
3349 case RELKIND_SEQUENCE:
3350 acl = acldefault(OBJECT_SEQUENCE, ownerId);
3351 break;
3352 default:
3353 acl = acldefault(OBJECT_TABLE, ownerId);
3354 break;
3355 }
3356 aclDatum = (Datum) 0;
3357 }
3358 else
3359 {
3360 /* detoast rel's ACL if necessary */
3361 acl = DatumGetAclP(aclDatum);
3362 }
3363
3364 result = aclmask(acl, roleid, ownerId, mask, how);
3365
3366 /* if we have a detoasted copy, free it */
3367 if (acl && acl != DatumGetPointer(aclDatum))
3368 pfree(acl);
3369
3370 ReleaseSysCache(tuple);
3371
3372 /*
3373 * Check if ACL_SELECT is being checked and, if so, and not set already as
3374 * part of the result, then check if the user is a member of the
3375 * pg_read_all_data role, which allows read access to all relations.
3376 */
3377 if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
3378 has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
3379 result |= ACL_SELECT;
3380
3381 /*
3382 * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3383 * so, and not set already as part of the result, then check if the user
3384 * is a member of the pg_write_all_data role, which allows
3385 * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3386 * which requires superuser, see above).
3387 */
3388 if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
3389 !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
3390 has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
3391 result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
3392
3393 /*
3394 * Check if ACL_MAINTAIN is being checked and, if so, and not already set
3395 * as part of the result, then check if the user is a member of the
3396 * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
3397 * MATERIALIZED VIEW, REINDEX, and LOCK TABLE on all relations.
3398 */
3399 if (mask & ACL_MAINTAIN &&
3400 !(result & ACL_MAINTAIN) &&
3401 has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
3402 result |= ACL_MAINTAIN;
3403
3404 return result;
3405}
3406
3407/*
3408 * Routine for examining a user's privileges for a configuration
3409 * parameter (GUC), identified by GUC name.
3410 */
3411static AclMode
3412pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
3413{
3414 AclMode result;
3415 char *parname;
3416 text *partext;
3417 HeapTuple tuple;
3418
3419 /* Superusers bypass all permission checking. */
3420 if (superuser_arg(roleid))
3421 return mask;
3422
3423 /* Convert name to the form it should have in pg_parameter_acl... */
3425 partext = cstring_to_text(parname);
3426
3427 /* ... and look it up */
3428 tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3429
3430 if (!HeapTupleIsValid(tuple))
3431 {
3432 /* If no entry, GUC has no permissions for non-superusers */
3433 result = ACL_NO_RIGHTS;
3434 }
3435 else
3436 {
3437 Datum aclDatum;
3438 bool isNull;
3439 Acl *acl;
3440
3441 aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3442 Anum_pg_parameter_acl_paracl,
3443 &isNull);
3444 if (isNull)
3445 {
3446 /* No ACL, so build default ACL */
3447 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3448 aclDatum = (Datum) 0;
3449 }
3450 else
3451 {
3452 /* detoast ACL if necessary */
3453 acl = DatumGetAclP(aclDatum);
3454 }
3455
3456 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3457
3458 /* if we have a detoasted copy, free it */
3459 if (acl && acl != DatumGetPointer(aclDatum))
3460 pfree(acl);
3461
3462 ReleaseSysCache(tuple);
3463 }
3464
3465 pfree(parname);
3466 pfree(partext);
3467
3468 return result;
3469}
3470
3471/*
3472 * Routine for examining a user's privileges for a configuration
3473 * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
3474 */
3475static AclMode
3477{
3478 AclMode result;
3479 HeapTuple tuple;
3480 Datum aclDatum;
3481 bool isNull;
3482 Acl *acl;
3483
3484 /* Superusers bypass all permission checking. */
3485 if (superuser_arg(roleid))
3486 return mask;
3487
3488 /* Get the ACL from pg_parameter_acl */
3489 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3490 if (!HeapTupleIsValid(tuple))
3491 ereport(ERROR,
3492 (errcode(ERRCODE_UNDEFINED_OBJECT),
3493 errmsg("parameter ACL with OID %u does not exist",
3494 acl_oid)));
3495
3496 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3497 Anum_pg_parameter_acl_paracl,
3498 &isNull);
3499 if (isNull)
3500 {
3501 /* No ACL, so build default ACL */
3502 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3503 aclDatum = (Datum) 0;
3504 }
3505 else
3506 {
3507 /* detoast ACL if necessary */
3508 acl = DatumGetAclP(aclDatum);
3509 }
3510
3511 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3512
3513 /* if we have a detoasted copy, free it */
3514 if (acl && acl != DatumGetPointer(aclDatum))
3515 pfree(acl);
3516
3517 ReleaseSysCache(tuple);
3518
3519 return result;
3520}
3521
3522/*
3523 * Routine for examining a user's privileges for a largeobject
3524 *
3525 * When a large object is opened for reading, it is opened relative to the
3526 * caller's snapshot, but when it is opened for writing, a current
3527 * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
3528 * takes a snapshot argument so that the permissions check can be made
3529 * relative to the same snapshot that will be used to read the underlying
3530 * data. The caller will actually pass NULL for an instantaneous MVCC
3531 * snapshot, since all we do with the snapshot argument is pass it through
3532 * to systable_beginscan().
3533 */
3534static AclMode
3536 AclMode mask, AclMaskHow how,
3537 Snapshot snapshot)
3538{
3539 AclMode result;
3540 Relation pg_lo_meta;
3541 ScanKeyData entry[1];
3542 SysScanDesc scan;
3543 HeapTuple tuple;
3544 Datum aclDatum;
3545 bool isNull;
3546 Acl *acl;
3547 Oid ownerId;
3548
3549 /* Superusers bypass all permission checking. */
3550 if (superuser_arg(roleid))
3551 return mask;
3552
3553 /*
3554 * Get the largeobject's ACL from pg_largeobject_metadata
3555 */
3556 pg_lo_meta = table_open(LargeObjectMetadataRelationId,
3558
3559 ScanKeyInit(&entry[0],
3560 Anum_pg_largeobject_metadata_oid,
3561 BTEqualStrategyNumber, F_OIDEQ,
3562 ObjectIdGetDatum(lobj_oid));
3563
3564 scan = systable_beginscan(pg_lo_meta,
3565 LargeObjectMetadataOidIndexId, true,
3566 snapshot, 1, entry);
3567
3568 tuple = systable_getnext(scan);
3569 if (!HeapTupleIsValid(tuple))
3570 ereport(ERROR,
3571 (errcode(ERRCODE_UNDEFINED_OBJECT),
3572 errmsg("large object %u does not exist", lobj_oid)));
3573
3574 ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
3575
3576 aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
3577 RelationGetDescr(pg_lo_meta), &isNull);
3578
3579 if (isNull)
3580 {
3581 /* No ACL, so build default ACL */
3582 acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
3583 aclDatum = (Datum) 0;
3584 }
3585 else
3586 {
3587 /* detoast ACL if necessary */
3588 acl = DatumGetAclP(aclDatum);
3589 }
3590
3591 result = aclmask(acl, roleid, ownerId, mask, how);
3592
3593 /* if we have a detoasted copy, free it */
3594 if (acl && acl != DatumGetPointer(aclDatum))
3595 pfree(acl);
3596
3597 systable_endscan(scan);
3598
3599 table_close(pg_lo_meta, AccessShareLock);
3600
3601 return result;
3602}
3603
3604/*
3605 * Routine for examining a user's privileges for a namespace, with is_missing
3606 */
3607static AclMode
3609 AclMode mask, AclMaskHow how,
3610 bool *is_missing)
3611{
3612 AclMode result;
3613 HeapTuple tuple;
3614 Datum aclDatum;
3615 bool isNull;
3616 Acl *acl;
3617 Oid ownerId;
3618
3619 /* Superusers bypass all permission checking. */
3620 if (superuser_arg(roleid))
3621 return mask;
3622
3623 /*
3624 * If we have been assigned this namespace as a temp namespace, check to
3625 * make sure we have CREATE TEMP permission on the database, and if so act
3626 * as though we have all standard (but not GRANT OPTION) permissions on
3627 * the namespace. If we don't have CREATE TEMP, act as though we have
3628 * only USAGE (and not CREATE) rights.
3629 *
3630 * This may seem redundant given the check in InitTempTableNamespace, but
3631 * it really isn't since current user ID may have changed since then. The
3632 * upshot of this behavior is that a SECURITY DEFINER function can create
3633 * temp tables that can then be accessed (if permission is granted) by
3634 * code in the same session that doesn't have permissions to create temp
3635 * tables.
3636 *
3637 * XXX Would it be safe to ereport a special error message as
3638 * InitTempTableNamespace does? Returning zero here means we'll get a
3639 * generic "permission denied for schema pg_temp_N" message, which is not
3640 * remarkably user-friendly.
3641 */
3642 if (isTempNamespace(nsp_oid))
3643 {
3644 if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
3645 ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
3646 return mask & ACL_ALL_RIGHTS_SCHEMA;
3647 else
3648 return mask & ACL_USAGE;
3649 }
3650
3651 /*
3652 * Get the schema's ACL from pg_namespace
3653 */
3654 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
3655 if (!HeapTupleIsValid(tuple))
3656 {
3657 if (is_missing != NULL)
3658 {
3659 /* return "no privileges" instead of throwing an error */
3660 *is_missing = true;
3661 return 0;
3662 }
3663 else
3664 ereport(ERROR,
3665 (errcode(ERRCODE_UNDEFINED_SCHEMA),
3666 errmsg("schema with OID %u does not exist", nsp_oid)));
3667 }
3668
3669 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3670
3671 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
3672 &isNull);
3673 if (isNull)
3674 {
3675 /* No ACL, so build default ACL */
3676 acl = acldefault(OBJECT_SCHEMA, ownerId);
3677 aclDatum = (Datum) 0;
3678 }
3679 else
3680 {
3681 /* detoast ACL if necessary */
3682 acl = DatumGetAclP(aclDatum);
3683 }
3684
3685 result = aclmask(acl, roleid, ownerId, mask, how);
3686
3687 /* if we have a detoasted copy, free it */
3688 if (acl && acl != DatumGetPointer(aclDatum))
3689 pfree(acl);
3690
3691 ReleaseSysCache(tuple);
3692
3693 /*
3694 * Check if ACL_USAGE is being checked and, if so, and not set already as
3695 * part of the result, then check if the user is a member of the
3696 * pg_read_all_data or pg_write_all_data roles, which allow usage access
3697 * to all schemas.
3698 */
3699 if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
3700 (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
3701 has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
3702 result |= ACL_USAGE;
3703 return result;
3704}
3705
3706/*
3707 * Routine for examining a user's privileges for a type, with is_missing
3708 */
3709static AclMode
3710pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
3711 bool *is_missing)
3712{
3713 AclMode result;
3714 HeapTuple tuple;
3715 Form_pg_type typeForm;
3716 Datum aclDatum;
3717 bool isNull;
3718 Acl *acl;
3719 Oid ownerId;
3720
3721 /* Bypass permission checks for superusers */
3722 if (superuser_arg(roleid))
3723 return mask;
3724
3725 /*
3726 * Must get the type's tuple from pg_type
3727 */
3728 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3729 if (!HeapTupleIsValid(tuple))
3730 {
3731 if (is_missing != NULL)
3732 {
3733 /* return "no privileges" instead of throwing an error */
3734 *is_missing = true;
3735 return 0;
3736 }
3737 else
3738 ereport(ERROR,
3739 (errcode(ERRCODE_UNDEFINED_OBJECT),
3740 errmsg("type with OID %u does not exist",
3741 type_oid)));
3742 }
3743 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3744
3745 /*
3746 * "True" array types don't manage permissions of their own; consult the
3747 * element type instead.
3748 */
3749 if (IsTrueArrayType(typeForm))
3750 {
3751 Oid elttype_oid = typeForm->typelem;
3752
3753 ReleaseSysCache(tuple);
3754
3755 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3756 if (!HeapTupleIsValid(tuple))
3757 {
3758 if (is_missing != NULL)
3759 {
3760 /* return "no privileges" instead of throwing an error */
3761 *is_missing = true;
3762 return 0;
3763 }
3764 else
3765 ereport(ERROR,
3766 (errcode(ERRCODE_UNDEFINED_OBJECT),
3767 errmsg("type with OID %u does not exist",
3768 elttype_oid)));
3769 }
3770 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3771 }
3772
3773 /*
3774 * Likewise, multirange types don't manage their own permissions; consult
3775 * the associated range type. (Note we must do this after the array step
3776 * to get the right answer for arrays of multiranges.)
3777 */
3778 if (typeForm->typtype == TYPTYPE_MULTIRANGE)
3779 {
3780 Oid rangetype = get_multirange_range(typeForm->oid);
3781
3782 ReleaseSysCache(tuple);
3783
3784 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
3785 if (!HeapTupleIsValid(tuple))
3786 {
3787 if (is_missing != NULL)
3788 {
3789 /* return "no privileges" instead of throwing an error */
3790 *is_missing = true;
3791 return 0;
3792 }
3793 else
3794 ereport(ERROR,
3795 (errcode(ERRCODE_UNDEFINED_OBJECT),
3796 errmsg("type with OID %u does not exist",
3797 rangetype)));
3798 }
3799 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3800 }
3801
3802 /*
3803 * Now get the type's owner and ACL from the tuple
3804 */
3805 ownerId = typeForm->typowner;
3806
3807 aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3808 Anum_pg_type_typacl, &isNull);
3809 if (isNull)
3810 {
3811 /* No ACL, so build default ACL */
3812 acl = acldefault(OBJECT_TYPE, ownerId);
3813 aclDatum = (Datum) 0;
3814 }
3815 else
3816 {
3817 /* detoast rel's ACL if necessary */
3818 acl = DatumGetAclP(aclDatum);
3819 }
3820
3821 result = aclmask(acl, roleid, ownerId, mask, how);
3822
3823 /* if we have a detoasted copy, free it */
3824 if (acl && acl != DatumGetPointer(aclDatum))
3825 pfree(acl);
3826
3827 ReleaseSysCache(tuple);
3828
3829 return result;
3830}
3831
3832/*
3833 * Exported generic routine for checking a user's access privileges to an object
3834 */
3836object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
3837{
3838 return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3839}
3840
3841/*
3842 * Exported generic routine for checking a user's access privileges to an
3843 * object, with is_missing
3844 */
3846object_aclcheck_ext(Oid classid, Oid objectid,
3847 Oid roleid, AclMode mode,
3848 bool *is_missing)
3849{
3850 if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
3851 is_missing) != 0)
3852 return ACLCHECK_OK;
3853 else
3854 return ACLCHECK_NO_PRIV;
3855}
3856
3857/*
3858 * Exported routine for checking a user's access privileges to a column
3859 *
3860 * Returns ACLCHECK_OK if the user has any of the privileges identified by
3861 * 'mode'; otherwise returns a suitable error code (in practice, always
3862 * ACLCHECK_NO_PRIV).
3863 *
3864 * As with pg_attribute_aclmask, only privileges granted directly on the
3865 * column are considered here.
3866 */
3869 Oid roleid, AclMode mode)
3870{
3871 return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3872}
3873
3874
3875/*
3876 * Exported routine for checking a user's access privileges to a column,
3877 * with is_missing
3878 */
3881 Oid roleid, AclMode mode, bool *is_missing)
3882{
3883 if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3884 ACLMASK_ANY, is_missing) != 0)
3885 return ACLCHECK_OK;
3886 else
3887 return ACLCHECK_NO_PRIV;
3888}
3889
3890/*
3891 * Exported routine for checking a user's access privileges to any/all columns
3892 *
3893 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
3894 * privileges identified by 'mode' on any non-dropped column in the relation;
3895 * otherwise returns a suitable error code (in practice, always
3896 * ACLCHECK_NO_PRIV).
3897 *
3898 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
3899 * privileges identified by 'mode' on each non-dropped column in the relation
3900 * (and there must be at least one such column); otherwise returns a suitable
3901 * error code (in practice, always ACLCHECK_NO_PRIV).
3902 *
3903 * As with pg_attribute_aclmask, only privileges granted directly on the
3904 * column(s) are considered here.
3905 *
3906 * Note: system columns are not considered here; there are cases where that
3907 * might be appropriate but there are also cases where it wouldn't.
3908 */
3911 AclMaskHow how)
3912{
3913 return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3914}
3915
3916/*
3917 * Exported routine for checking a user's access privileges to any/all columns,
3918 * with is_missing
3919 */
3922 AclMode mode, AclMaskHow how,
3923 bool *is_missing)
3924{
3925 AclResult result;
3926 HeapTuple classTuple;
3927 Form_pg_class classForm;
3928 Oid ownerId;
3929 AttrNumber nattrs;
3930 AttrNumber curr_att;
3931
3932 /*
3933 * Must fetch pg_class row to get owner ID and number of attributes.
3934 */
3935 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3936 if (!HeapTupleIsValid(classTuple))
3937 {
3938 if (is_missing != NULL)
3939 {
3940 /* return "no privileges" instead of throwing an error */
3941 *is_missing = true;
3942 return ACLCHECK_NO_PRIV;
3943 }
3944 else
3945 ereport(ERROR,
3947 errmsg("relation with OID %u does not exist",
3948 table_oid)));
3949 }
3950 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3951
3952 ownerId = classForm->relowner;
3953 nattrs = classForm->relnatts;
3954
3955 ReleaseSysCache(classTuple);
3956
3957 /*
3958 * Initialize result in case there are no non-dropped columns. We want to
3959 * report failure in such cases for either value of 'how'.
3960 */
3961 result = ACLCHECK_NO_PRIV;
3962
3963 for (curr_att = 1; curr_att <= nattrs; curr_att++)
3964 {
3965 HeapTuple attTuple;
3966 Datum aclDatum;
3967 bool isNull;
3968 Acl *acl;
3969 AclMode attmask;
3970
3971 attTuple = SearchSysCache2(ATTNUM,
3972 ObjectIdGetDatum(table_oid),
3973 Int16GetDatum(curr_att));
3974
3975 /*
3976 * Lookup failure probably indicates that the table was just dropped,
3977 * but we'll treat it the same as a dropped column rather than
3978 * throwing error.
3979 */
3980 if (!HeapTupleIsValid(attTuple))
3981 continue;
3982
3983 /* ignore dropped columns */
3984 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
3985 {
3986 ReleaseSysCache(attTuple);
3987 continue;
3988 }
3989
3990 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3991 &isNull);
3992
3993 /*
3994 * Here we hard-wire knowledge that the default ACL for a column
3995 * grants no privileges, so that we can fall out quickly in the very
3996 * common case where attacl is null.
3997 */
3998 if (isNull)
3999 attmask = 0;
4000 else
4001 {
4002 /* detoast column's ACL if necessary */
4003 acl = DatumGetAclP(aclDatum);
4004
4005 attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
4006
4007 /* if we have a detoasted copy, free it */
4008 if (acl != DatumGetPointer(aclDatum))
4009 pfree(acl);
4010 }
4011
4012 ReleaseSysCache(attTuple);
4013
4014 if (attmask != 0)
4015 {
4016 result = ACLCHECK_OK;
4017 if (how == ACLMASK_ANY)
4018 break; /* succeed on any success */
4019 }
4020 else
4021 {
4022 result = ACLCHECK_NO_PRIV;
4023 if (how == ACLMASK_ALL)
4024 break; /* fail on any failure */
4025 }
4026 }
4027
4028 return result;
4029}
4030
4031/*
4032 * Exported routine for checking a user's access privileges to a table
4033 *
4034 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4035 * 'mode'; otherwise returns a suitable error code (in practice, always
4036 * ACLCHECK_NO_PRIV).
4037 */
4040{
4041 return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
4042}
4043
4044/*
4045 * Exported routine for checking a user's access privileges to a table,
4046 * with is_missing
4047 */
4050 AclMode mode, bool *is_missing)
4051{
4052 if (pg_class_aclmask_ext(table_oid, roleid, mode,
4053 ACLMASK_ANY, is_missing) != 0)
4054 return ACLCHECK_OK;
4055 else
4056 return ACLCHECK_NO_PRIV;
4057}
4058
4059/*
4060 * Exported routine for checking a user's access privileges to a configuration
4061 * parameter (GUC), identified by GUC name.
4062 */
4065{
4066 if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4067 return ACLCHECK_OK;
4068 else
4069 return ACLCHECK_NO_PRIV;
4070}
4071
4072/*
4073 * Exported routine for checking a user's access privileges to a largeobject
4074 */
4077 Snapshot snapshot)
4078{
4079 if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4080 ACLMASK_ANY, snapshot) != 0)
4081 return ACLCHECK_OK;
4082 else
4083 return ACLCHECK_NO_PRIV;
4084}
4085
4086/*
4087 * Generic ownership check for an object
4088 */
4089bool
4090object_ownercheck(Oid classid, Oid objectid, Oid roleid)
4091{
4092 int cacheid;
4093 Oid ownerId;
4094
4095 /* Superusers bypass all permission checking. */
4096 if (superuser_arg(roleid))
4097 return true;
4098
4099 /* For large objects, the catalog to consult is pg_largeobject_metadata */
4100 if (classid == LargeObjectRelationId)
4101 classid = LargeObjectMetadataRelationId;
4102
4103 cacheid = get_object_catcache_oid(classid);
4104 if (cacheid != -1)
4105 {
4106 /* we can get the object's tuple from the syscache */
4107 HeapTuple tuple;
4108
4109 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4110 if (!HeapTupleIsValid(tuple))
4111 elog(ERROR, "cache lookup failed for %s %u",
4112 get_object_class_descr(classid), objectid);
4113
4114 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4115 tuple,
4116 get_object_attnum_owner(classid)));
4117 ReleaseSysCache(tuple);
4118 }
4119 else
4120 {
4121 /* for catalogs without an appropriate syscache */
4122 Relation rel;
4123 ScanKeyData entry[1];
4124 SysScanDesc scan;
4125 HeapTuple tuple;
4126 bool isnull;
4127
4128 rel = table_open(classid, AccessShareLock);
4129
4130 ScanKeyInit(&entry[0],
4131 get_object_attnum_oid(classid),
4132 BTEqualStrategyNumber, F_OIDEQ,
4133 ObjectIdGetDatum(objectid));
4134
4135 scan = systable_beginscan(rel,
4136 get_object_oid_index(classid), true,
4137 NULL, 1, entry);
4138
4139 tuple = systable_getnext(scan);
4140 if (!HeapTupleIsValid(tuple))
4141 elog(ERROR, "could not find tuple for %s %u",
4142 get_object_class_descr(classid), objectid);
4143
4144 ownerId = DatumGetObjectId(heap_getattr(tuple,
4145 get_object_attnum_owner(classid),
4146 RelationGetDescr(rel),
4147 &isnull));
4148 Assert(!isnull);
4149
4150 systable_endscan(scan);
4152 }
4153
4154 return has_privs_of_role(roleid, ownerId);
4155}
4156
4157/*
4158 * Check whether specified role has CREATEROLE privilege (or is a superuser)
4159 *
4160 * Note: roles do not have owners per se; instead we use this test in
4161 * places where an ownership-like permissions test is needed for a role.
4162 * Be sure to apply it to the role trying to do the operation, not the
4163 * role being operated on! Also note that this generally should not be
4164 * considered enough privilege if the target role is a superuser.
4165 * (We don't handle that consideration here because we want to give a
4166 * separate error message for such cases, so the caller has to deal with it.)
4167 */
4168bool
4170{
4171 bool result = false;
4172 HeapTuple utup;
4173
4174 /* Superusers bypass all permission checking. */
4175 if (superuser_arg(roleid))
4176 return true;
4177
4178 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4179 if (HeapTupleIsValid(utup))
4180 {
4181 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4182 ReleaseSysCache(utup);
4183 }
4184 return result;
4185}
4186
4187bool
4189{
4190 bool result = false;
4191 HeapTuple utup;
4192
4193 /* Superusers bypass all permission checking. */
4194 if (superuser_arg(roleid))
4195 return true;
4196
4197 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4198 if (HeapTupleIsValid(utup))
4199 {
4200 result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4201 ReleaseSysCache(utup);
4202 }
4203 return result;
4204}
4205
4206/*
4207 * Fetch pg_default_acl entry for given role, namespace and object type
4208 * (object type must be given in pg_default_acl's encoding).
4209 * Returns NULL if no such entry.
4210 */
4211static Acl *
4212get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
4213{
4214 Acl *result = NULL;
4215 HeapTuple tuple;
4216
4217 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4218 ObjectIdGetDatum(roleId),
4219 ObjectIdGetDatum(nsp_oid),
4220 CharGetDatum(objtype));
4221
4222 if (HeapTupleIsValid(tuple))
4223 {
4224 Datum aclDatum;
4225 bool isNull;
4226
4227 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4228 Anum_pg_default_acl_defaclacl,
4229 &isNull);
4230 if (!isNull)
4231 result = DatumGetAclPCopy(aclDatum);
4232 ReleaseSysCache(tuple);
4233 }
4234
4235 return result;
4236}
4237
4238/*
4239 * Get default permissions for newly created object within given schema
4240 *
4241 * Returns NULL if built-in system defaults should be used.
4242 *
4243 * If the result is not NULL, caller must call recordDependencyOnNewAcl
4244 * once the OID of the new object is known.
4245 */
4246Acl *
4247get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
4248{
4249 Acl *result;
4250 Acl *glob_acl;
4251 Acl *schema_acl;
4252 Acl *def_acl;
4253 char defaclobjtype;
4254
4255 /*
4256 * Use NULL during bootstrap, since pg_default_acl probably isn't there
4257 * yet.
4258 */
4260 return NULL;
4261
4262 /* Check if object type is supported in pg_default_acl */
4263 switch (objtype)
4264 {
4265 case OBJECT_TABLE:
4266 defaclobjtype = DEFACLOBJ_RELATION;
4267 break;
4268
4269 case OBJECT_SEQUENCE:
4270 defaclobjtype = DEFACLOBJ_SEQUENCE;
4271 break;
4272
4273 case OBJECT_FUNCTION:
4274 defaclobjtype = DEFACLOBJ_FUNCTION;
4275 break;
4276
4277 case OBJECT_TYPE:
4278 defaclobjtype = DEFACLOBJ_TYPE;
4279 break;
4280
4281 case OBJECT_SCHEMA:
4282 defaclobjtype = DEFACLOBJ_NAMESPACE;
4283 break;
4284
4285 case OBJECT_LARGEOBJECT:
4286 defaclobjtype = DEFACLOBJ_LARGEOBJECT;
4287 break;
4288
4289 default:
4290 return NULL;
4291 }
4292
4293 /* Look up the relevant pg_default_acl entries */
4294 glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4295 schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4296
4297 /* Quick out if neither entry exists */
4298 if (glob_acl == NULL && schema_acl == NULL)
4299 return NULL;
4300
4301 /* We need to know the hard-wired default value, too */
4302 def_acl = acldefault(objtype, ownerId);
4303
4304 /* If there's no global entry, substitute the hard-wired default */
4305 if (glob_acl == NULL)
4306 glob_acl = def_acl;
4307
4308 /* Merge in any per-schema privileges */
4309 result = aclmerge(glob_acl, schema_acl, ownerId);
4310
4311 /*
4312 * For efficiency, we want to return NULL if the result equals default.
4313 * This requires sorting both arrays to get an accurate comparison.
4314 */
4315 aclitemsort(result);
4316 aclitemsort(def_acl);
4317 if (aclequal(result, def_acl))
4318 result = NULL;
4319
4320 return result;
4321}
4322
4323/*
4324 * Record dependencies on roles mentioned in a new object's ACL.
4325 */
4326void
4327recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
4328 Oid ownerId, Acl *acl)
4329{
4330 int nmembers;
4331 Oid *members;
4332
4333 /* Nothing to do if ACL is defaulted */
4334 if (acl == NULL)
4335 return;
4336
4337 /* Extract roles mentioned in ACL */
4338 nmembers = aclmembers(acl, &members);
4339
4340 /* Update the shared dependency ACL info */
4341 updateAclDependencies(classId, objectId, objsubId,
4342 ownerId,
4343 0, NULL,
4344 nmembers, members);
4345}
4346
4347/*
4348 * Record initial privileges for the top-level object passed in.
4349 *
4350 * For the object passed in, this will record its ACL (if any) and the ACLs of
4351 * any sub-objects (eg: columns) into pg_init_privs.
4352 */
4353void
4355{
4356 /*
4357 * pg_class / pg_attribute
4358 *
4359 * If this is a relation then we need to see if there are any sub-objects
4360 * (eg: columns) for it and, if so, be sure to call
4361 * recordExtensionInitPrivWorker() for each one.
4362 */
4363 if (classoid == RelationRelationId)
4364 {
4365 Form_pg_class pg_class_tuple;
4366 Datum aclDatum;
4367 bool isNull;
4368 HeapTuple tuple;
4369
4370 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4371 if (!HeapTupleIsValid(tuple))
4372 elog(ERROR, "cache lookup failed for relation %u", objoid);
4373 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4374
4375 /*
4376 * Indexes don't have permissions, neither do the pg_class rows for
4377 * composite types. (These cases are unreachable given the
4378 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4379 */
4380 if (pg_class_tuple->relkind == RELKIND_INDEX ||
4381 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4382 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4383 {
4384 ReleaseSysCache(tuple);
4385 return;
4386 }
4387
4388 /*
4389 * If this isn't a sequence then it's possibly going to have
4390 * column-level ACLs associated with it.
4391 */
4392 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4393 {
4394 AttrNumber curr_att;
4395 AttrNumber nattrs = pg_class_tuple->relnatts;
4396
4397 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4398 {
4399 HeapTuple attTuple;
4400 Datum attaclDatum;
4401
4402 attTuple = SearchSysCache2(ATTNUM,
4403 ObjectIdGetDatum(objoid),
4404 Int16GetDatum(curr_att));
4405
4406 if (!HeapTupleIsValid(attTuple))
4407 continue;
4408
4409 /* ignore dropped columns */
4410 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4411 {
4412 ReleaseSysCache(attTuple);
4413 continue;
4414 }
4415
4416 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4417 Anum_pg_attribute_attacl,
4418 &isNull);
4419
4420 /* no need to do anything for a NULL ACL */
4421 if (isNull)
4422 {
4423 ReleaseSysCache(attTuple);
4424 continue;
4425 }
4426
4427 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4428 DatumGetAclP(attaclDatum));
4429
4430 ReleaseSysCache(attTuple);
4431 }
4432 }
4433
4434 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4435 &isNull);
4436
4437 /* Add the record, if any, for the top-level object */
4438 if (!isNull)
4439 recordExtensionInitPrivWorker(objoid, classoid, 0,
4440 DatumGetAclP(aclDatum));
4441
4442 ReleaseSysCache(tuple);
4443 }
4444 else if (classoid == LargeObjectRelationId)
4445 {
4446 /* For large objects, we must consult pg_largeobject_metadata */
4447 Datum aclDatum;
4448 bool isNull;
4449 HeapTuple tuple;
4450 ScanKeyData entry[1];
4451 SysScanDesc scan;
4452 Relation relation;
4453
4454 /*
4455 * Note: this is dead code, given that we don't allow large objects to
4456 * be made extension members. But it seems worth carrying in case
4457 * some future caller of this function has need for it.
4458 */
4459 relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4460
4461 /* There's no syscache for pg_largeobject_metadata */
4462 ScanKeyInit(&entry[0],
4463 Anum_pg_largeobject_metadata_oid,
4464 BTEqualStrategyNumber, F_OIDEQ,
4465 ObjectIdGetDatum(objoid));
4466
4467 scan = systable_beginscan(relation,
4468 LargeObjectMetadataOidIndexId, true,
4469 NULL, 1, entry);
4470
4471 tuple = systable_getnext(scan);
4472 if (!HeapTupleIsValid(tuple))
4473 elog(ERROR, "could not find tuple for large object %u", objoid);
4474
4475 aclDatum = heap_getattr(tuple,
4476 Anum_pg_largeobject_metadata_lomacl,
4477 RelationGetDescr(relation), &isNull);
4478
4479 /* Add the record, if any, for the top-level object */
4480 if (!isNull)
4481 recordExtensionInitPrivWorker(objoid, classoid, 0,
4482 DatumGetAclP(aclDatum));
4483
4484 systable_endscan(scan);
4485 }
4486 /* This will error on unsupported classoid. */
4487 else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4488 {
4489 int cacheid;
4490 Datum aclDatum;
4491 bool isNull;
4492 HeapTuple tuple;
4493
4494 cacheid = get_object_catcache_oid(classoid);
4495 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
4496 if (!HeapTupleIsValid(tuple))
4497 elog(ERROR, "cache lookup failed for %s %u",
4498 get_object_class_descr(classoid), objoid);
4499
4500 aclDatum = SysCacheGetAttr(cacheid, tuple,
4501 get_object_attnum_acl(classoid),
4502 &isNull);
4503
4504 /* Add the record, if any, for the top-level object */
4505 if (!isNull)
4506 recordExtensionInitPrivWorker(objoid, classoid, 0,
4507 DatumGetAclP(aclDatum));
4508
4509 ReleaseSysCache(tuple);
4510 }
4511}
4512
4513/*
4514 * For the object passed in, remove its ACL and the ACLs of any object subIds
4515 * from pg_init_privs (via recordExtensionInitPrivWorker()).
4516 */
4517void
4519{
4520 /*
4521 * If this is a relation then we need to see if there are any sub-objects
4522 * (eg: columns) for it and, if so, be sure to call
4523 * recordExtensionInitPrivWorker() for each one.
4524 */
4525 if (classoid == RelationRelationId)
4526 {
4527 Form_pg_class pg_class_tuple;
4528 HeapTuple tuple;
4529
4530 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4531 if (!HeapTupleIsValid(tuple))
4532 elog(ERROR, "cache lookup failed for relation %u", objoid);
4533 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4534
4535 /*
4536 * Indexes don't have permissions, neither do the pg_class rows for
4537 * composite types. (These cases are unreachable given the
4538 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4539 */
4540 if (pg_class_tuple->relkind == RELKIND_INDEX ||
4541 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4542 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4543 {
4544 ReleaseSysCache(tuple);
4545 return;
4546 }
4547
4548 /*
4549 * If this isn't a sequence then it's possibly going to have
4550 * column-level ACLs associated with it.
4551 */
4552 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4553 {
4554 AttrNumber curr_att;
4555 AttrNumber nattrs = pg_class_tuple->relnatts;
4556
4557 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4558 {
4559 HeapTuple attTuple;
4560
4561 attTuple = SearchSysCache2(ATTNUM,
4562 ObjectIdGetDatum(objoid),
4563 Int16GetDatum(curr_att));
4564
4565 if (!HeapTupleIsValid(attTuple))
4566 continue;
4567
4568 /* when removing, remove all entries, even dropped columns */
4569
4570 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4571
4572 ReleaseSysCache(attTuple);
4573 }
4574 }
4575
4576 ReleaseSysCache(tuple);
4577 }
4578
4579 /* Remove the record, if any, for the top-level object */
4580 recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
4581}
4582
4583/*
4584 * Record initial ACL for an extension object
4585 *
4586 * Can be called at any time, we check if 'creating_extension' is set and, if
4587 * not, exit immediately.
4588 *
4589 * Pass in the object OID, the OID of the class (the OID of the table which
4590 * the object is defined in) and the 'sub' id of the object (objsubid), if
4591 * any. If there is no 'sub' id (they are currently only used for columns of
4592 * tables) then pass in '0'. Finally, pass in the complete ACL to store.
4593 *
4594 * If an ACL already exists for this object/sub-object then we will replace
4595 * it with what is passed in.
4596 *
4597 * Passing in NULL for 'new_acl' will result in the entry for the object being
4598 * removed, if one is found.
4599 */
4600static void
4601recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
4602{
4603 /*
4604 * Generally, we only record the initial privileges when an extension is
4605 * being created, but because we don't actually use CREATE EXTENSION
4606 * during binary upgrades with pg_upgrade, there is a variable to let us
4607 * know that the GRANT and REVOKE statements being issued, while this
4608 * variable is true, are for the initial privileges of the extension
4609 * object and therefore we need to record them.
4610 */
4612 return;
4613
4614 recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4615}
4616
4617/*
4618 * Record initial ACL for an extension object, worker.
4619 *
4620 * This will perform a wholesale replacement of the entire ACL for the object
4621 * passed in, therefore be sure to pass in the complete new ACL to use.
4622 *
4623 * Generally speaking, do *not* use this function directly but instead use
4624 * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
4625 * This function does *not* check if 'creating_extension' is set as it is also
4626 * used when an object is added to or removed from an extension via ALTER
4627 * EXTENSION ... ADD/DROP.
4628 */
4629static void
4630recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
4631 Acl *new_acl)
4632{
4633 Relation relation;
4634 ScanKeyData key[3];
4635 SysScanDesc scan;
4636 HeapTuple tuple;
4637 HeapTuple oldtuple;
4638 int noldmembers;
4639 int nnewmembers;
4640 Oid *oldmembers;
4641 Oid *newmembers;
4642
4643 /* We'll need the role membership of the new ACL. */
4644 nnewmembers = aclmembers(new_acl, &newmembers);
4645
4646 /* Search pg_init_privs for an existing entry. */
4647 relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4648
4649 ScanKeyInit(&key[0],
4650 Anum_pg_init_privs_objoid,
4651 BTEqualStrategyNumber, F_OIDEQ,
4652 ObjectIdGetDatum(objoid));
4653 ScanKeyInit(&key[1],
4654 Anum_pg_init_privs_classoid,
4655 BTEqualStrategyNumber, F_OIDEQ,
4656 ObjectIdGetDatum(classoid));
4657 ScanKeyInit(&key[2],
4658 Anum_pg_init_privs_objsubid,
4659 BTEqualStrategyNumber, F_INT4EQ,
4660 Int32GetDatum(objsubid));
4661
4662 scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4663 NULL, 3, key);
4664
4665 /* There should exist only one entry or none. */
4666 oldtuple = systable_getnext(scan);
4667
4668 /* If we find an entry, update it with the latest ACL. */
4669 if (HeapTupleIsValid(oldtuple))
4670 {
4671 Datum values[Natts_pg_init_privs] = {0};
4672 bool nulls[Natts_pg_init_privs] = {0};
4673 bool replace[Natts_pg_init_privs] = {0};
4674 Datum oldAclDatum;
4675 bool isNull;
4676 Acl *old_acl;
4677
4678 /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
4679 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4680 RelationGetDescr(relation), &isNull);
4681 Assert(!isNull);
4682 old_acl = DatumGetAclP(oldAclDatum);
4683 noldmembers = aclmembers(old_acl, &oldmembers);
4684
4685 updateInitAclDependencies(classoid, objoid, objsubid,
4686 noldmembers, oldmembers,
4687 nnewmembers, newmembers);
4688
4689 /* If we have a new ACL to set, then update the row with it. */
4690 if (new_acl && ACL_NUM(new_acl) != 0)
4691 {
4692 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4693 replace[Anum_pg_init_privs_initprivs - 1] = true;
4694
4695 oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4696 values, nulls, replace);
4697
4698 CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4699 }
4700 else
4701 {
4702 /* new_acl is NULL/empty, so delete the entry we found. */
4703 CatalogTupleDelete(relation, &oldtuple->t_self);
4704 }
4705 }
4706 else
4707 {
4708 Datum values[Natts_pg_init_privs] = {0};
4709 bool nulls[Natts_pg_init_privs] = {0};
4710
4711 /*
4712 * Only add a new entry if the new ACL is non-NULL.
4713 *
4714 * If we are passed in a NULL ACL and no entry exists, we can just
4715 * fall through and do nothing.
4716 */
4717 if (new_acl && ACL_NUM(new_acl) != 0)
4718 {
4719 /* No entry found, so add it. */
4720 values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4721 values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4722 values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4723
4724 /* This function only handles initial privileges of extensions */
4725 values[Anum_pg_init_privs_privtype - 1] =
4727
4728 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4729
4730 tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4731
4732 CatalogTupleInsert(relation, tuple);
4733
4734 /* Update pg_shdepend, too. */
4735 noldmembers = 0;
4736 oldmembers = NULL;
4737
4738 updateInitAclDependencies(classoid, objoid, objsubid,
4739 noldmembers, oldmembers,
4740 nnewmembers, newmembers);
4741 }
4742 }
4743
4744 systable_endscan(scan);
4745
4746 /* prevent error when processing objects multiple times */
4748
4749 table_close(relation, RowExclusiveLock);
4750}
4751
4752/*
4753 * ReplaceRoleInInitPriv
4754 *
4755 * Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
4756 */
4757void
4758ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
4759 Oid classid, Oid objid, int32 objsubid)
4760{
4761 Relation rel;
4762 ScanKeyData key[3];
4763 SysScanDesc scan;
4764 HeapTuple oldtuple;
4765 Datum oldAclDatum;
4766 bool isNull;
4767 Acl *old_acl;
4768 Acl *new_acl;
4769 HeapTuple newtuple;
4770 int noldmembers;
4771 int nnewmembers;
4772 Oid *oldmembers;
4773 Oid *newmembers;
4774
4775 /* Search for existing pg_init_privs entry for the target object. */
4776 rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4777
4778 ScanKeyInit(&key[0],
4779 Anum_pg_init_privs_objoid,
4780 BTEqualStrategyNumber, F_OIDEQ,
4781 ObjectIdGetDatum(objid));
4782 ScanKeyInit(&key[1],
4783 Anum_pg_init_privs_classoid,
4784 BTEqualStrategyNumber, F_OIDEQ,
4785 ObjectIdGetDatum(classid));
4786 ScanKeyInit(&key[2],
4787 Anum_pg_init_privs_objsubid,
4788 BTEqualStrategyNumber, F_INT4EQ,
4789 Int32GetDatum(objsubid));
4790
4791 scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4792 NULL, 3, key);
4793
4794 /* There should exist only one entry or none. */
4795 oldtuple = systable_getnext(scan);
4796
4797 if (!HeapTupleIsValid(oldtuple))
4798 {
4799 /*
4800 * Hmm, why are we here if there's no entry? But pack up and go away
4801 * quietly.
4802 */
4803 systable_endscan(scan);
4805 return;
4806 }
4807
4808 /* Get a writable copy of the existing ACL. */
4809 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4810 RelationGetDescr(rel), &isNull);
4811 Assert(!isNull);
4812 old_acl = DatumGetAclPCopy(oldAclDatum);
4813
4814 /*
4815 * Generate new ACL. This usage of aclnewowner is a bit off-label when
4816 * oldroleid isn't the owner; but it does the job fine.
4817 */
4818 new_acl = aclnewowner(old_acl, oldroleid, newroleid);
4819
4820 /*
4821 * If we end with an empty ACL, delete the pg_init_privs entry. (That
4822 * probably can't happen here, but we may as well cover the case.)
4823 */
4824 if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4825 {
4826 CatalogTupleDelete(rel, &oldtuple->t_self);
4827 }
4828 else
4829 {
4830 Datum values[Natts_pg_init_privs] = {0};
4831 bool nulls[Natts_pg_init_privs] = {0};
4832 bool replaces[Natts_pg_init_privs] = {0};
4833
4834 /* Update existing entry. */
4835 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4836 replaces[Anum_pg_init_privs_initprivs - 1] = true;
4837
4838 newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4839 values, nulls, replaces);
4840 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4841 }
4842
4843 /*
4844 * Update the shared dependency ACL info.
4845 */
4846 noldmembers = aclmembers(old_acl, &oldmembers);
4847 nnewmembers = aclmembers(new_acl, &newmembers);
4848
4849 updateInitAclDependencies(classid, objid, objsubid,
4850 noldmembers, oldmembers,
4851 nnewmembers, newmembers);
4852
4853 systable_endscan(scan);
4854
4855 /* prevent error when processing objects multiple times */
4857
4859}
4860
4861/*
4862 * RemoveRoleFromInitPriv
4863 *
4864 * Used by shdepDropOwned to remove mentions of a role in pg_init_privs.
4865 */
4866void
4867RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
4868{
4869 Relation rel;
4870 ScanKeyData key[3];
4871 SysScanDesc scan;
4872 HeapTuple oldtuple;
4873 int cacheid;
4874 HeapTuple objtuple;
4875 Oid ownerId;
4876 Datum oldAclDatum;
4877 bool isNull;
4878 Acl *old_acl;
4879 Acl *new_acl;
4880 HeapTuple newtuple;
4881 int noldmembers;
4882 int nnewmembers;
4883 Oid *oldmembers;
4884 Oid *newmembers;
4885
4886 /* Search for existing pg_init_privs entry for the target object. */
4887 rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4888
4889 ScanKeyInit(&key[0],
4890 Anum_pg_init_privs_objoid,
4891 BTEqualStrategyNumber, F_OIDEQ,
4892 ObjectIdGetDatum(objid));
4893 ScanKeyInit(&key[1],
4894 Anum_pg_init_privs_classoid,
4895 BTEqualStrategyNumber, F_OIDEQ,
4896 ObjectIdGetDatum(classid));
4897 ScanKeyInit(&key[2],
4898 Anum_pg_init_privs_objsubid,
4899 BTEqualStrategyNumber, F_INT4EQ,
4900 Int32GetDatum(objsubid));
4901
4902 scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4903 NULL, 3, key);
4904
4905 /* There should exist only one entry or none. */
4906 oldtuple = systable_getnext(scan);
4907
4908 if (!HeapTupleIsValid(oldtuple))
4909 {
4910 /*
4911 * Hmm, why are we here if there's no entry? But pack up and go away
4912 * quietly.
4913 */
4914 systable_endscan(scan);
4916 return;
4917 }
4918
4919 /* Get a writable copy of the existing ACL. */
4920 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4921 RelationGetDescr(rel), &isNull);
4922 Assert(!isNull);
4923 old_acl = DatumGetAclPCopy(oldAclDatum);
4924
4925 /*
4926 * We need the members of both old and new ACLs so we can correct the
4927 * shared dependency information. Collect data before
4928 * merge_acl_with_grant throws away old_acl.
4929 */
4930 noldmembers = aclmembers(old_acl, &oldmembers);
4931
4932 /* Must find out the owner's OID the hard way. */
4933 cacheid = get_object_catcache_oid(classid);
4934 objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
4935 if (!HeapTupleIsValid(objtuple))
4936 elog(ERROR, "cache lookup failed for %s %u",
4937 get_object_class_descr(classid), objid);
4938
4939 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4940 objtuple,
4941 get_object_attnum_owner(classid)));
4942 ReleaseSysCache(objtuple);
4943
4944 /*
4945 * Generate new ACL. Grantor of rights is always the same as the owner.
4946 */
4947 if (old_acl != NULL)
4948 new_acl = merge_acl_with_grant(old_acl,
4949 false, /* is_grant */
4950 false, /* grant_option */
4952 list_make1_oid(roleid),
4954 ownerId,
4955 ownerId);
4956 else
4957 new_acl = NULL; /* this case shouldn't happen, probably */
4958
4959 /* If we end with an empty ACL, delete the pg_init_privs entry. */
4960 if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4961 {
4962 CatalogTupleDelete(rel, &oldtuple->t_self);
4963 }
4964 else
4965 {
4966 Datum values[Natts_pg_init_privs] = {0};
4967 bool nulls[Natts_pg_init_privs] = {0};
4968 bool replaces[Natts_pg_init_privs] = {0};
4969
4970 /* Update existing entry. */
4971 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4972 replaces[Anum_pg_init_privs_initprivs - 1] = true;
4973
4974 newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4975 values, nulls, replaces);
4976 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4977 }
4978
4979 /*
4980 * Update the shared dependency ACL info.
4981 */
4982 nnewmembers = aclmembers(new_acl, &newmembers);
4983
4984 updateInitAclDependencies(classid, objid, objsubid,
4985 noldmembers, oldmembers,
4986 nnewmembers, newmembers);
4987
4988 systable_endscan(scan);
4989
4990 /* prevent error when processing objects multiple times */
4992
4994}
Acl * aclconcat(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:477
Acl * aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
Definition: acl.c:501
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition: acl.c:803
bool aclequal(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:559
Acl * aclupdate(const Acl *old_acl, const AclItem *mod_aip, int modechg, Oid ownerId, DropBehavior behavior)
Definition: acl.c:992
void select_best_grantor(Oid roleId, AclMode privileges, const Acl *acl, Oid ownerId, Oid *grantorId, AclMode *grantOptions)
Definition: acl.c:5476
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5284
Acl * make_empty_acl(void)
Definition: acl.c:448
int aclmembers(const Acl *acl, Oid **roleids)
Definition: acl.c:1540
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1119
Acl * aclcopy(const Acl *orig_acl)
Definition: acl.c:457
void aclitemsort(Acl *acl)
Definition: acl.c:545
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1388
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5586
#define ACLITEM_ALL_PRIV_BITS
Definition: acl.h:87
#define ACL_ALL_RIGHTS_FOREIGN_SERVER
Definition: acl.h:164
#define ACL_ALL_RIGHTS_TABLESPACE
Definition: acl.h:170
AclResult
Definition: acl.h:182
@ ACLCHECK_NO_PRIV
Definition: acl.h:184
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
#define ACL_ALL_RIGHTS_PARAMETER_ACL
Definition: acl.h:168
#define ACL_ALL_RIGHTS_SCHEMA
Definition: acl.h:169
#define DatumGetAclP(X)
Definition: acl.h:120
#define ACL_MODECHG_DEL
Definition: acl.h:130
#define ACL_ALL_RIGHTS_SEQUENCE
Definition: acl.h:161
#define ACL_ALL_RIGHTS_DATABASE
Definition: acl.h:162
#define ACL_MODECHG_ADD
Definition: acl.h:129
#define ACL_ALL_RIGHTS_COLUMN
Definition: acl.h:159
#define ACL_OPTION_TO_PRIVS(privs)
Definition: acl.h:71
#define ACL_ALL_RIGHTS_FUNCTION
Definition: acl.h:165
#define ACL_ALL_RIGHTS_LANGUAGE
Definition: acl.h:166
#define ACL_ALL_RIGHTS_TYPE
Definition: acl.h:171
#define ACL_ALL_RIGHTS_FDW
Definition: acl.h:163
#define ACLITEM_SET_PRIVS_GOPTIONS(item, privs, goptions)
Definition: acl.h:82
#define ACL_NUM(ACL)
Definition: acl.h:108
#define DatumGetAclPCopy(X)
Definition: acl.h:121
#define ACL_ALL_RIGHTS_RELATION
Definition: acl.h:160
#define ACL_ID_PUBLIC
Definition: acl.h:46
#define ACL_ALL_RIGHTS_LARGEOBJECT
Definition: acl.h:167
AclMaskHow
Definition: acl.h:175
@ ACLMASK_ANY
Definition: acl.h:177
@ ACLMASK_ALL
Definition: acl.h:176
#define ACL_GRANT_OPTION_FOR(privs)
Definition: acl.h:70
static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3158
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3846
void ExecuteGrantStmt(GrantStmt *stmt)
Definition: aclchk.c:391
AclResult pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, Snapshot snapshot)
Definition: aclchk.c:4076
static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
Definition: aclchk.c:1593
void RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4867
static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4601
static void expand_col_privileges(List *colnames, Oid table_oid, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
Definition: aclchk.c:1560
bool has_bypassrls_privilege(Oid roleid)
Definition: aclchk.c:4188
AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:4049
void aclcheck_error_col(AclResult aclerr, ObjectType objtype, const char *objectname, const char *colname)
Definition: aclchk.c:2943
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3921
void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, Acl *acl)
Definition: aclchk.c:4327
static void ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, AttrNumber attnum, Oid ownerId, AclMode col_privileges, Relation attRelation, const Acl *old_rel_acl)
Definition: aclchk.c:1639
static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2403
void ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
Definition: aclchk.c:916
static void ExecGrantStmt_oids(InternalGrant *istmt)
Definition: aclchk.c:601
static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, AclMode mask, AclMaskHow how, Snapshot snapshot)
Definition: aclchk.c:3535
static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3147
static List * objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
Definition: aclchk.c:677
static AclMode pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3412
AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
Definition: aclchk.c:3910
static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3476
static void SetDefaultACL(InternalDefaultACL *iacls)
Definition: aclchk.c:1147
static List * objectsInSchemaToOids(ObjectType objtype, List *nspnames)
Definition: aclchk.c:789
AclResult pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
Definition: aclchk.c:4064
void ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4758
static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
Definition: aclchk.c:2115
static Acl * merge_acl_with_grant(Acl *old_acl, bool is_grant, bool grant_option, DropBehavior behavior, List *grantees, AclMode privileges, Oid grantorId, Oid ownerId)
Definition: aclchk.c:181
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:4354
static List * getRelationsInNamespace(Oid namespaceId, char relkind)
Definition: aclchk.c:878
static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3282
static AclMode string_to_privilege(const char *privname)
Definition: aclchk.c:2566
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2654
static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3046
static void ExecGrant_Largeobject(InternalGrant *istmt)
Definition: aclchk.c:2267
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3868
static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, AclMode privileges, Oid objectId, Oid grantorId, ObjectType objtype, const char *objname, AttrNumber att_number, const char *colname)
Definition: aclchk.c:240
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3836
static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4630
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4090
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3880
static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3608
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
Definition: aclchk.c:1105
AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3272
static void ExecGrant_Parameter(InternalGrant *istmt)
Definition: aclchk.c:2423
static const char * privilege_to_string(AclMode privilege)
Definition: aclchk.c:2607
static Acl * get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
Definition: aclchk.c:4212
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2973
bool has_createrole_privilege(Oid roleid)
Definition: aclchk.c:4169
static void ExecGrant_Relation(InternalGrant *istmt)
Definition: aclchk.c:1784
static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3710
bool binary_upgrade_record_init_privs
Definition: aclchk.c:109
Acl * get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
Definition: aclchk.c:4247
void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
Definition: aclchk.c:1422
static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2251
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4039
static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:2985
static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3057
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:4518
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:765
#define gettext_noop(x)
Definition: c.h:1194
int32_t int32
Definition: c.h:548
#define OidIsValid(objectId)
Definition: c.h:788
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:448
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:86
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:371
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:274
@ DEPENDENCY_AUTO
Definition: dependency.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errhint(const char *fmt,...)
Definition: elog.c:1330
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
bool EventTriggerSupportsObjectType(ObjectType obtype)
void EventTriggerCollectGrant(InternalGrant *istmt)
bool creating_extension
Definition: extension.c:77
#define palloc0_array(type, count)
Definition: fe_memutils.h:77
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
Oid MyDatabaseId
Definition: globals.c:94
char * convert_GUC_name_for_parameter_acl(const char *name)
Definition: guc.c:1251
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1361
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:904
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition: indexing.c:365
int j
Definition: isn.c:78
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
Definition: lmgr.c:601
int LOCKMODE
Definition: lockdefs.h:26
#define AccessShareLock
Definition: lockdefs.h:36
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2093
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:949
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2924
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3648
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:531
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:477
Oid GetUserId(void)
Definition: miscinit.c:469
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3455
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3719
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3605
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:98
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
AttrNumber get_object_attnum_owner(Oid class_id)
AttrNumber get_object_attnum_oid(Oid class_id)
AttrNumber get_object_attnum_name(Oid class_id)
const char * get_object_class_descr(Oid class_id)
AttrNumber get_object_attnum_acl(Oid class_id)
int get_object_catcache_oid(Oid class_id)
Oid get_object_oid_index(Oid class_id)
ObjectType get_object_type(Oid class_id, Oid object_id)
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:423
#define ACL_CREATE_TEMP
Definition: parsenodes.h:86
#define ACL_SET
Definition: parsenodes.h:88
#define ACL_DELETE
Definition: parsenodes.h:79
uint64 AclMode
Definition: parsenodes.h:74
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define ACL_INSERT
Definition: parsenodes.h:76
#define ACL_NO_RIGHTS
Definition: parsenodes.h:92
#define ACL_UPDATE
Definition: parsenodes.h:78
DropBehavior
Definition: parsenodes.h:2397
@ DROP_CASCADE
Definition: parsenodes.h:2399
@ DROP_RESTRICT
Definition: parsenodes.h:2398
ObjectType
Definition: parsenodes.h:2324
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2339
@ OBJECT_FDW
Definition: parsenodes.h:2341
@ OBJECT_TSPARSER
Definition: parsenodes.h:2372
@ OBJECT_COLLATION
Definition: parsenodes.h:2332
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2375
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2325
@ OBJECT_OPCLASS
Definition: parsenodes.h:2349
@ OBJECT_DEFACL
Definition: parsenodes.h:2336
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2326
@ OBJECT_MATVIEW
Definition: parsenodes.h:2348
@ OBJECT_SCHEMA
Definition: parsenodes.h:2361
@ OBJECT_POLICY
Definition: parsenodes.h:2353
@ OBJECT_OPERATOR
Definition: parsenodes.h:2350
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2343
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2370
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2351
@ OBJECT_DOMAIN
Definition: parsenodes.h:2337
@ OBJECT_COLUMN
Definition: parsenodes.h:2331
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2367
@ OBJECT_ROLE
Definition: parsenodes.h:2358
@ OBJECT_ROUTINE
Definition: parsenodes.h:2359
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2347
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2356
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2354
@ OBJECT_EXTENSION
Definition: parsenodes.h:2340
@ OBJECT_INDEX
Definition: parsenodes.h:2345
@ OBJECT_DEFAULT
Definition: parsenodes.h:2335
@ OBJECT_DATABASE
Definition: parsenodes.h:2334
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2362
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2373
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2346
@ OBJECT_AMOP
Definition: parsenodes.h:2327
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2357
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2342
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2371
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2329
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2355
@ OBJECT_RULE
Definition: parsenodes.h:2360
@ OBJECT_CONVERSION
Definition: parsenodes.h:2333
@ OBJECT_AMPROC
Definition: parsenodes.h:2328
@ OBJECT_TABLE
Definition: parsenodes.h:2366
@ OBJECT_VIEW
Definition: parsenodes.h:2376
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2352
@ OBJECT_TYPE
Definition: parsenodes.h:2374
@ OBJECT_FUNCTION
Definition: parsenodes.h:2344
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2365
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2338
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2363
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2364
@ OBJECT_CAST
Definition: parsenodes.h:2330
@ OBJECT_TRIGGER
Definition: parsenodes.h:2369
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2368
@ ACL_TARGET_OBJECT
Definition: parsenodes.h:2570
@ ACL_TARGET_ALL_IN_SCHEMA
Definition: parsenodes.h:2571
#define ACL_CONNECT
Definition: parsenodes.h:87
#define ACL_ALTER_SYSTEM
Definition: parsenodes.h:89
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define ACL_SELECT
Definition: parsenodes.h:77
#define ACL_TRUNCATE
Definition: parsenodes.h:80
#define ACL_EXECUTE
Definition: parsenodes.h:83
#define ACL_CREATE
Definition: parsenodes.h:85
#define ACL_TRIGGER
Definition: parsenodes.h:82
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
bool rolcreaterole
Definition: pg_authid.h:37
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
bool rolbypassrls
Definition: pg_authid.h:41
static PgChecksumMode mode
Definition: pg_checksums.c:56
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:156
#define NAMEDATALEN
FormData_pg_default_acl * Form_pg_default_acl
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
@ INITPRIVS_EXTENSION
Definition: pg_init_privs.h:80
FormData_pg_language * Form_pg_language
Definition: pg_language.h:65
FormData_pg_largeobject_metadata * Form_pg_largeobject_metadata
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define lfirst_oid(lc)
Definition: pg_list.h:174
FormData_pg_namespace * Form_pg_namespace
Definition: pg_namespace.h:52
Oid ParameterAclLookup(const char *parameter, bool missing_ok)
Oid ParameterAclCreate(const char *parameter)
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:491
void updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:512
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
NameData typname
Definition: pg_type.h:41
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79
#define snprintf
Definition: port.h:260
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
static Name DatumGetName(Datum X)
Definition: postgres.h:370
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:252
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:182
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
static Datum CharGetDatum(char X)
Definition: postgres.h:132
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetDescr(relation)
Definition: rel.h:541
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:28
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char * priv_name
Definition: parsenodes.h:2627
List * cols
Definition: parsenodes.h:2628
Definition: acl.h:55
Oid ai_grantee
Definition: acl.h:56
Oid ai_grantor
Definition: acl.h:57
char * defname
Definition: parsenodes.h:843
Node * arg
Definition: parsenodes.h:844
ItemPointerData t_self
Definition: htup.h:65
AclMode privileges
Definition: aclchk.c:98
List * grantees
Definition: aclchk.c:99
DropBehavior behavior
Definition: aclchk.c:101
ObjectType objtype
Definition: aclchk.c:96
DropBehavior behavior
AclMode privileges
ObjectType objtype
Definition: pg_list.h:54
Definition: nodes.h:135
RoleSpecType roletype
Definition: parsenodes.h:429
Definition: c.h:706
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCacheLocked1(int cacheId, Datum key1)
Definition: syscache.c:282
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:240
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:595
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:230
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:625
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *key)
Definition: tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:985
#define strVal(v)
Definition: value.h:82
text * cstring_to_text(const char *s)
Definition: varlena.c:181
const char * name
void CommandCounterIncrement(void)
Definition: xact.c:1101