Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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 & ~((AclMode) 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 & ~((AclMode) 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 GRANT/REVOKE ON SCHEMAS")));
1211 objtype = DEFACLOBJ_NAMESPACE;
1212 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1213 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1214 break;
1215
1216 case OBJECT_LARGEOBJECT:
1217 if (OidIsValid(iacls->nspid))
1218 ereport(ERROR,
1219 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1220 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON LARGE OBJECTS")));
1221 objtype = DEFACLOBJ_LARGEOBJECT;
1222 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1223 this_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
1224 break;
1225
1226 default:
1227 elog(ERROR, "unrecognized object type: %d",
1228 (int) iacls->objtype);
1229 objtype = 0; /* keep compiler quiet */
1230 break;
1231 }
1232
1233 /* Search for existing row for this object type in catalog */
1234 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1235 ObjectIdGetDatum(iacls->roleid),
1236 ObjectIdGetDatum(iacls->nspid),
1237 CharGetDatum(objtype));
1238
1239 if (HeapTupleIsValid(tuple))
1240 {
1241 Datum aclDatum;
1242 bool isNull;
1243
1244 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1245 Anum_pg_default_acl_defaclacl,
1246 &isNull);
1247 if (!isNull)
1248 old_acl = DatumGetAclPCopy(aclDatum);
1249 else
1250 old_acl = NULL; /* this case shouldn't happen, probably */
1251 isNew = false;
1252 }
1253 else
1254 {
1255 old_acl = NULL;
1256 isNew = true;
1257 }
1258
1259 if (old_acl != NULL)
1260 {
1261 /*
1262 * We need the members of both old and new ACLs so we can correct the
1263 * shared dependency information. Collect data before
1264 * merge_acl_with_grant throws away old_acl.
1265 */
1266 noldmembers = aclmembers(old_acl, &oldmembers);
1267 }
1268 else
1269 {
1270 /* If no or null entry, start with the default ACL value */
1271 old_acl = aclcopy(def_acl);
1272 /* There are no old member roles according to the catalogs */
1273 noldmembers = 0;
1274 oldmembers = NULL;
1275 }
1276
1277 /*
1278 * Generate new ACL. Grantor of rights is always the same as the target
1279 * role.
1280 */
1281 new_acl = merge_acl_with_grant(old_acl,
1282 iacls->is_grant,
1283 iacls->grant_option,
1284 iacls->behavior,
1285 iacls->grantees,
1286 this_privileges,
1287 iacls->roleid,
1288 iacls->roleid);
1289
1290 /*
1291 * If the result is the same as the default value, we do not need an
1292 * explicit pg_default_acl entry, and should in fact remove the entry if
1293 * it exists. Must sort both arrays to compare properly.
1294 */
1295 aclitemsort(new_acl);
1296 aclitemsort(def_acl);
1297 if (aclequal(new_acl, def_acl))
1298 {
1299 /* delete old entry, if indeed there is one */
1300 if (!isNew)
1301 {
1302 ObjectAddress myself;
1303
1304 /*
1305 * The dependency machinery will take care of removing all
1306 * associated dependency entries. We use DROP_RESTRICT since
1307 * there shouldn't be anything depending on this entry.
1308 */
1309 myself.classId = DefaultAclRelationId;
1310 myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1311 myself.objectSubId = 0;
1312
1313 performDeletion(&myself, DROP_RESTRICT, 0);
1314 }
1315 }
1316 else
1317 {
1318 Datum values[Natts_pg_default_acl] = {0};
1319 bool nulls[Natts_pg_default_acl] = {0};
1320 bool replaces[Natts_pg_default_acl] = {0};
1321 Oid defAclOid;
1322
1323 if (isNew)
1324 {
1325 /* insert new entry */
1326 defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1327 Anum_pg_default_acl_oid);
1328 values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1329 values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1330 values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1331 values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1332 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1333
1334 newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1335 CatalogTupleInsert(rel, newtuple);
1336 }
1337 else
1338 {
1339 defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1340
1341 /* update existing entry */
1342 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1343 replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1344
1345 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1346 values, nulls, replaces);
1347 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1348 }
1349
1350 /* these dependencies don't change in an update */
1351 if (isNew)
1352 {
1353 /* dependency on role */
1354 recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1355 iacls->roleid);
1356
1357 /* dependency on namespace */
1358 if (OidIsValid(iacls->nspid))
1359 {
1360 ObjectAddress myself,
1361 referenced;
1362
1363 myself.classId = DefaultAclRelationId;
1364 myself.objectId = defAclOid;
1365 myself.objectSubId = 0;
1366
1367 referenced.classId = NamespaceRelationId;
1368 referenced.objectId = iacls->nspid;
1369 referenced.objectSubId = 0;
1370
1371 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1372 }
1373 }
1374
1375 /*
1376 * Update the shared dependency ACL info
1377 */
1378 nnewmembers = aclmembers(new_acl, &newmembers);
1379
1380 updateAclDependencies(DefaultAclRelationId,
1381 defAclOid, 0,
1382 iacls->roleid,
1383 noldmembers, oldmembers,
1384 nnewmembers, newmembers);
1385
1386 if (isNew)
1387 InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1388 else
1389 InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1390 }
1391
1392 if (HeapTupleIsValid(tuple))
1393 ReleaseSysCache(tuple);
1394
1396
1397 /* prevent error when processing duplicate objects */
1399}
1400
1401
1402/*
1403 * RemoveRoleFromObjectACL
1404 *
1405 * Used by shdepDropOwned to remove mentions of a role in ACLs.
1406 *
1407 * Notice that this doesn't accept an objsubid parameter, which is a bit bogus
1408 * since the pg_shdepend record that caused us to call it certainly had one.
1409 * If, for example, pg_shdepend records the existence of a permission on
1410 * mytable.mycol, this function will effectively issue a REVOKE ALL ON TABLE
1411 * mytable. That gets the job done because (per SQL spec) such a REVOKE also
1412 * revokes per-column permissions. We could not recreate a situation where
1413 * the role has table-level but not column-level permissions; but it's okay
1414 * (for now anyway) because this is only used when we're dropping the role
1415 * and so all its permissions everywhere must go away. At worst it's a bit
1416 * inefficient if the role has column permissions on several columns of the
1417 * same table.
1418 */
1419void
1420RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1421{
1422 if (classid == DefaultAclRelationId)
1423 {
1424 InternalDefaultACL iacls;
1425 Form_pg_default_acl pg_default_acl_tuple;
1426 Relation rel;
1427 ScanKeyData skey[1];
1428 SysScanDesc scan;
1429 HeapTuple tuple;
1430
1431 /* first fetch info needed by SetDefaultACL */
1432 rel = table_open(DefaultAclRelationId, AccessShareLock);
1433
1434 ScanKeyInit(&skey[0],
1435 Anum_pg_default_acl_oid,
1436 BTEqualStrategyNumber, F_OIDEQ,
1437 ObjectIdGetDatum(objid));
1438
1439 scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1440 NULL, 1, skey);
1441
1442 tuple = systable_getnext(scan);
1443
1444 if (!HeapTupleIsValid(tuple))
1445 elog(ERROR, "could not find tuple for default ACL %u", objid);
1446
1447 pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1448
1449 iacls.roleid = pg_default_acl_tuple->defaclrole;
1450 iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1451
1452 switch (pg_default_acl_tuple->defaclobjtype)
1453 {
1454 case DEFACLOBJ_RELATION:
1455 iacls.objtype = OBJECT_TABLE;
1456 break;
1457 case DEFACLOBJ_SEQUENCE:
1458 iacls.objtype = OBJECT_SEQUENCE;
1459 break;
1460 case DEFACLOBJ_FUNCTION:
1461 iacls.objtype = OBJECT_FUNCTION;
1462 break;
1463 case DEFACLOBJ_TYPE:
1464 iacls.objtype = OBJECT_TYPE;
1465 break;
1466 case DEFACLOBJ_NAMESPACE:
1467 iacls.objtype = OBJECT_SCHEMA;
1468 break;
1469 case DEFACLOBJ_LARGEOBJECT:
1471 break;
1472 default:
1473 /* Shouldn't get here */
1474 elog(ERROR, "unexpected default ACL type: %d",
1475 (int) pg_default_acl_tuple->defaclobjtype);
1476 break;
1477 }
1478
1479 systable_endscan(scan);
1481
1482 iacls.is_grant = false;
1483 iacls.all_privs = true;
1484 iacls.privileges = ACL_NO_RIGHTS;
1485 iacls.grantees = list_make1_oid(roleid);
1486 iacls.grant_option = false;
1487 iacls.behavior = DROP_CASCADE;
1488
1489 /* Do it */
1490 SetDefaultACL(&iacls);
1491 }
1492 else
1493 {
1494 InternalGrant istmt;
1495
1496 switch (classid)
1497 {
1498 case RelationRelationId:
1499 /* it's OK to use TABLE for a sequence */
1500 istmt.objtype = OBJECT_TABLE;
1501 break;
1502 case DatabaseRelationId:
1503 istmt.objtype = OBJECT_DATABASE;
1504 break;
1505 case TypeRelationId:
1506 istmt.objtype = OBJECT_TYPE;
1507 break;
1508 case ProcedureRelationId:
1509 istmt.objtype = OBJECT_ROUTINE;
1510 break;
1511 case LanguageRelationId:
1512 istmt.objtype = OBJECT_LANGUAGE;
1513 break;
1514 case LargeObjectRelationId:
1516 break;
1517 case NamespaceRelationId:
1518 istmt.objtype = OBJECT_SCHEMA;
1519 break;
1520 case TableSpaceRelationId:
1521 istmt.objtype = OBJECT_TABLESPACE;
1522 break;
1523 case ForeignServerRelationId:
1525 break;
1526 case ForeignDataWrapperRelationId:
1527 istmt.objtype = OBJECT_FDW;
1528 break;
1529 case ParameterAclRelationId:
1531 break;
1532 default:
1533 elog(ERROR, "unexpected object class %u", classid);
1534 break;
1535 }
1536 istmt.is_grant = false;
1537 istmt.objects = list_make1_oid(objid);
1538 istmt.all_privs = true;
1539 istmt.privileges = ACL_NO_RIGHTS;
1540 istmt.col_privs = NIL;
1541 istmt.grantees = list_make1_oid(roleid);
1542 istmt.grant_option = false;
1543 istmt.behavior = DROP_CASCADE;
1544
1545 ExecGrantStmt_oids(&istmt);
1546 }
1547}
1548
1549
1550/*
1551 * expand_col_privileges
1552 *
1553 * OR the specified privilege(s) into per-column array entries for each
1554 * specified attribute. The per-column array is indexed starting at
1555 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1556 */
1557static void
1558expand_col_privileges(List *colnames, Oid table_oid,
1559 AclMode this_privileges,
1560 AclMode *col_privileges,
1561 int num_col_privileges)
1562{
1563 ListCell *cell;
1564
1565 foreach(cell, colnames)
1566 {
1567 char *colname = strVal(lfirst(cell));
1569
1570 attnum = get_attnum(table_oid, colname);
1572 ereport(ERROR,
1573 (errcode(ERRCODE_UNDEFINED_COLUMN),
1574 errmsg("column \"%s\" of relation \"%s\" does not exist",
1575 colname, get_rel_name(table_oid))));
1577 if (attnum <= 0 || attnum >= num_col_privileges)
1578 elog(ERROR, "column number out of range"); /* safety check */
1579 col_privileges[attnum] |= this_privileges;
1580 }
1581}
1582
1583/*
1584 * expand_all_col_privileges
1585 *
1586 * OR the specified privilege(s) into per-column array entries for each valid
1587 * attribute of a relation. The per-column array is indexed starting at
1588 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1589 */
1590static void
1592 AclMode this_privileges,
1593 AclMode *col_privileges,
1594 int num_col_privileges)
1595{
1596 AttrNumber curr_att;
1597
1598 Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1599 for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1600 curr_att <= classForm->relnatts;
1601 curr_att++)
1602 {
1603 HeapTuple attTuple;
1604 bool isdropped;
1605
1606 if (curr_att == InvalidAttrNumber)
1607 continue;
1608
1609 /* Views don't have any system columns at all */
1610 if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1611 continue;
1612
1613 attTuple = SearchSysCache2(ATTNUM,
1614 ObjectIdGetDatum(table_oid),
1615 Int16GetDatum(curr_att));
1616 if (!HeapTupleIsValid(attTuple))
1617 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1618 curr_att, table_oid);
1619
1620 isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1621
1622 ReleaseSysCache(attTuple);
1623
1624 /* ignore dropped columns */
1625 if (isdropped)
1626 continue;
1627
1628 col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1629 }
1630}
1631
1632/*
1633 * This processes attributes, but expects to be called from
1634 * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1635 */
1636static void
1637ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1638 AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1639 Relation attRelation, const Acl *old_rel_acl)
1640{
1641 HeapTuple attr_tuple;
1642 Form_pg_attribute pg_attribute_tuple;
1643 Acl *old_acl;
1644 Acl *new_acl;
1645 Acl *merged_acl;
1646 Datum aclDatum;
1647 bool isNull;
1648 Oid grantorId;
1649 AclMode avail_goptions;
1650 bool need_update;
1651 HeapTuple newtuple;
1652 Datum values[Natts_pg_attribute] = {0};
1653 bool nulls[Natts_pg_attribute] = {0};
1654 bool replaces[Natts_pg_attribute] = {0};
1655 int noldmembers;
1656 int nnewmembers;
1657 Oid *oldmembers;
1658 Oid *newmembers;
1659
1660 attr_tuple = SearchSysCache2(ATTNUM,
1661 ObjectIdGetDatum(relOid),
1663 if (!HeapTupleIsValid(attr_tuple))
1664 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1665 attnum, relOid);
1666 pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1667
1668 /*
1669 * Get working copy of existing ACL. If there's no ACL, substitute the
1670 * proper default.
1671 */
1672 aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1673 &isNull);
1674 if (isNull)
1675 {
1676 old_acl = acldefault(OBJECT_COLUMN, ownerId);
1677 /* There are no old member roles according to the catalogs */
1678 noldmembers = 0;
1679 oldmembers = NULL;
1680 }
1681 else
1682 {
1683 old_acl = DatumGetAclPCopy(aclDatum);
1684 /* Get the roles mentioned in the existing ACL */
1685 noldmembers = aclmembers(old_acl, &oldmembers);
1686 }
1687
1688 /*
1689 * In select_best_grantor we should consider existing table-level ACL bits
1690 * as well as the per-column ACL. Build a new ACL that is their
1691 * concatenation. (This is a bit cheap and dirty compared to merging them
1692 * properly with no duplications, but it's all we need here.)
1693 */
1694 merged_acl = aclconcat(old_rel_acl, old_acl);
1695
1696 /* Determine ID to do the grant as, and available grant options */
1697 select_best_grantor(GetUserId(), col_privileges,
1698 merged_acl, ownerId,
1699 &grantorId, &avail_goptions);
1700
1701 pfree(merged_acl);
1702
1703 /*
1704 * Restrict the privileges to what we can actually grant, and emit the
1705 * standards-mandated warning and error messages. Note: we don't track
1706 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1707 * each column; we just approximate it by whether all the possible
1708 * privileges are specified now. Since the all_privs flag only determines
1709 * whether a warning is issued, this seems close enough.
1710 */
1711 col_privileges =
1712 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1713 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1714 col_privileges,
1715 relOid, grantorId, OBJECT_COLUMN,
1716 relname, attnum,
1717 NameStr(pg_attribute_tuple->attname));
1718
1719 /*
1720 * Generate new ACL.
1721 */
1722 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1723 istmt->grant_option,
1724 istmt->behavior, istmt->grantees,
1725 col_privileges, grantorId,
1726 ownerId);
1727
1728 /*
1729 * We need the members of both old and new ACLs so we can correct the
1730 * shared dependency information.
1731 */
1732 nnewmembers = aclmembers(new_acl, &newmembers);
1733
1734 /* finished building new ACL value, now insert it */
1735
1736 /*
1737 * If the updated ACL is empty, we can set attacl to null, and maybe even
1738 * avoid an update of the pg_attribute row. This is worth testing because
1739 * we'll come through here multiple times for any relation-level REVOKE,
1740 * even if there were never any column GRANTs. Note we are assuming that
1741 * the "default" ACL state for columns is empty.
1742 */
1743 if (ACL_NUM(new_acl) > 0)
1744 {
1745 values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1746 need_update = true;
1747 }
1748 else
1749 {
1750 nulls[Anum_pg_attribute_attacl - 1] = true;
1751 need_update = !isNull;
1752 }
1753 replaces[Anum_pg_attribute_attacl - 1] = true;
1754
1755 if (need_update)
1756 {
1757 newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1758 values, nulls, replaces);
1759
1760 CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1761
1762 /* Update initial privileges for extensions */
1763 recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1764 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1765
1766 /* Update the shared dependency ACL info */
1767 updateAclDependencies(RelationRelationId, relOid, attnum,
1768 ownerId,
1769 noldmembers, oldmembers,
1770 nnewmembers, newmembers);
1771 }
1772
1773 pfree(new_acl);
1774
1775 ReleaseSysCache(attr_tuple);
1776}
1777
1778/*
1779 * This processes both sequences and non-sequences.
1780 */
1781static void
1783{
1784 Relation relation;
1785 Relation attRelation;
1786 ListCell *cell;
1787
1788 relation = table_open(RelationRelationId, RowExclusiveLock);
1789 attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1790
1791 foreach(cell, istmt->objects)
1792 {
1793 Oid relOid = lfirst_oid(cell);
1794 Datum aclDatum;
1795 Form_pg_class pg_class_tuple;
1796 bool isNull;
1797 AclMode this_privileges;
1798 AclMode *col_privileges;
1799 int num_col_privileges;
1800 bool have_col_privileges;
1801 Acl *old_acl;
1802 Acl *old_rel_acl;
1803 int noldmembers;
1804 Oid *oldmembers;
1805 Oid ownerId;
1806 HeapTuple tuple;
1807 ListCell *cell_colprivs;
1808
1809 tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relOid));
1810 if (!HeapTupleIsValid(tuple))
1811 elog(ERROR, "cache lookup failed for relation %u", relOid);
1812 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1813
1814 /* Not sensible to grant on an index */
1815 if (pg_class_tuple->relkind == RELKIND_INDEX ||
1816 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1817 ereport(ERROR,
1818 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1819 errmsg("\"%s\" is an index",
1820 NameStr(pg_class_tuple->relname))));
1821
1822 /* Composite types aren't tables either */
1823 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1824 ereport(ERROR,
1825 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1826 errmsg("\"%s\" is a composite type",
1827 NameStr(pg_class_tuple->relname))));
1828
1829 /* Used GRANT SEQUENCE on a non-sequence? */
1830 if (istmt->objtype == OBJECT_SEQUENCE &&
1831 pg_class_tuple->relkind != RELKIND_SEQUENCE)
1832 ereport(ERROR,
1833 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1834 errmsg("\"%s\" is not a sequence",
1835 NameStr(pg_class_tuple->relname))));
1836
1837 /* Adjust the default permissions based on object type */
1838 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1839 {
1840 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1841 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1842 else
1843 this_privileges = ACL_ALL_RIGHTS_RELATION;
1844 }
1845 else
1846 this_privileges = istmt->privileges;
1847
1848 /*
1849 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1850 * so we have to look at the relkind to determine the supported
1851 * permissions. The OR of table and sequence permissions were already
1852 * checked.
1853 */
1854 if (istmt->objtype == OBJECT_TABLE)
1855 {
1856 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1857 {
1858 /*
1859 * For backward compatibility, just throw a warning for
1860 * invalid sequence permissions when using the non-sequence
1861 * GRANT syntax.
1862 */
1863 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1864 {
1865 /*
1866 * Mention the object name because the user needs to know
1867 * which operations succeeded. This is required because
1868 * WARNING allows the command to continue.
1869 */
1871 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1872 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1873 NameStr(pg_class_tuple->relname))));
1874 this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1875 }
1876 }
1877 else
1878 {
1879 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1880 {
1881 /*
1882 * USAGE is the only permission supported by sequences but
1883 * not by non-sequences. Don't mention the object name
1884 * because we didn't in the combined TABLE | SEQUENCE
1885 * check.
1886 */
1887 ereport(ERROR,
1888 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1889 errmsg("invalid privilege type %s for table",
1890 "USAGE")));
1891 }
1892 }
1893 }
1894
1895 /*
1896 * Set up array in which we'll accumulate any column privilege bits
1897 * that need modification. The array is indexed such that entry [0]
1898 * corresponds to FirstLowInvalidHeapAttributeNumber.
1899 */
1900 num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1901 col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1902 have_col_privileges = false;
1903
1904 /*
1905 * If we are revoking relation privileges that are also column
1906 * privileges, we must implicitly revoke them from each column too,
1907 * per SQL spec. (We don't need to implicitly add column privileges
1908 * during GRANT because the permissions-checking code always checks
1909 * both relation and per-column privileges.)
1910 */
1911 if (!istmt->is_grant &&
1912 (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1913 {
1914 expand_all_col_privileges(relOid, pg_class_tuple,
1915 this_privileges & ACL_ALL_RIGHTS_COLUMN,
1916 col_privileges,
1917 num_col_privileges);
1918 have_col_privileges = true;
1919 }
1920
1921 /*
1922 * Get owner ID and working copy of existing ACL. If there's no ACL,
1923 * substitute the proper default.
1924 */
1925 ownerId = pg_class_tuple->relowner;
1926 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1927 &isNull);
1928 if (isNull)
1929 {
1930 switch (pg_class_tuple->relkind)
1931 {
1932 case RELKIND_SEQUENCE:
1933 old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1934 break;
1935 default:
1936 old_acl = acldefault(OBJECT_TABLE, ownerId);
1937 break;
1938 }
1939 /* There are no old member roles according to the catalogs */
1940 noldmembers = 0;
1941 oldmembers = NULL;
1942 }
1943 else
1944 {
1945 old_acl = DatumGetAclPCopy(aclDatum);
1946 /* Get the roles mentioned in the existing ACL */
1947 noldmembers = aclmembers(old_acl, &oldmembers);
1948 }
1949
1950 /* Need an extra copy of original rel ACL for column handling */
1951 old_rel_acl = aclcopy(old_acl);
1952
1953 /*
1954 * Handle relation-level privileges, if any were specified
1955 */
1956 if (this_privileges != ACL_NO_RIGHTS)
1957 {
1958 AclMode avail_goptions;
1959 Acl *new_acl;
1960 Oid grantorId;
1961 HeapTuple newtuple;
1962 Datum values[Natts_pg_class] = {0};
1963 bool nulls[Natts_pg_class] = {0};
1964 bool replaces[Natts_pg_class] = {0};
1965 int nnewmembers;
1966 Oid *newmembers;
1967 ObjectType objtype;
1968
1969 /* Determine ID to do the grant as, and available grant options */
1970 select_best_grantor(GetUserId(), this_privileges,
1971 old_acl, ownerId,
1972 &grantorId, &avail_goptions);
1973
1974 switch (pg_class_tuple->relkind)
1975 {
1976 case RELKIND_SEQUENCE:
1977 objtype = OBJECT_SEQUENCE;
1978 break;
1979 default:
1980 objtype = OBJECT_TABLE;
1981 break;
1982 }
1983
1984 /*
1985 * Restrict the privileges to what we can actually grant, and emit
1986 * the standards-mandated warning and error messages.
1987 */
1988 this_privileges =
1989 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1990 istmt->all_privs, this_privileges,
1991 relOid, grantorId, objtype,
1992 NameStr(pg_class_tuple->relname),
1993 0, NULL);
1994
1995 /*
1996 * Generate new ACL.
1997 */
1998 new_acl = merge_acl_with_grant(old_acl,
1999 istmt->is_grant,
2000 istmt->grant_option,
2001 istmt->behavior,
2002 istmt->grantees,
2003 this_privileges,
2004 grantorId,
2005 ownerId);
2006
2007 /*
2008 * We need the members of both old and new ACLs so we can correct
2009 * the shared dependency information.
2010 */
2011 nnewmembers = aclmembers(new_acl, &newmembers);
2012
2013 /* finished building new ACL value, now insert it */
2014 replaces[Anum_pg_class_relacl - 1] = true;
2015 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
2016
2017 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2018 values, nulls, replaces);
2019
2020 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2021 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2022
2023 /* Update initial privileges for extensions */
2024 recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2025
2026 /* Update the shared dependency ACL info */
2027 updateAclDependencies(RelationRelationId, relOid, 0,
2028 ownerId,
2029 noldmembers, oldmembers,
2030 nnewmembers, newmembers);
2031
2032 pfree(new_acl);
2033 }
2034 else
2035 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2036
2037 /*
2038 * Handle column-level privileges, if any were specified or implied.
2039 * We first expand the user-specified column privileges into the
2040 * array, and then iterate over all nonempty array entries.
2041 */
2042 foreach(cell_colprivs, istmt->col_privs)
2043 {
2044 AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2045
2046 if (col_privs->priv_name == NULL)
2047 this_privileges = ACL_ALL_RIGHTS_COLUMN;
2048 else
2049 this_privileges = string_to_privilege(col_privs->priv_name);
2050
2051 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2052 ereport(ERROR,
2053 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2054 errmsg("invalid privilege type %s for column",
2055 privilege_to_string(this_privileges))));
2056
2057 if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2058 this_privileges & ~((AclMode) ACL_SELECT))
2059 {
2060 /*
2061 * The only column privilege allowed on sequences is SELECT.
2062 * This is a warning not error because we do it that way for
2063 * relation-level privileges.
2064 */
2066 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2067 errmsg("sequence \"%s\" only supports SELECT column privileges",
2068 NameStr(pg_class_tuple->relname))));
2069
2070 this_privileges &= (AclMode) ACL_SELECT;
2071 }
2072
2073 expand_col_privileges(col_privs->cols, relOid,
2074 this_privileges,
2075 col_privileges,
2076 num_col_privileges);
2077 have_col_privileges = true;
2078 }
2079
2080 if (have_col_privileges)
2081 {
2082 AttrNumber i;
2083
2084 for (i = 0; i < num_col_privileges; i++)
2085 {
2086 if (col_privileges[i] == ACL_NO_RIGHTS)
2087 continue;
2088 ExecGrant_Attribute(istmt,
2089 relOid,
2090 NameStr(pg_class_tuple->relname),
2092 ownerId,
2093 col_privileges[i],
2094 attRelation,
2095 old_rel_acl);
2096 }
2097 }
2098
2099 pfree(old_rel_acl);
2100 pfree(col_privileges);
2101
2102 ReleaseSysCache(tuple);
2103
2104 /* prevent error when processing duplicate objects */
2106 }
2107
2108 table_close(attRelation, RowExclusiveLock);
2109 table_close(relation, RowExclusiveLock);
2110}
2111
2112static void
2113ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
2114 void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
2115{
2116 int cacheid;
2117 Relation relation;
2118 ListCell *cell;
2119
2120 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2121 istmt->privileges = default_privs;
2122
2123 cacheid = get_object_catcache_oid(classid);
2124
2125 relation = table_open(classid, RowExclusiveLock);
2126
2127 foreach(cell, istmt->objects)
2128 {
2129 Oid objectid = lfirst_oid(cell);
2130 Datum aclDatum;
2131 Datum nameDatum;
2132 bool isNull;
2133 AclMode avail_goptions;
2134 AclMode this_privileges;
2135 Acl *old_acl;
2136 Acl *new_acl;
2137 Oid grantorId;
2138 Oid ownerId;
2139 HeapTuple tuple;
2140 HeapTuple newtuple;
2141 Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2142 bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2143 bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2144 int noldmembers;
2145 int nnewmembers;
2146 Oid *oldmembers;
2147 Oid *newmembers;
2148
2149 tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid));
2150 if (!HeapTupleIsValid(tuple))
2151 elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2152
2153 /*
2154 * Additional object-type-specific checks
2155 */
2156 if (object_check)
2157 object_check(istmt, tuple);
2158
2159 /*
2160 * Get owner ID and working copy of existing ACL. If there's no ACL,
2161 * substitute the proper default.
2162 */
2163 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2164 tuple,
2165 get_object_attnum_owner(classid)));
2166 aclDatum = SysCacheGetAttr(cacheid,
2167 tuple,
2168 get_object_attnum_acl(classid),
2169 &isNull);
2170 if (isNull)
2171 {
2172 old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2173 /* There are no old member roles according to the catalogs */
2174 noldmembers = 0;
2175 oldmembers = NULL;
2176 }
2177 else
2178 {
2179 old_acl = DatumGetAclPCopy(aclDatum);
2180 /* Get the roles mentioned in the existing ACL */
2181 noldmembers = aclmembers(old_acl, &oldmembers);
2182 }
2183
2184 /* Determine ID to do the grant as, and available grant options */
2186 old_acl, ownerId,
2187 &grantorId, &avail_goptions);
2188
2189 nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2190 get_object_attnum_name(classid));
2191
2192 /*
2193 * Restrict the privileges to what we can actually grant, and emit the
2194 * standards-mandated warning and error messages.
2195 */
2196 this_privileges =
2197 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2198 istmt->all_privs, istmt->privileges,
2199 objectid, grantorId, get_object_type(classid, objectid),
2200 NameStr(*DatumGetName(nameDatum)),
2201 0, NULL);
2202
2203 /*
2204 * Generate new ACL.
2205 */
2206 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2207 istmt->grant_option, istmt->behavior,
2208 istmt->grantees, this_privileges,
2209 grantorId, ownerId);
2210
2211 /*
2212 * We need the members of both old and new ACLs so we can correct the
2213 * shared dependency information.
2214 */
2215 nnewmembers = aclmembers(new_acl, &newmembers);
2216
2217 /* finished building new ACL value, now insert it */
2218 replaces[get_object_attnum_acl(classid) - 1] = true;
2219 values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2220
2221 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2222 nulls, replaces);
2223
2224 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2225 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2226
2227 /* Update initial privileges for extensions */
2228 recordExtensionInitPriv(objectid, classid, 0, new_acl);
2229
2230 /* Update the shared dependency ACL info */
2231 updateAclDependencies(classid,
2232 objectid, 0,
2233 ownerId,
2234 noldmembers, oldmembers,
2235 nnewmembers, newmembers);
2236
2237 ReleaseSysCache(tuple);
2238
2239 pfree(new_acl);
2240
2241 /* prevent error when processing duplicate objects */
2243 }
2244
2245 table_close(relation, RowExclusiveLock);
2246}
2247
2248static void
2250{
2251 Form_pg_language pg_language_tuple;
2252
2253 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2254
2255 if (!pg_language_tuple->lanpltrusted)
2256 ereport(ERROR,
2257 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2258 errmsg("language \"%s\" is not trusted",
2259 NameStr(pg_language_tuple->lanname)),
2260 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2261 "because only superusers can use untrusted languages.")));
2262}
2263
2264static void
2266{
2267 Relation relation;
2268 ListCell *cell;
2269
2270 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2272
2273 relation = table_open(LargeObjectMetadataRelationId,
2275
2276 foreach(cell, istmt->objects)
2277 {
2278 Oid loid = lfirst_oid(cell);
2279 Form_pg_largeobject_metadata form_lo_meta;
2280 char loname[NAMEDATALEN];
2281 Datum aclDatum;
2282 bool isNull;
2283 AclMode avail_goptions;
2284 AclMode this_privileges;
2285 Acl *old_acl;
2286 Acl *new_acl;
2287 Oid grantorId;
2288 Oid ownerId;
2289 HeapTuple newtuple;
2290 Datum values[Natts_pg_largeobject_metadata] = {0};
2291 bool nulls[Natts_pg_largeobject_metadata] = {0};
2292 bool replaces[Natts_pg_largeobject_metadata] = {0};
2293 int noldmembers;
2294 int nnewmembers;
2295 Oid *oldmembers;
2296 Oid *newmembers;
2297 ScanKeyData entry[1];
2298 SysScanDesc scan;
2299 HeapTuple tuple;
2300
2301 /* There's no syscache for pg_largeobject_metadata */
2302 ScanKeyInit(&entry[0],
2303 Anum_pg_largeobject_metadata_oid,
2304 BTEqualStrategyNumber, F_OIDEQ,
2305 ObjectIdGetDatum(loid));
2306
2307 scan = systable_beginscan(relation,
2308 LargeObjectMetadataOidIndexId, true,
2309 NULL, 1, entry);
2310
2311 tuple = systable_getnext(scan);
2312 if (!HeapTupleIsValid(tuple))
2313 elog(ERROR, "could not find tuple for large object %u", loid);
2314
2315 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2316
2317 /*
2318 * Get owner ID and working copy of existing ACL. If there's no ACL,
2319 * substitute the proper default.
2320 */
2321 ownerId = form_lo_meta->lomowner;
2322 aclDatum = heap_getattr(tuple,
2323 Anum_pg_largeobject_metadata_lomacl,
2324 RelationGetDescr(relation), &isNull);
2325 if (isNull)
2326 {
2327 old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2328 /* There are no old member roles according to the catalogs */
2329 noldmembers = 0;
2330 oldmembers = NULL;
2331 }
2332 else
2333 {
2334 old_acl = DatumGetAclPCopy(aclDatum);
2335 /* Get the roles mentioned in the existing ACL */
2336 noldmembers = aclmembers(old_acl, &oldmembers);
2337 }
2338
2339 /* Determine ID to do the grant as, and available grant options */
2341 old_acl, ownerId,
2342 &grantorId, &avail_goptions);
2343
2344 /*
2345 * Restrict the privileges to what we can actually grant, and emit the
2346 * standards-mandated warning and error messages.
2347 */
2348 snprintf(loname, sizeof(loname), "large object %u", loid);
2349 this_privileges =
2350 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2351 istmt->all_privs, istmt->privileges,
2352 loid, grantorId, OBJECT_LARGEOBJECT,
2353 loname, 0, NULL);
2354
2355 /*
2356 * Generate new ACL.
2357 */
2358 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2359 istmt->grant_option, istmt->behavior,
2360 istmt->grantees, this_privileges,
2361 grantorId, ownerId);
2362
2363 /*
2364 * We need the members of both old and new ACLs so we can correct the
2365 * shared dependency information.
2366 */
2367 nnewmembers = aclmembers(new_acl, &newmembers);
2368
2369 /* finished building new ACL value, now insert it */
2370 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2371 values[Anum_pg_largeobject_metadata_lomacl - 1]
2372 = PointerGetDatum(new_acl);
2373
2374 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2375 values, nulls, replaces);
2376
2377 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2378
2379 /* Update initial privileges for extensions */
2380 recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2381
2382 /* Update the shared dependency ACL info */
2383 updateAclDependencies(LargeObjectRelationId,
2384 form_lo_meta->oid, 0,
2385 ownerId,
2386 noldmembers, oldmembers,
2387 nnewmembers, newmembers);
2388
2389 systable_endscan(scan);
2390
2391 pfree(new_acl);
2392
2393 /* prevent error when processing duplicate objects */
2395 }
2396
2397 table_close(relation, RowExclusiveLock);
2398}
2399
2400static void
2402{
2403 Form_pg_type pg_type_tuple;
2404
2405 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2406
2407 /* Disallow GRANT on dependent types */
2408 if (IsTrueArrayType(pg_type_tuple))
2409 ereport(ERROR,
2410 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2411 errmsg("cannot set privileges of array types"),
2412 errhint("Set the privileges of the element type instead.")));
2413 if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2414 ereport(ERROR,
2415 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2416 errmsg("cannot set privileges of multirange types"),
2417 errhint("Set the privileges of the range type instead.")));
2418}
2419
2420static void
2422{
2423 Relation relation;
2424 ListCell *cell;
2425
2426 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2428
2429 relation = table_open(ParameterAclRelationId, RowExclusiveLock);
2430
2431 foreach(cell, istmt->objects)
2432 {
2433 Oid parameterId = lfirst_oid(cell);
2434 Datum nameDatum;
2435 const char *parname;
2436 Datum aclDatum;
2437 bool isNull;
2438 AclMode avail_goptions;
2439 AclMode this_privileges;
2440 Acl *old_acl;
2441 Acl *new_acl;
2442 Oid grantorId;
2443 Oid ownerId;
2444 HeapTuple tuple;
2445 int noldmembers;
2446 int nnewmembers;
2447 Oid *oldmembers;
2448 Oid *newmembers;
2449
2450 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
2451 if (!HeapTupleIsValid(tuple))
2452 elog(ERROR, "cache lookup failed for parameter ACL %u",
2453 parameterId);
2454
2455 /* We'll need the GUC's name */
2456 nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
2457 Anum_pg_parameter_acl_parname);
2458 parname = TextDatumGetCString(nameDatum);
2459
2460 /* Treat all parameters as belonging to the bootstrap superuser. */
2461 ownerId = BOOTSTRAP_SUPERUSERID;
2462
2463 /*
2464 * Get working copy of existing ACL. If there's no ACL, substitute the
2465 * proper default.
2466 */
2467 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
2468 Anum_pg_parameter_acl_paracl,
2469 &isNull);
2470
2471 if (isNull)
2472 {
2473 old_acl = acldefault(istmt->objtype, ownerId);
2474 /* There are no old member roles according to the catalogs */
2475 noldmembers = 0;
2476 oldmembers = NULL;
2477 }
2478 else
2479 {
2480 old_acl = DatumGetAclPCopy(aclDatum);
2481 /* Get the roles mentioned in the existing ACL */
2482 noldmembers = aclmembers(old_acl, &oldmembers);
2483 }
2484
2485 /* Determine ID to do the grant as, and available grant options */
2487 old_acl, ownerId,
2488 &grantorId, &avail_goptions);
2489
2490 /*
2491 * Restrict the privileges to what we can actually grant, and emit the
2492 * standards-mandated warning and error messages.
2493 */
2494 this_privileges =
2495 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2496 istmt->all_privs, istmt->privileges,
2497 parameterId, grantorId,
2499 parname,
2500 0, NULL);
2501
2502 /*
2503 * Generate new ACL.
2504 */
2505 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2506 istmt->grant_option, istmt->behavior,
2507 istmt->grantees, this_privileges,
2508 grantorId, ownerId);
2509
2510 /*
2511 * We need the members of both old and new ACLs so we can correct the
2512 * shared dependency information.
2513 */
2514 nnewmembers = aclmembers(new_acl, &newmembers);
2515
2516 /*
2517 * If the new ACL is equal to the default, we don't need the catalog
2518 * entry any longer. Delete it rather than updating it, to avoid
2519 * leaving a degenerate entry.
2520 */
2521 if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
2522 {
2523 CatalogTupleDelete(relation, &tuple->t_self);
2524 }
2525 else
2526 {
2527 /* finished building new ACL value, now insert it */
2528 HeapTuple newtuple;
2529 Datum values[Natts_pg_parameter_acl] = {0};
2530 bool nulls[Natts_pg_parameter_acl] = {0};
2531 bool replaces[Natts_pg_parameter_acl] = {0};
2532
2533 replaces[Anum_pg_parameter_acl_paracl - 1] = true;
2534 values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
2535
2536 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2537 values, nulls, replaces);
2538
2539 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2540 }
2541
2542 /* Update initial privileges for extensions */
2543 recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
2544 new_acl);
2545
2546 /* Update the shared dependency ACL info */
2547 updateAclDependencies(ParameterAclRelationId, parameterId, 0,
2548 ownerId,
2549 noldmembers, oldmembers,
2550 nnewmembers, newmembers);
2551
2552 ReleaseSysCache(tuple);
2553 pfree(new_acl);
2554
2555 /* prevent error when processing duplicate objects */
2557 }
2558
2559 table_close(relation, RowExclusiveLock);
2560}
2561
2562
2563static AclMode
2564string_to_privilege(const char *privname)
2565{
2566 if (strcmp(privname, "insert") == 0)
2567 return ACL_INSERT;
2568 if (strcmp(privname, "select") == 0)
2569 return ACL_SELECT;
2570 if (strcmp(privname, "update") == 0)
2571 return ACL_UPDATE;
2572 if (strcmp(privname, "delete") == 0)
2573 return ACL_DELETE;
2574 if (strcmp(privname, "truncate") == 0)
2575 return ACL_TRUNCATE;
2576 if (strcmp(privname, "references") == 0)
2577 return ACL_REFERENCES;
2578 if (strcmp(privname, "trigger") == 0)
2579 return ACL_TRIGGER;
2580 if (strcmp(privname, "execute") == 0)
2581 return ACL_EXECUTE;
2582 if (strcmp(privname, "usage") == 0)
2583 return ACL_USAGE;
2584 if (strcmp(privname, "create") == 0)
2585 return ACL_CREATE;
2586 if (strcmp(privname, "temporary") == 0)
2587 return ACL_CREATE_TEMP;
2588 if (strcmp(privname, "temp") == 0)
2589 return ACL_CREATE_TEMP;
2590 if (strcmp(privname, "connect") == 0)
2591 return ACL_CONNECT;
2592 if (strcmp(privname, "set") == 0)
2593 return ACL_SET;
2594 if (strcmp(privname, "alter system") == 0)
2595 return ACL_ALTER_SYSTEM;
2596 if (strcmp(privname, "maintain") == 0)
2597 return ACL_MAINTAIN;
2598 ereport(ERROR,
2599 (errcode(ERRCODE_SYNTAX_ERROR),
2600 errmsg("unrecognized privilege type \"%s\"", privname)));
2601 return 0; /* appease compiler */
2602}
2603
2604static const char *
2606{
2607 switch (privilege)
2608 {
2609 case ACL_INSERT:
2610 return "INSERT";
2611 case ACL_SELECT:
2612 return "SELECT";
2613 case ACL_UPDATE:
2614 return "UPDATE";
2615 case ACL_DELETE:
2616 return "DELETE";
2617 case ACL_TRUNCATE:
2618 return "TRUNCATE";
2619 case ACL_REFERENCES:
2620 return "REFERENCES";
2621 case ACL_TRIGGER:
2622 return "TRIGGER";
2623 case ACL_EXECUTE:
2624 return "EXECUTE";
2625 case ACL_USAGE:
2626 return "USAGE";
2627 case ACL_CREATE:
2628 return "CREATE";
2629 case ACL_CREATE_TEMP:
2630 return "TEMP";
2631 case ACL_CONNECT:
2632 return "CONNECT";
2633 case ACL_SET:
2634 return "SET";
2635 case ACL_ALTER_SYSTEM:
2636 return "ALTER SYSTEM";
2637 case ACL_MAINTAIN:
2638 return "MAINTAIN";
2639 default:
2640 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2641 }
2642 return NULL; /* appease compiler */
2643}
2644
2645/*
2646 * Standardized reporting of aclcheck permissions failures.
2647 *
2648 * Note: we do not double-quote the %s's below, because many callers
2649 * supply strings that might be already quoted.
2650 */
2651void
2653 const char *objectname)
2654{
2655 switch (aclerr)
2656 {
2657 case ACLCHECK_OK:
2658 /* no error, so return to caller */
2659 break;
2660 case ACLCHECK_NO_PRIV:
2661 {
2662 const char *msg = "???";
2663
2664 switch (objtype)
2665 {
2666 case OBJECT_AGGREGATE:
2667 msg = gettext_noop("permission denied for aggregate %s");
2668 break;
2669 case OBJECT_COLLATION:
2670 msg = gettext_noop("permission denied for collation %s");
2671 break;
2672 case OBJECT_COLUMN:
2673 msg = gettext_noop("permission denied for column %s");
2674 break;
2675 case OBJECT_CONVERSION:
2676 msg = gettext_noop("permission denied for conversion %s");
2677 break;
2678 case OBJECT_DATABASE:
2679 msg = gettext_noop("permission denied for database %s");
2680 break;
2681 case OBJECT_DOMAIN:
2682 msg = gettext_noop("permission denied for domain %s");
2683 break;
2685 msg = gettext_noop("permission denied for event trigger %s");
2686 break;
2687 case OBJECT_EXTENSION:
2688 msg = gettext_noop("permission denied for extension %s");
2689 break;
2690 case OBJECT_FDW:
2691 msg = gettext_noop("permission denied for foreign-data wrapper %s");
2692 break;
2694 msg = gettext_noop("permission denied for foreign server %s");
2695 break;
2697 msg = gettext_noop("permission denied for foreign table %s");
2698 break;
2699 case OBJECT_FUNCTION:
2700 msg = gettext_noop("permission denied for function %s");
2701 break;
2702 case OBJECT_INDEX:
2703 msg = gettext_noop("permission denied for index %s");
2704 break;
2705 case OBJECT_LANGUAGE:
2706 msg = gettext_noop("permission denied for language %s");
2707 break;
2708 case OBJECT_LARGEOBJECT:
2709 msg = gettext_noop("permission denied for large object %s");
2710 break;
2711 case OBJECT_MATVIEW:
2712 msg = gettext_noop("permission denied for materialized view %s");
2713 break;
2714 case OBJECT_OPCLASS:
2715 msg = gettext_noop("permission denied for operator class %s");
2716 break;
2717 case OBJECT_OPERATOR:
2718 msg = gettext_noop("permission denied for operator %s");
2719 break;
2720 case OBJECT_OPFAMILY:
2721 msg = gettext_noop("permission denied for operator family %s");
2722 break;
2724 msg = gettext_noop("permission denied for parameter %s");
2725 break;
2726 case OBJECT_POLICY:
2727 msg = gettext_noop("permission denied for policy %s");
2728 break;
2729 case OBJECT_PROCEDURE:
2730 msg = gettext_noop("permission denied for procedure %s");
2731 break;
2732 case OBJECT_PUBLICATION:
2733 msg = gettext_noop("permission denied for publication %s");
2734 break;
2735 case OBJECT_ROUTINE:
2736 msg = gettext_noop("permission denied for routine %s");
2737 break;
2738 case OBJECT_SCHEMA:
2739 msg = gettext_noop("permission denied for schema %s");
2740 break;
2741 case OBJECT_SEQUENCE:
2742 msg = gettext_noop("permission denied for sequence %s");
2743 break;
2745 msg = gettext_noop("permission denied for statistics object %s");
2746 break;
2748 msg = gettext_noop("permission denied for subscription %s");
2749 break;
2750 case OBJECT_TABLE:
2751 msg = gettext_noop("permission denied for table %s");
2752 break;
2753 case OBJECT_TABLESPACE:
2754 msg = gettext_noop("permission denied for tablespace %s");
2755 break;
2757 msg = gettext_noop("permission denied for text search configuration %s");
2758 break;
2760 msg = gettext_noop("permission denied for text search dictionary %s");
2761 break;
2762 case OBJECT_TYPE:
2763 msg = gettext_noop("permission denied for type %s");
2764 break;
2765 case OBJECT_VIEW:
2766 msg = gettext_noop("permission denied for view %s");
2767 break;
2768 /* these currently aren't used */
2770 case OBJECT_AMOP:
2771 case OBJECT_AMPROC:
2772 case OBJECT_ATTRIBUTE:
2773 case OBJECT_CAST:
2774 case OBJECT_DEFAULT:
2775 case OBJECT_DEFACL:
2779 case OBJECT_ROLE:
2780 case OBJECT_RULE:
2782 case OBJECT_TRANSFORM:
2783 case OBJECT_TRIGGER:
2784 case OBJECT_TSPARSER:
2785 case OBJECT_TSTEMPLATE:
2787 elog(ERROR, "unsupported object type: %d", objtype);
2788 }
2789
2790 ereport(ERROR,
2791 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2792 errmsg(msg, objectname)));
2793 break;
2794 }
2795 case ACLCHECK_NOT_OWNER:
2796 {
2797 const char *msg = "???";
2798
2799 switch (objtype)
2800 {
2801 case OBJECT_AGGREGATE:
2802 msg = gettext_noop("must be owner of aggregate %s");
2803 break;
2804 case OBJECT_COLLATION:
2805 msg = gettext_noop("must be owner of collation %s");
2806 break;
2807 case OBJECT_CONVERSION:
2808 msg = gettext_noop("must be owner of conversion %s");
2809 break;
2810 case OBJECT_DATABASE:
2811 msg = gettext_noop("must be owner of database %s");
2812 break;
2813 case OBJECT_DOMAIN:
2814 msg = gettext_noop("must be owner of domain %s");
2815 break;
2817 msg = gettext_noop("must be owner of event trigger %s");
2818 break;
2819 case OBJECT_EXTENSION:
2820 msg = gettext_noop("must be owner of extension %s");
2821 break;
2822 case OBJECT_FDW:
2823 msg = gettext_noop("must be owner of foreign-data wrapper %s");
2824 break;
2826 msg = gettext_noop("must be owner of foreign server %s");
2827 break;
2829 msg = gettext_noop("must be owner of foreign table %s");
2830 break;
2831 case OBJECT_FUNCTION:
2832 msg = gettext_noop("must be owner of function %s");
2833 break;
2834 case OBJECT_INDEX:
2835 msg = gettext_noop("must be owner of index %s");
2836 break;
2837 case OBJECT_LANGUAGE:
2838 msg = gettext_noop("must be owner of language %s");
2839 break;
2840 case OBJECT_LARGEOBJECT:
2841 msg = gettext_noop("must be owner of large object %s");
2842 break;
2843 case OBJECT_MATVIEW:
2844 msg = gettext_noop("must be owner of materialized view %s");
2845 break;
2846 case OBJECT_OPCLASS:
2847 msg = gettext_noop("must be owner of operator class %s");
2848 break;
2849 case OBJECT_OPERATOR:
2850 msg = gettext_noop("must be owner of operator %s");
2851 break;
2852 case OBJECT_OPFAMILY:
2853 msg = gettext_noop("must be owner of operator family %s");
2854 break;
2855 case OBJECT_PROCEDURE:
2856 msg = gettext_noop("must be owner of procedure %s");
2857 break;
2858 case OBJECT_PUBLICATION:
2859 msg = gettext_noop("must be owner of publication %s");
2860 break;
2861 case OBJECT_ROUTINE:
2862 msg = gettext_noop("must be owner of routine %s");
2863 break;
2864 case OBJECT_SEQUENCE:
2865 msg = gettext_noop("must be owner of sequence %s");
2866 break;
2868 msg = gettext_noop("must be owner of subscription %s");
2869 break;
2870 case OBJECT_TABLE:
2871 msg = gettext_noop("must be owner of table %s");
2872 break;
2873 case OBJECT_TYPE:
2874 msg = gettext_noop("must be owner of type %s");
2875 break;
2876 case OBJECT_VIEW:
2877 msg = gettext_noop("must be owner of view %s");
2878 break;
2879 case OBJECT_SCHEMA:
2880 msg = gettext_noop("must be owner of schema %s");
2881 break;
2883 msg = gettext_noop("must be owner of statistics object %s");
2884 break;
2885 case OBJECT_TABLESPACE:
2886 msg = gettext_noop("must be owner of tablespace %s");
2887 break;
2889 msg = gettext_noop("must be owner of text search configuration %s");
2890 break;
2892 msg = gettext_noop("must be owner of text search dictionary %s");
2893 break;
2894
2895 /*
2896 * Special cases: For these, the error message talks
2897 * about "relation", because that's where the
2898 * ownership is attached. See also
2899 * check_object_ownership().
2900 */
2901 case OBJECT_COLUMN:
2902 case OBJECT_POLICY:
2903 case OBJECT_RULE:
2905 case OBJECT_TRIGGER:
2906 msg = gettext_noop("must be owner of relation %s");
2907 break;
2908 /* these currently aren't used */
2910 case OBJECT_AMOP:
2911 case OBJECT_AMPROC:
2912 case OBJECT_ATTRIBUTE:
2913 case OBJECT_CAST:
2914 case OBJECT_DEFAULT:
2915 case OBJECT_DEFACL:
2920 case OBJECT_ROLE:
2921 case OBJECT_TRANSFORM:
2922 case OBJECT_TSPARSER:
2923 case OBJECT_TSTEMPLATE:
2925 elog(ERROR, "unsupported object type: %d", objtype);
2926 }
2927
2928 ereport(ERROR,
2929 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2930 errmsg(msg, objectname)));
2931 break;
2932 }
2933 default:
2934 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2935 break;
2936 }
2937}
2938
2939
2940void
2942 const char *objectname, const char *colname)
2943{
2944 switch (aclerr)
2945 {
2946 case ACLCHECK_OK:
2947 /* no error, so return to caller */
2948 break;
2949 case ACLCHECK_NO_PRIV:
2950 ereport(ERROR,
2951 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2952 errmsg("permission denied for column \"%s\" of relation \"%s\"",
2953 colname, objectname)));
2954 break;
2955 case ACLCHECK_NOT_OWNER:
2956 /* relation msg is OK since columns don't have separate owners */
2957 aclcheck_error(aclerr, objtype, objectname);
2958 break;
2959 default:
2960 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2961 break;
2962 }
2963}
2964
2965
2966/*
2967 * Special common handling for types: use element type instead of array type,
2968 * and format nicely
2969 */
2970void
2972{
2973 Oid element_type = get_element_type(typeOid);
2974
2975 aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
2976}
2977
2978
2979/*
2980 * Relay for the various pg_*_mask routines depending on object kind
2981 */
2982static AclMode
2983pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
2984 AclMode mask, AclMaskHow how)
2985{
2986 switch (objtype)
2987 {
2988 case OBJECT_COLUMN:
2989 return
2990 pg_class_aclmask(object_oid, roleid, mask, how) |
2991 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
2992 case OBJECT_TABLE:
2993 case OBJECT_SEQUENCE:
2994 return pg_class_aclmask(object_oid, roleid, mask, how);
2995 case OBJECT_DATABASE:
2996 return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
2997 case OBJECT_FUNCTION:
2998 return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
2999 case OBJECT_LANGUAGE:
3000 return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
3001 case OBJECT_LARGEOBJECT:
3002 return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3003 mask, how, NULL);
3005 return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
3006 case OBJECT_SCHEMA:
3007 return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
3009 elog(ERROR, "grantable rights not supported for statistics objects");
3010 /* not reached, but keep compiler quiet */
3011 return ACL_NO_RIGHTS;
3012 case OBJECT_TABLESPACE:
3013 return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3014 case OBJECT_FDW:
3015 return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3017 return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3019 elog(ERROR, "grantable rights not supported for event triggers");
3020 /* not reached, but keep compiler quiet */
3021 return ACL_NO_RIGHTS;
3022 case OBJECT_TYPE:
3023 return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3024 default:
3025 elog(ERROR, "unrecognized object type: %d",
3026 (int) objtype);
3027 /* not reached, but keep compiler quiet */
3028 return ACL_NO_RIGHTS;
3029 }
3030}
3031
3032
3033/* ****************************************************************
3034 * Exported routines for examining a user's privileges for various objects
3035 *
3036 * See aclmask() for a description of the common API for these functions.
3037 * ****************************************************************
3038 */
3039
3040/*
3041 * Generic routine for examining a user's privileges for an object
3042 */
3043static AclMode
3044object_aclmask(Oid classid, Oid objectid, Oid roleid,
3045 AclMode mask, AclMaskHow how)
3046{
3047 return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3048}
3049
3050/*
3051 * Generic routine for examining a user's privileges for an object,
3052 * with is_missing
3053 */
3054static AclMode
3055object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
3056 AclMode mask, AclMaskHow how,
3057 bool *is_missing)
3058{
3059 int cacheid;
3060 AclMode result;
3061 HeapTuple tuple;
3062 Datum aclDatum;
3063 bool isNull;
3064 Acl *acl;
3065 Oid ownerId;
3066
3067 /* Special cases */
3068 switch (classid)
3069 {
3070 case NamespaceRelationId:
3071 return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
3072 is_missing);
3073 case TypeRelationId:
3074 return pg_type_aclmask_ext(objectid, roleid, mask, how,
3075 is_missing);
3076 }
3077
3078 /* Even more special cases */
3079 Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3080 Assert(classid != LargeObjectMetadataRelationId); /* should use
3081 * pg_largeobject_acl* */
3082
3083 /* Superusers bypass all permission checking. */
3084 if (superuser_arg(roleid))
3085 return mask;
3086
3087 /*
3088 * Get the object's ACL from its catalog
3089 */
3090
3091 cacheid = get_object_catcache_oid(classid);
3092
3093 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3094 if (!HeapTupleIsValid(tuple))
3095 {
3096 if (is_missing != NULL)
3097 {
3098 /* return "no privileges" instead of throwing an error */
3099 *is_missing = true;
3100 return 0;
3101 }
3102 else
3103 elog(ERROR, "cache lookup failed for %s %u",
3104 get_object_class_descr(classid), objectid);
3105 }
3106
3107 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3108 tuple,
3109 get_object_attnum_owner(classid)));
3110
3111 aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3112 &isNull);
3113 if (isNull)
3114 {
3115 /* No ACL, so build default ACL */
3116 acl = acldefault(get_object_type(classid, objectid), ownerId);
3117 aclDatum = (Datum) 0;
3118 }
3119 else
3120 {
3121 /* detoast ACL if necessary */
3122 acl = DatumGetAclP(aclDatum);
3123 }
3124
3125 result = aclmask(acl, roleid, ownerId, mask, how);
3126
3127 /* if we have a detoasted copy, free it */
3128 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3129 pfree(acl);
3130
3131 ReleaseSysCache(tuple);
3132
3133 return result;
3134}
3135
3136/*
3137 * Routine for examining a user's privileges for a column
3138 *
3139 * Note: this considers only privileges granted specifically on the column.
3140 * It is caller's responsibility to take relation-level privileges into account
3141 * as appropriate. (For the same reason, we have no special case for
3142 * superuser-ness here.)
3143 */
3144static AclMode
3146 AclMode mask, AclMaskHow how)
3147{
3148 return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3149 mask, how, NULL);
3150}
3151
3152/*
3153 * Routine for examining a user's privileges for a column, with is_missing
3154 */
3155static AclMode
3157 AclMode mask, AclMaskHow how, bool *is_missing)
3158{
3159 AclMode result;
3160 HeapTuple classTuple;
3161 HeapTuple attTuple;
3162 Form_pg_class classForm;
3163 Form_pg_attribute attributeForm;
3164 Datum aclDatum;
3165 bool isNull;
3166 Acl *acl;
3167 Oid ownerId;
3168
3169 /*
3170 * First, get the column's ACL from its pg_attribute entry
3171 */
3172 attTuple = SearchSysCache2(ATTNUM,
3173 ObjectIdGetDatum(table_oid),
3175 if (!HeapTupleIsValid(attTuple))
3176 {
3177 if (is_missing != NULL)
3178 {
3179 /* return "no privileges" instead of throwing an error */
3180 *is_missing = true;
3181 return 0;
3182 }
3183 else
3184 ereport(ERROR,
3185 (errcode(ERRCODE_UNDEFINED_COLUMN),
3186 errmsg("attribute %d of relation with OID %u does not exist",
3187 attnum, table_oid)));
3188 }
3189
3190 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3191
3192 /* Check dropped columns, too */
3193 if (attributeForm->attisdropped)
3194 {
3195 if (is_missing != NULL)
3196 {
3197 /* return "no privileges" instead of throwing an error */
3198 *is_missing = true;
3199 ReleaseSysCache(attTuple);
3200 return 0;
3201 }
3202 else
3203 ereport(ERROR,
3204 (errcode(ERRCODE_UNDEFINED_COLUMN),
3205 errmsg("attribute %d of relation with OID %u does not exist",
3206 attnum, table_oid)));
3207 }
3208
3209 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3210 &isNull);
3211
3212 /*
3213 * Here we hard-wire knowledge that the default ACL for a column grants no
3214 * privileges, so that we can fall out quickly in the very common case
3215 * where attacl is null.
3216 */
3217 if (isNull)
3218 {
3219 ReleaseSysCache(attTuple);
3220 return 0;
3221 }
3222
3223 /*
3224 * Must get the relation's ownerId from pg_class. Since we already found
3225 * a pg_attribute entry, the only likely reason for this to fail is that a
3226 * concurrent DROP of the relation committed since then (which could only
3227 * happen if we don't have lock on the relation). Treat that similarly to
3228 * not finding the attribute entry.
3229 */
3230 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3231 if (!HeapTupleIsValid(classTuple))
3232 {
3233 ReleaseSysCache(attTuple);
3234 if (is_missing != NULL)
3235 {
3236 /* return "no privileges" instead of throwing an error */
3237 *is_missing = true;
3238 return 0;
3239 }
3240 else
3241 ereport(ERROR,
3243 errmsg("relation with OID %u does not exist",
3244 table_oid)));
3245 }
3246 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3247
3248 ownerId = classForm->relowner;
3249
3250 ReleaseSysCache(classTuple);
3251
3252 /* detoast column's ACL if necessary */
3253 acl = DatumGetAclP(aclDatum);
3254
3255 result = aclmask(acl, roleid, ownerId, mask, how);
3256
3257 /* if we have a detoasted copy, free it */
3258 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3259 pfree(acl);
3260
3261 ReleaseSysCache(attTuple);
3262
3263 return result;
3264}
3265
3266/*
3267 * Exported routine for examining a user's privileges for a table
3268 */
3269AclMode
3270pg_class_aclmask(Oid table_oid, Oid roleid,
3271 AclMode mask, AclMaskHow how)
3272{
3273 return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3274}
3275
3276/*
3277 * Routine for examining a user's privileges for a table, with is_missing
3278 */
3279static AclMode
3280pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
3281 AclMaskHow how, bool *is_missing)
3282{
3283 AclMode result;
3284 HeapTuple tuple;
3285 Form_pg_class classForm;
3286 Datum aclDatum;
3287 bool isNull;
3288 Acl *acl;
3289 Oid ownerId;
3290
3291 /*
3292 * Must get the relation's tuple from pg_class
3293 */
3294 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3295 if (!HeapTupleIsValid(tuple))
3296 {
3297 if (is_missing != NULL)
3298 {
3299 /* return "no privileges" instead of throwing an error */
3300 *is_missing = true;
3301 return 0;
3302 }
3303 else
3304 ereport(ERROR,
3306 errmsg("relation with OID %u does not exist",
3307 table_oid)));
3308 }
3309
3310 classForm = (Form_pg_class) GETSTRUCT(tuple);
3311
3312 /*
3313 * Deny anyone permission to update a system catalog unless
3314 * pg_authid.rolsuper is set.
3315 *
3316 * As of 7.4 we have some updatable system views; those shouldn't be
3317 * protected in this way. Assume the view rules can take care of
3318 * themselves. ACL_USAGE is if we ever have system sequences.
3319 */
3320 if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3321 IsSystemClass(table_oid, classForm) &&
3322 classForm->relkind != RELKIND_VIEW &&
3323 !superuser_arg(roleid))
3325
3326 /*
3327 * Otherwise, superusers bypass all permission-checking.
3328 */
3329 if (superuser_arg(roleid))
3330 {
3331 ReleaseSysCache(tuple);
3332 return mask;
3333 }
3334
3335 /*
3336 * Normal case: get the relation's ACL from pg_class
3337 */
3338 ownerId = classForm->relowner;
3339
3340 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3341 &isNull);
3342 if (isNull)
3343 {
3344 /* No ACL, so build default ACL */
3345 switch (classForm->relkind)
3346 {
3347 case RELKIND_SEQUENCE:
3348 acl = acldefault(OBJECT_SEQUENCE, ownerId);
3349 break;
3350 default:
3351 acl = acldefault(OBJECT_TABLE, ownerId);
3352 break;
3353 }
3354 aclDatum = (Datum) 0;
3355 }
3356 else
3357 {
3358 /* detoast rel's ACL if necessary */
3359 acl = DatumGetAclP(aclDatum);
3360 }
3361
3362 result = aclmask(acl, roleid, ownerId, mask, how);
3363
3364 /* if we have a detoasted copy, free it */
3365 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3366 pfree(acl);
3367
3368 ReleaseSysCache(tuple);
3369
3370 /*
3371 * Check if ACL_SELECT is being checked and, if so, and not set already as
3372 * part of the result, then check if the user is a member of the
3373 * pg_read_all_data role, which allows read access to all relations.
3374 */
3375 if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
3376 has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
3377 result |= ACL_SELECT;
3378
3379 /*
3380 * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3381 * so, and not set already as part of the result, then check if the user
3382 * is a member of the pg_write_all_data role, which allows
3383 * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3384 * which requires superuser, see above).
3385 */
3386 if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
3387 !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
3388 has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
3389 result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
3390
3391 /*
3392 * Check if ACL_MAINTAIN is being checked and, if so, and not already set
3393 * as part of the result, then check if the user is a member of the
3394 * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
3395 * MATERIALIZED VIEW, REINDEX, and LOCK TABLE on all relations.
3396 */
3397 if (mask & ACL_MAINTAIN &&
3398 !(result & ACL_MAINTAIN) &&
3399 has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
3400 result |= ACL_MAINTAIN;
3401
3402 return result;
3403}
3404
3405/*
3406 * Routine for examining a user's privileges for a configuration
3407 * parameter (GUC), identified by GUC name.
3408 */
3409static AclMode
3410pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
3411{
3412 AclMode result;
3413 char *parname;
3414 text *partext;
3415 HeapTuple tuple;
3416
3417 /* Superusers bypass all permission checking. */
3418 if (superuser_arg(roleid))
3419 return mask;
3420
3421 /* Convert name to the form it should have in pg_parameter_acl... */
3423 partext = cstring_to_text(parname);
3424
3425 /* ... and look it up */
3426 tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3427
3428 if (!HeapTupleIsValid(tuple))
3429 {
3430 /* If no entry, GUC has no permissions for non-superusers */
3431 result = ACL_NO_RIGHTS;
3432 }
3433 else
3434 {
3435 Datum aclDatum;
3436 bool isNull;
3437 Acl *acl;
3438
3439 aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3440 Anum_pg_parameter_acl_paracl,
3441 &isNull);
3442 if (isNull)
3443 {
3444 /* No ACL, so build default ACL */
3445 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3446 aclDatum = (Datum) 0;
3447 }
3448 else
3449 {
3450 /* detoast ACL if necessary */
3451 acl = DatumGetAclP(aclDatum);
3452 }
3453
3454 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3455
3456 /* if we have a detoasted copy, free it */
3457 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3458 pfree(acl);
3459
3460 ReleaseSysCache(tuple);
3461 }
3462
3463 pfree(parname);
3464 pfree(partext);
3465
3466 return result;
3467}
3468
3469/*
3470 * Routine for examining a user's privileges for a configuration
3471 * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
3472 */
3473static AclMode
3475{
3476 AclMode result;
3477 HeapTuple tuple;
3478 Datum aclDatum;
3479 bool isNull;
3480 Acl *acl;
3481
3482 /* Superusers bypass all permission checking. */
3483 if (superuser_arg(roleid))
3484 return mask;
3485
3486 /* Get the ACL from pg_parameter_acl */
3487 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3488 if (!HeapTupleIsValid(tuple))
3489 ereport(ERROR,
3490 (errcode(ERRCODE_UNDEFINED_OBJECT),
3491 errmsg("parameter ACL with OID %u does not exist",
3492 acl_oid)));
3493
3494 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3495 Anum_pg_parameter_acl_paracl,
3496 &isNull);
3497 if (isNull)
3498 {
3499 /* No ACL, so build default ACL */
3500 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3501 aclDatum = (Datum) 0;
3502 }
3503 else
3504 {
3505 /* detoast ACL if necessary */
3506 acl = DatumGetAclP(aclDatum);
3507 }
3508
3509 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3510
3511 /* if we have a detoasted copy, free it */
3512 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3513 pfree(acl);
3514
3515 ReleaseSysCache(tuple);
3516
3517 return result;
3518}
3519
3520/*
3521 * Routine for examining a user's privileges for a largeobject
3522 *
3523 * When a large object is opened for reading, it is opened relative to the
3524 * caller's snapshot, but when it is opened for writing, a current
3525 * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
3526 * takes a snapshot argument so that the permissions check can be made
3527 * relative to the same snapshot that will be used to read the underlying
3528 * data. The caller will actually pass NULL for an instantaneous MVCC
3529 * snapshot, since all we do with the snapshot argument is pass it through
3530 * to systable_beginscan().
3531 */
3532static AclMode
3534 AclMode mask, AclMaskHow how,
3535 Snapshot snapshot)
3536{
3537 AclMode result;
3538 Relation pg_lo_meta;
3539 ScanKeyData entry[1];
3540 SysScanDesc scan;
3541 HeapTuple tuple;
3542 Datum aclDatum;
3543 bool isNull;
3544 Acl *acl;
3545 Oid ownerId;
3546
3547 /* Superusers bypass all permission checking. */
3548 if (superuser_arg(roleid))
3549 return mask;
3550
3551 /*
3552 * Get the largeobject's ACL from pg_largeobject_metadata
3553 */
3554 pg_lo_meta = table_open(LargeObjectMetadataRelationId,
3556
3557 ScanKeyInit(&entry[0],
3558 Anum_pg_largeobject_metadata_oid,
3559 BTEqualStrategyNumber, F_OIDEQ,
3560 ObjectIdGetDatum(lobj_oid));
3561
3562 scan = systable_beginscan(pg_lo_meta,
3563 LargeObjectMetadataOidIndexId, true,
3564 snapshot, 1, entry);
3565
3566 tuple = systable_getnext(scan);
3567 if (!HeapTupleIsValid(tuple))
3568 ereport(ERROR,
3569 (errcode(ERRCODE_UNDEFINED_OBJECT),
3570 errmsg("large object %u does not exist", lobj_oid)));
3571
3572 ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
3573
3574 aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
3575 RelationGetDescr(pg_lo_meta), &isNull);
3576
3577 if (isNull)
3578 {
3579 /* No ACL, so build default ACL */
3580 acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
3581 aclDatum = (Datum) 0;
3582 }
3583 else
3584 {
3585 /* detoast ACL if necessary */
3586 acl = DatumGetAclP(aclDatum);
3587 }
3588
3589 result = aclmask(acl, roleid, ownerId, mask, how);
3590
3591 /* if we have a detoasted copy, free it */
3592 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3593 pfree(acl);
3594
3595 systable_endscan(scan);
3596
3597 table_close(pg_lo_meta, AccessShareLock);
3598
3599 return result;
3600}
3601
3602/*
3603 * Routine for examining a user's privileges for a namespace, with is_missing
3604 */
3605static AclMode
3607 AclMode mask, AclMaskHow how,
3608 bool *is_missing)
3609{
3610 AclMode result;
3611 HeapTuple tuple;
3612 Datum aclDatum;
3613 bool isNull;
3614 Acl *acl;
3615 Oid ownerId;
3616
3617 /* Superusers bypass all permission checking. */
3618 if (superuser_arg(roleid))
3619 return mask;
3620
3621 /*
3622 * If we have been assigned this namespace as a temp namespace, check to
3623 * make sure we have CREATE TEMP permission on the database, and if so act
3624 * as though we have all standard (but not GRANT OPTION) permissions on
3625 * the namespace. If we don't have CREATE TEMP, act as though we have
3626 * only USAGE (and not CREATE) rights.
3627 *
3628 * This may seem redundant given the check in InitTempTableNamespace, but
3629 * it really isn't since current user ID may have changed since then. The
3630 * upshot of this behavior is that a SECURITY DEFINER function can create
3631 * temp tables that can then be accessed (if permission is granted) by
3632 * code in the same session that doesn't have permissions to create temp
3633 * tables.
3634 *
3635 * XXX Would it be safe to ereport a special error message as
3636 * InitTempTableNamespace does? Returning zero here means we'll get a
3637 * generic "permission denied for schema pg_temp_N" message, which is not
3638 * remarkably user-friendly.
3639 */
3640 if (isTempNamespace(nsp_oid))
3641 {
3642 if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
3643 ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
3644 return mask & ACL_ALL_RIGHTS_SCHEMA;
3645 else
3646 return mask & ACL_USAGE;
3647 }
3648
3649 /*
3650 * Get the schema's ACL from pg_namespace
3651 */
3652 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
3653 if (!HeapTupleIsValid(tuple))
3654 {
3655 if (is_missing != NULL)
3656 {
3657 /* return "no privileges" instead of throwing an error */
3658 *is_missing = true;
3659 return 0;
3660 }
3661 else
3662 ereport(ERROR,
3663 (errcode(ERRCODE_UNDEFINED_SCHEMA),
3664 errmsg("schema with OID %u does not exist", nsp_oid)));
3665 }
3666
3667 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3668
3669 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
3670 &isNull);
3671 if (isNull)
3672 {
3673 /* No ACL, so build default ACL */
3674 acl = acldefault(OBJECT_SCHEMA, ownerId);
3675 aclDatum = (Datum) 0;
3676 }
3677 else
3678 {
3679 /* detoast ACL if necessary */
3680 acl = DatumGetAclP(aclDatum);
3681 }
3682
3683 result = aclmask(acl, roleid, ownerId, mask, how);
3684
3685 /* if we have a detoasted copy, free it */
3686 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3687 pfree(acl);
3688
3689 ReleaseSysCache(tuple);
3690
3691 /*
3692 * Check if ACL_USAGE is being checked and, if so, and not set already as
3693 * part of the result, then check if the user is a member of the
3694 * pg_read_all_data or pg_write_all_data roles, which allow usage access
3695 * to all schemas.
3696 */
3697 if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
3698 (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
3699 has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
3700 result |= ACL_USAGE;
3701 return result;
3702}
3703
3704/*
3705 * Routine for examining a user's privileges for a type, with is_missing
3706 */
3707static AclMode
3708pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
3709 bool *is_missing)
3710{
3711 AclMode result;
3712 HeapTuple tuple;
3713 Form_pg_type typeForm;
3714 Datum aclDatum;
3715 bool isNull;
3716 Acl *acl;
3717 Oid ownerId;
3718
3719 /* Bypass permission checks for superusers */
3720 if (superuser_arg(roleid))
3721 return mask;
3722
3723 /*
3724 * Must get the type's tuple from pg_type
3725 */
3726 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3727 if (!HeapTupleIsValid(tuple))
3728 {
3729 if (is_missing != NULL)
3730 {
3731 /* return "no privileges" instead of throwing an error */
3732 *is_missing = true;
3733 return 0;
3734 }
3735 else
3736 ereport(ERROR,
3737 (errcode(ERRCODE_UNDEFINED_OBJECT),
3738 errmsg("type with OID %u does not exist",
3739 type_oid)));
3740 }
3741 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3742
3743 /*
3744 * "True" array types don't manage permissions of their own; consult the
3745 * element type instead.
3746 */
3747 if (IsTrueArrayType(typeForm))
3748 {
3749 Oid elttype_oid = typeForm->typelem;
3750
3751 ReleaseSysCache(tuple);
3752
3753 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3754 if (!HeapTupleIsValid(tuple))
3755 {
3756 if (is_missing != NULL)
3757 {
3758 /* return "no privileges" instead of throwing an error */
3759 *is_missing = true;
3760 return 0;
3761 }
3762 else
3763 ereport(ERROR,
3764 (errcode(ERRCODE_UNDEFINED_OBJECT),
3765 errmsg("type with OID %u does not exist",
3766 elttype_oid)));
3767 }
3768 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3769 }
3770
3771 /*
3772 * Likewise, multirange types don't manage their own permissions; consult
3773 * the associated range type. (Note we must do this after the array step
3774 * to get the right answer for arrays of multiranges.)
3775 */
3776 if (typeForm->typtype == TYPTYPE_MULTIRANGE)
3777 {
3778 Oid rangetype = get_multirange_range(typeForm->oid);
3779
3780 ReleaseSysCache(tuple);
3781
3782 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
3783 if (!HeapTupleIsValid(tuple))
3784 {
3785 if (is_missing != NULL)
3786 {
3787 /* return "no privileges" instead of throwing an error */
3788 *is_missing = true;
3789 return 0;
3790 }
3791 else
3792 ereport(ERROR,
3793 (errcode(ERRCODE_UNDEFINED_OBJECT),
3794 errmsg("type with OID %u does not exist",
3795 rangetype)));
3796 }
3797 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3798 }
3799
3800 /*
3801 * Now get the type's owner and ACL from the tuple
3802 */
3803 ownerId = typeForm->typowner;
3804
3805 aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3806 Anum_pg_type_typacl, &isNull);
3807 if (isNull)
3808 {
3809 /* No ACL, so build default ACL */
3810 acl = acldefault(OBJECT_TYPE, ownerId);
3811 aclDatum = (Datum) 0;
3812 }
3813 else
3814 {
3815 /* detoast rel's ACL if necessary */
3816 acl = DatumGetAclP(aclDatum);
3817 }
3818
3819 result = aclmask(acl, roleid, ownerId, mask, how);
3820
3821 /* if we have a detoasted copy, free it */
3822 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3823 pfree(acl);
3824
3825 ReleaseSysCache(tuple);
3826
3827 return result;
3828}
3829
3830/*
3831 * Exported generic routine for checking a user's access privileges to an object
3832 */
3834object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
3835{
3836 return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3837}
3838
3839/*
3840 * Exported generic routine for checking a user's access privileges to an
3841 * object, with is_missing
3842 */
3844object_aclcheck_ext(Oid classid, Oid objectid,
3845 Oid roleid, AclMode mode,
3846 bool *is_missing)
3847{
3848 if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
3849 is_missing) != 0)
3850 return ACLCHECK_OK;
3851 else
3852 return ACLCHECK_NO_PRIV;
3853}
3854
3855/*
3856 * Exported routine for checking a user's access privileges to a column
3857 *
3858 * Returns ACLCHECK_OK if the user has any of the privileges identified by
3859 * 'mode'; otherwise returns a suitable error code (in practice, always
3860 * ACLCHECK_NO_PRIV).
3861 *
3862 * As with pg_attribute_aclmask, only privileges granted directly on the
3863 * column are considered here.
3864 */
3867 Oid roleid, AclMode mode)
3868{
3869 return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3870}
3871
3872
3873/*
3874 * Exported routine for checking a user's access privileges to a column,
3875 * with is_missing
3876 */
3879 Oid roleid, AclMode mode, bool *is_missing)
3880{
3881 if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3882 ACLMASK_ANY, is_missing) != 0)
3883 return ACLCHECK_OK;
3884 else
3885 return ACLCHECK_NO_PRIV;
3886}
3887
3888/*
3889 * Exported routine for checking a user's access privileges to any/all columns
3890 *
3891 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
3892 * privileges identified by 'mode' on any non-dropped column in the relation;
3893 * otherwise returns a suitable error code (in practice, always
3894 * ACLCHECK_NO_PRIV).
3895 *
3896 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
3897 * privileges identified by 'mode' on each non-dropped column in the relation
3898 * (and there must be at least one such column); otherwise returns a suitable
3899 * error code (in practice, always ACLCHECK_NO_PRIV).
3900 *
3901 * As with pg_attribute_aclmask, only privileges granted directly on the
3902 * column(s) are considered here.
3903 *
3904 * Note: system columns are not considered here; there are cases where that
3905 * might be appropriate but there are also cases where it wouldn't.
3906 */
3909 AclMaskHow how)
3910{
3911 return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3912}
3913
3914/*
3915 * Exported routine for checking a user's access privileges to any/all columns,
3916 * with is_missing
3917 */
3920 AclMode mode, AclMaskHow how,
3921 bool *is_missing)
3922{
3923 AclResult result;
3924 HeapTuple classTuple;
3925 Form_pg_class classForm;
3926 Oid ownerId;
3927 AttrNumber nattrs;
3928 AttrNumber curr_att;
3929
3930 /*
3931 * Must fetch pg_class row to get owner ID and number of attributes.
3932 */
3933 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3934 if (!HeapTupleIsValid(classTuple))
3935 {
3936 if (is_missing != NULL)
3937 {
3938 /* return "no privileges" instead of throwing an error */
3939 *is_missing = true;
3940 return ACLCHECK_NO_PRIV;
3941 }
3942 else
3943 ereport(ERROR,
3945 errmsg("relation with OID %u does not exist",
3946 table_oid)));
3947 }
3948 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3949
3950 ownerId = classForm->relowner;
3951 nattrs = classForm->relnatts;
3952
3953 ReleaseSysCache(classTuple);
3954
3955 /*
3956 * Initialize result in case there are no non-dropped columns. We want to
3957 * report failure in such cases for either value of 'how'.
3958 */
3959 result = ACLCHECK_NO_PRIV;
3960
3961 for (curr_att = 1; curr_att <= nattrs; curr_att++)
3962 {
3963 HeapTuple attTuple;
3964 Datum aclDatum;
3965 bool isNull;
3966 Acl *acl;
3967 AclMode attmask;
3968
3969 attTuple = SearchSysCache2(ATTNUM,
3970 ObjectIdGetDatum(table_oid),
3971 Int16GetDatum(curr_att));
3972
3973 /*
3974 * Lookup failure probably indicates that the table was just dropped,
3975 * but we'll treat it the same as a dropped column rather than
3976 * throwing error.
3977 */
3978 if (!HeapTupleIsValid(attTuple))
3979 continue;
3980
3981 /* ignore dropped columns */
3982 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
3983 {
3984 ReleaseSysCache(attTuple);
3985 continue;
3986 }
3987
3988 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3989 &isNull);
3990
3991 /*
3992 * Here we hard-wire knowledge that the default ACL for a column
3993 * grants no privileges, so that we can fall out quickly in the very
3994 * common case where attacl is null.
3995 */
3996 if (isNull)
3997 attmask = 0;
3998 else
3999 {
4000 /* detoast column's ACL if necessary */
4001 acl = DatumGetAclP(aclDatum);
4002
4003 attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
4004
4005 /* if we have a detoasted copy, free it */
4006 if ((Pointer) acl != DatumGetPointer(aclDatum))
4007 pfree(acl);
4008 }
4009
4010 ReleaseSysCache(attTuple);
4011
4012 if (attmask != 0)
4013 {
4014 result = ACLCHECK_OK;
4015 if (how == ACLMASK_ANY)
4016 break; /* succeed on any success */
4017 }
4018 else
4019 {
4020 result = ACLCHECK_NO_PRIV;
4021 if (how == ACLMASK_ALL)
4022 break; /* fail on any failure */
4023 }
4024 }
4025
4026 return result;
4027}
4028
4029/*
4030 * Exported routine for checking a user's access privileges to a table
4031 *
4032 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4033 * 'mode'; otherwise returns a suitable error code (in practice, always
4034 * ACLCHECK_NO_PRIV).
4035 */
4038{
4039 return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
4040}
4041
4042/*
4043 * Exported routine for checking a user's access privileges to a table,
4044 * with is_missing
4045 */
4048 AclMode mode, bool *is_missing)
4049{
4050 if (pg_class_aclmask_ext(table_oid, roleid, mode,
4051 ACLMASK_ANY, is_missing) != 0)
4052 return ACLCHECK_OK;
4053 else
4054 return ACLCHECK_NO_PRIV;
4055}
4056
4057/*
4058 * Exported routine for checking a user's access privileges to a configuration
4059 * parameter (GUC), identified by GUC name.
4060 */
4063{
4064 if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4065 return ACLCHECK_OK;
4066 else
4067 return ACLCHECK_NO_PRIV;
4068}
4069
4070/*
4071 * Exported routine for checking a user's access privileges to a largeobject
4072 */
4075 Snapshot snapshot)
4076{
4077 if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4078 ACLMASK_ANY, snapshot) != 0)
4079 return ACLCHECK_OK;
4080 else
4081 return ACLCHECK_NO_PRIV;
4082}
4083
4084/*
4085 * Generic ownership check for an object
4086 */
4087bool
4088object_ownercheck(Oid classid, Oid objectid, Oid roleid)
4089{
4090 int cacheid;
4091 Oid ownerId;
4092
4093 /* Superusers bypass all permission checking. */
4094 if (superuser_arg(roleid))
4095 return true;
4096
4097 /* For large objects, the catalog to consult is pg_largeobject_metadata */
4098 if (classid == LargeObjectRelationId)
4099 classid = LargeObjectMetadataRelationId;
4100
4101 cacheid = get_object_catcache_oid(classid);
4102 if (cacheid != -1)
4103 {
4104 /* we can get the object's tuple from the syscache */
4105 HeapTuple tuple;
4106
4107 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4108 if (!HeapTupleIsValid(tuple))
4109 elog(ERROR, "cache lookup failed for %s %u",
4110 get_object_class_descr(classid), objectid);
4111
4112 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4113 tuple,
4114 get_object_attnum_owner(classid)));
4115 ReleaseSysCache(tuple);
4116 }
4117 else
4118 {
4119 /* for catalogs without an appropriate syscache */
4120 Relation rel;
4121 ScanKeyData entry[1];
4122 SysScanDesc scan;
4123 HeapTuple tuple;
4124 bool isnull;
4125
4126 rel = table_open(classid, AccessShareLock);
4127
4128 ScanKeyInit(&entry[0],
4129 get_object_attnum_oid(classid),
4130 BTEqualStrategyNumber, F_OIDEQ,
4131 ObjectIdGetDatum(objectid));
4132
4133 scan = systable_beginscan(rel,
4134 get_object_oid_index(classid), true,
4135 NULL, 1, entry);
4136
4137 tuple = systable_getnext(scan);
4138 if (!HeapTupleIsValid(tuple))
4139 elog(ERROR, "could not find tuple for %s %u",
4140 get_object_class_descr(classid), objectid);
4141
4142 ownerId = DatumGetObjectId(heap_getattr(tuple,
4143 get_object_attnum_owner(classid),
4144 RelationGetDescr(rel),
4145 &isnull));
4146 Assert(!isnull);
4147
4148 systable_endscan(scan);
4150 }
4151
4152 return has_privs_of_role(roleid, ownerId);
4153}
4154
4155/*
4156 * Check whether specified role has CREATEROLE privilege (or is a superuser)
4157 *
4158 * Note: roles do not have owners per se; instead we use this test in
4159 * places where an ownership-like permissions test is needed for a role.
4160 * Be sure to apply it to the role trying to do the operation, not the
4161 * role being operated on! Also note that this generally should not be
4162 * considered enough privilege if the target role is a superuser.
4163 * (We don't handle that consideration here because we want to give a
4164 * separate error message for such cases, so the caller has to deal with it.)
4165 */
4166bool
4168{
4169 bool result = false;
4170 HeapTuple utup;
4171
4172 /* Superusers bypass all permission checking. */
4173 if (superuser_arg(roleid))
4174 return true;
4175
4176 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4177 if (HeapTupleIsValid(utup))
4178 {
4179 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4180 ReleaseSysCache(utup);
4181 }
4182 return result;
4183}
4184
4185bool
4187{
4188 bool result = false;
4189 HeapTuple utup;
4190
4191 /* Superusers bypass all permission checking. */
4192 if (superuser_arg(roleid))
4193 return true;
4194
4195 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4196 if (HeapTupleIsValid(utup))
4197 {
4198 result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4199 ReleaseSysCache(utup);
4200 }
4201 return result;
4202}
4203
4204/*
4205 * Fetch pg_default_acl entry for given role, namespace and object type
4206 * (object type must be given in pg_default_acl's encoding).
4207 * Returns NULL if no such entry.
4208 */
4209static Acl *
4210get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
4211{
4212 Acl *result = NULL;
4213 HeapTuple tuple;
4214
4215 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4216 ObjectIdGetDatum(roleId),
4217 ObjectIdGetDatum(nsp_oid),
4218 CharGetDatum(objtype));
4219
4220 if (HeapTupleIsValid(tuple))
4221 {
4222 Datum aclDatum;
4223 bool isNull;
4224
4225 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4226 Anum_pg_default_acl_defaclacl,
4227 &isNull);
4228 if (!isNull)
4229 result = DatumGetAclPCopy(aclDatum);
4230 ReleaseSysCache(tuple);
4231 }
4232
4233 return result;
4234}
4235
4236/*
4237 * Get default permissions for newly created object within given schema
4238 *
4239 * Returns NULL if built-in system defaults should be used.
4240 *
4241 * If the result is not NULL, caller must call recordDependencyOnNewAcl
4242 * once the OID of the new object is known.
4243 */
4244Acl *
4245get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
4246{
4247 Acl *result;
4248 Acl *glob_acl;
4249 Acl *schema_acl;
4250 Acl *def_acl;
4251 char defaclobjtype;
4252
4253 /*
4254 * Use NULL during bootstrap, since pg_default_acl probably isn't there
4255 * yet.
4256 */
4258 return NULL;
4259
4260 /* Check if object type is supported in pg_default_acl */
4261 switch (objtype)
4262 {
4263 case OBJECT_TABLE:
4264 defaclobjtype = DEFACLOBJ_RELATION;
4265 break;
4266
4267 case OBJECT_SEQUENCE:
4268 defaclobjtype = DEFACLOBJ_SEQUENCE;
4269 break;
4270
4271 case OBJECT_FUNCTION:
4272 defaclobjtype = DEFACLOBJ_FUNCTION;
4273 break;
4274
4275 case OBJECT_TYPE:
4276 defaclobjtype = DEFACLOBJ_TYPE;
4277 break;
4278
4279 case OBJECT_SCHEMA:
4280 defaclobjtype = DEFACLOBJ_NAMESPACE;
4281 break;
4282
4283 case OBJECT_LARGEOBJECT:
4284 defaclobjtype = DEFACLOBJ_LARGEOBJECT;
4285 break;
4286
4287 default:
4288 return NULL;
4289 }
4290
4291 /* Look up the relevant pg_default_acl entries */
4292 glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4293 schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4294
4295 /* Quick out if neither entry exists */
4296 if (glob_acl == NULL && schema_acl == NULL)
4297 return NULL;
4298
4299 /* We need to know the hard-wired default value, too */
4300 def_acl = acldefault(objtype, ownerId);
4301
4302 /* If there's no global entry, substitute the hard-wired default */
4303 if (glob_acl == NULL)
4304 glob_acl = def_acl;
4305
4306 /* Merge in any per-schema privileges */
4307 result = aclmerge(glob_acl, schema_acl, ownerId);
4308
4309 /*
4310 * For efficiency, we want to return NULL if the result equals default.
4311 * This requires sorting both arrays to get an accurate comparison.
4312 */
4313 aclitemsort(result);
4314 aclitemsort(def_acl);
4315 if (aclequal(result, def_acl))
4316 result = NULL;
4317
4318 return result;
4319}
4320
4321/*
4322 * Record dependencies on roles mentioned in a new object's ACL.
4323 */
4324void
4325recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
4326 Oid ownerId, Acl *acl)
4327{
4328 int nmembers;
4329 Oid *members;
4330
4331 /* Nothing to do if ACL is defaulted */
4332 if (acl == NULL)
4333 return;
4334
4335 /* Extract roles mentioned in ACL */
4336 nmembers = aclmembers(acl, &members);
4337
4338 /* Update the shared dependency ACL info */
4339 updateAclDependencies(classId, objectId, objsubId,
4340 ownerId,
4341 0, NULL,
4342 nmembers, members);
4343}
4344
4345/*
4346 * Record initial privileges for the top-level object passed in.
4347 *
4348 * For the object passed in, this will record its ACL (if any) and the ACLs of
4349 * any sub-objects (eg: columns) into pg_init_privs.
4350 */
4351void
4353{
4354 /*
4355 * pg_class / pg_attribute
4356 *
4357 * If this is a relation then we need to see if there are any sub-objects
4358 * (eg: columns) for it and, if so, be sure to call
4359 * recordExtensionInitPrivWorker() for each one.
4360 */
4361 if (classoid == RelationRelationId)
4362 {
4363 Form_pg_class pg_class_tuple;
4364 Datum aclDatum;
4365 bool isNull;
4366 HeapTuple tuple;
4367
4368 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4369 if (!HeapTupleIsValid(tuple))
4370 elog(ERROR, "cache lookup failed for relation %u", objoid);
4371 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4372
4373 /*
4374 * Indexes don't have permissions, neither do the pg_class rows for
4375 * composite types. (These cases are unreachable given the
4376 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4377 */
4378 if (pg_class_tuple->relkind == RELKIND_INDEX ||
4379 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4380 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4381 {
4382 ReleaseSysCache(tuple);
4383 return;
4384 }
4385
4386 /*
4387 * If this isn't a sequence then it's possibly going to have
4388 * column-level ACLs associated with it.
4389 */
4390 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4391 {
4392 AttrNumber curr_att;
4393 AttrNumber nattrs = pg_class_tuple->relnatts;
4394
4395 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4396 {
4397 HeapTuple attTuple;
4398 Datum attaclDatum;
4399
4400 attTuple = SearchSysCache2(ATTNUM,
4401 ObjectIdGetDatum(objoid),
4402 Int16GetDatum(curr_att));
4403
4404 if (!HeapTupleIsValid(attTuple))
4405 continue;
4406
4407 /* ignore dropped columns */
4408 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4409 {
4410 ReleaseSysCache(attTuple);
4411 continue;
4412 }
4413
4414 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4415 Anum_pg_attribute_attacl,
4416 &isNull);
4417
4418 /* no need to do anything for a NULL ACL */
4419 if (isNull)
4420 {
4421 ReleaseSysCache(attTuple);
4422 continue;
4423 }
4424
4425 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4426 DatumGetAclP(attaclDatum));
4427
4428 ReleaseSysCache(attTuple);
4429 }
4430 }
4431
4432 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4433 &isNull);
4434
4435 /* Add the record, if any, for the top-level object */
4436 if (!isNull)
4437 recordExtensionInitPrivWorker(objoid, classoid, 0,
4438 DatumGetAclP(aclDatum));
4439
4440 ReleaseSysCache(tuple);
4441 }
4442 else if (classoid == LargeObjectRelationId)
4443 {
4444 /* For large objects, we must consult pg_largeobject_metadata */
4445 Datum aclDatum;
4446 bool isNull;
4447 HeapTuple tuple;
4448 ScanKeyData entry[1];
4449 SysScanDesc scan;
4450 Relation relation;
4451
4452 /*
4453 * Note: this is dead code, given that we don't allow large objects to
4454 * be made extension members. But it seems worth carrying in case
4455 * some future caller of this function has need for it.
4456 */
4457 relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4458
4459 /* There's no syscache for pg_largeobject_metadata */
4460 ScanKeyInit(&entry[0],
4461 Anum_pg_largeobject_metadata_oid,
4462 BTEqualStrategyNumber, F_OIDEQ,
4463 ObjectIdGetDatum(objoid));
4464
4465 scan = systable_beginscan(relation,
4466 LargeObjectMetadataOidIndexId, true,
4467 NULL, 1, entry);
4468
4469 tuple = systable_getnext(scan);
4470 if (!HeapTupleIsValid(tuple))
4471 elog(ERROR, "could not find tuple for large object %u", objoid);
4472
4473 aclDatum = heap_getattr(tuple,
4474 Anum_pg_largeobject_metadata_lomacl,
4475 RelationGetDescr(relation), &isNull);
4476
4477 /* Add the record, if any, for the top-level object */
4478 if (!isNull)
4479 recordExtensionInitPrivWorker(objoid, classoid, 0,
4480 DatumGetAclP(aclDatum));
4481
4482 systable_endscan(scan);
4483 }
4484 /* This will error on unsupported classoid. */
4485 else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4486 {
4487 int cacheid;
4488 Datum aclDatum;
4489 bool isNull;
4490 HeapTuple tuple;
4491
4492 cacheid = get_object_catcache_oid(classoid);
4493 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
4494 if (!HeapTupleIsValid(tuple))
4495 elog(ERROR, "cache lookup failed for %s %u",
4496 get_object_class_descr(classoid), objoid);
4497
4498 aclDatum = SysCacheGetAttr(cacheid, tuple,
4499 get_object_attnum_acl(classoid),
4500 &isNull);
4501
4502 /* Add the record, if any, for the top-level object */
4503 if (!isNull)
4504 recordExtensionInitPrivWorker(objoid, classoid, 0,
4505 DatumGetAclP(aclDatum));
4506
4507 ReleaseSysCache(tuple);
4508 }
4509}
4510
4511/*
4512 * For the object passed in, remove its ACL and the ACLs of any object subIds
4513 * from pg_init_privs (via recordExtensionInitPrivWorker()).
4514 */
4515void
4517{
4518 /*
4519 * If this is a relation then we need to see if there are any sub-objects
4520 * (eg: columns) for it and, if so, be sure to call
4521 * recordExtensionInitPrivWorker() for each one.
4522 */
4523 if (classoid == RelationRelationId)
4524 {
4525 Form_pg_class pg_class_tuple;
4526 HeapTuple tuple;
4527
4528 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4529 if (!HeapTupleIsValid(tuple))
4530 elog(ERROR, "cache lookup failed for relation %u", objoid);
4531 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4532
4533 /*
4534 * Indexes don't have permissions, neither do the pg_class rows for
4535 * composite types. (These cases are unreachable given the
4536 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4537 */
4538 if (pg_class_tuple->relkind == RELKIND_INDEX ||
4539 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4540 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4541 {
4542 ReleaseSysCache(tuple);
4543 return;
4544 }
4545
4546 /*
4547 * If this isn't a sequence then it's possibly going to have
4548 * column-level ACLs associated with it.
4549 */
4550 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4551 {
4552 AttrNumber curr_att;
4553 AttrNumber nattrs = pg_class_tuple->relnatts;
4554
4555 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4556 {
4557 HeapTuple attTuple;
4558
4559 attTuple = SearchSysCache2(ATTNUM,
4560 ObjectIdGetDatum(objoid),
4561 Int16GetDatum(curr_att));
4562
4563 if (!HeapTupleIsValid(attTuple))
4564 continue;
4565
4566 /* when removing, remove all entries, even dropped columns */
4567
4568 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4569
4570 ReleaseSysCache(attTuple);
4571 }
4572 }
4573
4574 ReleaseSysCache(tuple);
4575 }
4576
4577 /* Remove the record, if any, for the top-level object */
4578 recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
4579}
4580
4581/*
4582 * Record initial ACL for an extension object
4583 *
4584 * Can be called at any time, we check if 'creating_extension' is set and, if
4585 * not, exit immediately.
4586 *
4587 * Pass in the object OID, the OID of the class (the OID of the table which
4588 * the object is defined in) and the 'sub' id of the object (objsubid), if
4589 * any. If there is no 'sub' id (they are currently only used for columns of
4590 * tables) then pass in '0'. Finally, pass in the complete ACL to store.
4591 *
4592 * If an ACL already exists for this object/sub-object then we will replace
4593 * it with what is passed in.
4594 *
4595 * Passing in NULL for 'new_acl' will result in the entry for the object being
4596 * removed, if one is found.
4597 */
4598static void
4599recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
4600{
4601 /*
4602 * Generally, we only record the initial privileges when an extension is
4603 * being created, but because we don't actually use CREATE EXTENSION
4604 * during binary upgrades with pg_upgrade, there is a variable to let us
4605 * know that the GRANT and REVOKE statements being issued, while this
4606 * variable is true, are for the initial privileges of the extension
4607 * object and therefore we need to record them.
4608 */
4610 return;
4611
4612 recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4613}
4614
4615/*
4616 * Record initial ACL for an extension object, worker.
4617 *
4618 * This will perform a wholesale replacement of the entire ACL for the object
4619 * passed in, therefore be sure to pass in the complete new ACL to use.
4620 *
4621 * Generally speaking, do *not* use this function directly but instead use
4622 * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
4623 * This function does *not* check if 'creating_extension' is set as it is also
4624 * used when an object is added to or removed from an extension via ALTER
4625 * EXTENSION ... ADD/DROP.
4626 */
4627static void
4628recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
4629 Acl *new_acl)
4630{
4631 Relation relation;
4632 ScanKeyData key[3];
4633 SysScanDesc scan;
4634 HeapTuple tuple;
4635 HeapTuple oldtuple;
4636 int noldmembers;
4637 int nnewmembers;
4638 Oid *oldmembers;
4639 Oid *newmembers;
4640
4641 /* We'll need the role membership of the new ACL. */
4642 nnewmembers = aclmembers(new_acl, &newmembers);
4643
4644 /* Search pg_init_privs for an existing entry. */
4645 relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4646
4647 ScanKeyInit(&key[0],
4648 Anum_pg_init_privs_objoid,
4649 BTEqualStrategyNumber, F_OIDEQ,
4650 ObjectIdGetDatum(objoid));
4651 ScanKeyInit(&key[1],
4652 Anum_pg_init_privs_classoid,
4653 BTEqualStrategyNumber, F_OIDEQ,
4654 ObjectIdGetDatum(classoid));
4655 ScanKeyInit(&key[2],
4656 Anum_pg_init_privs_objsubid,
4657 BTEqualStrategyNumber, F_INT4EQ,
4658 Int32GetDatum(objsubid));
4659
4660 scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4661 NULL, 3, key);
4662
4663 /* There should exist only one entry or none. */
4664 oldtuple = systable_getnext(scan);
4665
4666 /* If we find an entry, update it with the latest ACL. */
4667 if (HeapTupleIsValid(oldtuple))
4668 {
4669 Datum values[Natts_pg_init_privs] = {0};
4670 bool nulls[Natts_pg_init_privs] = {0};
4671 bool replace[Natts_pg_init_privs] = {0};
4672 Datum oldAclDatum;
4673 bool isNull;
4674 Acl *old_acl;
4675
4676 /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
4677 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4678 RelationGetDescr(relation), &isNull);
4679 Assert(!isNull);
4680 old_acl = DatumGetAclP(oldAclDatum);
4681 noldmembers = aclmembers(old_acl, &oldmembers);
4682
4683 updateInitAclDependencies(classoid, objoid, objsubid,
4684 noldmembers, oldmembers,
4685 nnewmembers, newmembers);
4686
4687 /* If we have a new ACL to set, then update the row with it. */
4688 if (new_acl && ACL_NUM(new_acl) != 0)
4689 {
4690 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4691 replace[Anum_pg_init_privs_initprivs - 1] = true;
4692
4693 oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4694 values, nulls, replace);
4695
4696 CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4697 }
4698 else
4699 {
4700 /* new_acl is NULL/empty, so delete the entry we found. */
4701 CatalogTupleDelete(relation, &oldtuple->t_self);
4702 }
4703 }
4704 else
4705 {
4706 Datum values[Natts_pg_init_privs] = {0};
4707 bool nulls[Natts_pg_init_privs] = {0};
4708
4709 /*
4710 * Only add a new entry if the new ACL is non-NULL.
4711 *
4712 * If we are passed in a NULL ACL and no entry exists, we can just
4713 * fall through and do nothing.
4714 */
4715 if (new_acl && ACL_NUM(new_acl) != 0)
4716 {
4717 /* No entry found, so add it. */
4718 values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4719 values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4720 values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4721
4722 /* This function only handles initial privileges of extensions */
4723 values[Anum_pg_init_privs_privtype - 1] =
4725
4726 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4727
4728 tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4729
4730 CatalogTupleInsert(relation, tuple);
4731
4732 /* Update pg_shdepend, too. */
4733 noldmembers = 0;
4734 oldmembers = NULL;
4735
4736 updateInitAclDependencies(classoid, objoid, objsubid,
4737 noldmembers, oldmembers,
4738 nnewmembers, newmembers);
4739 }
4740 }
4741
4742 systable_endscan(scan);
4743
4744 /* prevent error when processing objects multiple times */
4746
4747 table_close(relation, RowExclusiveLock);
4748}
4749
4750/*
4751 * ReplaceRoleInInitPriv
4752 *
4753 * Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
4754 */
4755void
4756ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
4757 Oid classid, Oid objid, int32 objsubid)
4758{
4759 Relation rel;
4760 ScanKeyData key[3];
4761 SysScanDesc scan;
4762 HeapTuple oldtuple;
4763 Datum oldAclDatum;
4764 bool isNull;
4765 Acl *old_acl;
4766 Acl *new_acl;
4767 HeapTuple newtuple;
4768 int noldmembers;
4769 int nnewmembers;
4770 Oid *oldmembers;
4771 Oid *newmembers;
4772
4773 /* Search for existing pg_init_privs entry for the target object. */
4774 rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4775
4776 ScanKeyInit(&key[0],
4777 Anum_pg_init_privs_objoid,
4778 BTEqualStrategyNumber, F_OIDEQ,
4779 ObjectIdGetDatum(objid));
4780 ScanKeyInit(&key[1],
4781 Anum_pg_init_privs_classoid,
4782 BTEqualStrategyNumber, F_OIDEQ,
4783 ObjectIdGetDatum(classid));
4784 ScanKeyInit(&key[2],
4785 Anum_pg_init_privs_objsubid,
4786 BTEqualStrategyNumber, F_INT4EQ,
4787 Int32GetDatum(objsubid));
4788
4789 scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4790 NULL, 3, key);
4791
4792 /* There should exist only one entry or none. */
4793 oldtuple = systable_getnext(scan);
4794
4795 if (!HeapTupleIsValid(oldtuple))
4796 {
4797 /*
4798 * Hmm, why are we here if there's no entry? But pack up and go away
4799 * quietly.
4800 */
4801 systable_endscan(scan);
4803 return;
4804 }
4805
4806 /* Get a writable copy of the existing ACL. */
4807 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4808 RelationGetDescr(rel), &isNull);
4809 Assert(!isNull);
4810 old_acl = DatumGetAclPCopy(oldAclDatum);
4811
4812 /*
4813 * Generate new ACL. This usage of aclnewowner is a bit off-label when
4814 * oldroleid isn't the owner; but it does the job fine.
4815 */
4816 new_acl = aclnewowner(old_acl, oldroleid, newroleid);
4817
4818 /*
4819 * If we end with an empty ACL, delete the pg_init_privs entry. (That
4820 * probably can't happen here, but we may as well cover the case.)
4821 */
4822 if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4823 {
4824 CatalogTupleDelete(rel, &oldtuple->t_self);
4825 }
4826 else
4827 {
4828 Datum values[Natts_pg_init_privs] = {0};
4829 bool nulls[Natts_pg_init_privs] = {0};
4830 bool replaces[Natts_pg_init_privs] = {0};
4831
4832 /* Update existing entry. */
4833 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4834 replaces[Anum_pg_init_privs_initprivs - 1] = true;
4835
4836 newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4837 values, nulls, replaces);
4838 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4839 }
4840
4841 /*
4842 * Update the shared dependency ACL info.
4843 */
4844 noldmembers = aclmembers(old_acl, &oldmembers);
4845 nnewmembers = aclmembers(new_acl, &newmembers);
4846
4847 updateInitAclDependencies(classid, objid, objsubid,
4848 noldmembers, oldmembers,
4849 nnewmembers, newmembers);
4850
4851 systable_endscan(scan);
4852
4853 /* prevent error when processing objects multiple times */
4855
4857}
4858
4859/*
4860 * RemoveRoleFromInitPriv
4861 *
4862 * Used by shdepDropOwned to remove mentions of a role in pg_init_privs.
4863 */
4864void
4865RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
4866{
4867 Relation rel;
4868 ScanKeyData key[3];
4869 SysScanDesc scan;
4870 HeapTuple oldtuple;
4871 int cacheid;
4872 HeapTuple objtuple;
4873 Oid ownerId;
4874 Datum oldAclDatum;
4875 bool isNull;
4876 Acl *old_acl;
4877 Acl *new_acl;
4878 HeapTuple newtuple;
4879 int noldmembers;
4880 int nnewmembers;
4881 Oid *oldmembers;
4882 Oid *newmembers;
4883
4884 /* Search for existing pg_init_privs entry for the target object. */
4885 rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4886
4887 ScanKeyInit(&key[0],
4888 Anum_pg_init_privs_objoid,
4889 BTEqualStrategyNumber, F_OIDEQ,
4890 ObjectIdGetDatum(objid));
4891 ScanKeyInit(&key[1],
4892 Anum_pg_init_privs_classoid,
4893 BTEqualStrategyNumber, F_OIDEQ,
4894 ObjectIdGetDatum(classid));
4895 ScanKeyInit(&key[2],
4896 Anum_pg_init_privs_objsubid,
4897 BTEqualStrategyNumber, F_INT4EQ,
4898 Int32GetDatum(objsubid));
4899
4900 scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4901 NULL, 3, key);
4902
4903 /* There should exist only one entry or none. */
4904 oldtuple = systable_getnext(scan);
4905
4906 if (!HeapTupleIsValid(oldtuple))
4907 {
4908 /*
4909 * Hmm, why are we here if there's no entry? But pack up and go away
4910 * quietly.
4911 */
4912 systable_endscan(scan);
4914 return;
4915 }
4916
4917 /* Get a writable copy of the existing ACL. */
4918 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4919 RelationGetDescr(rel), &isNull);
4920 Assert(!isNull);
4921 old_acl = DatumGetAclPCopy(oldAclDatum);
4922
4923 /*
4924 * We need the members of both old and new ACLs so we can correct the
4925 * shared dependency information. Collect data before
4926 * merge_acl_with_grant throws away old_acl.
4927 */
4928 noldmembers = aclmembers(old_acl, &oldmembers);
4929
4930 /* Must find out the owner's OID the hard way. */
4931 cacheid = get_object_catcache_oid(classid);
4932 objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
4933 if (!HeapTupleIsValid(objtuple))
4934 elog(ERROR, "cache lookup failed for %s %u",
4935 get_object_class_descr(classid), objid);
4936
4937 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4938 objtuple,
4939 get_object_attnum_owner(classid)));
4940 ReleaseSysCache(objtuple);
4941
4942 /*
4943 * Generate new ACL. Grantor of rights is always the same as the owner.
4944 */
4945 if (old_acl != NULL)
4946 new_acl = merge_acl_with_grant(old_acl,
4947 false, /* is_grant */
4948 false, /* grant_option */
4950 list_make1_oid(roleid),
4952 ownerId,
4953 ownerId);
4954 else
4955 new_acl = NULL; /* this case shouldn't happen, probably */
4956
4957 /* If we end with an empty ACL, delete the pg_init_privs entry. */
4958 if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4959 {
4960 CatalogTupleDelete(rel, &oldtuple->t_self);
4961 }
4962 else
4963 {
4964 Datum values[Natts_pg_init_privs] = {0};
4965 bool nulls[Natts_pg_init_privs] = {0};
4966 bool replaces[Natts_pg_init_privs] = {0};
4967
4968 /* Update existing entry. */
4969 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4970 replaces[Anum_pg_init_privs_initprivs - 1] = true;
4971
4972 newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4973 values, nulls, replaces);
4974 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4975 }
4976
4977 /*
4978 * Update the shared dependency ACL info.
4979 */
4980 nnewmembers = aclmembers(new_acl, &newmembers);
4981
4982 updateInitAclDependencies(classid, objid, objsubid,
4983 noldmembers, oldmembers,
4984 nnewmembers, newmembers);
4985
4986 systable_endscan(scan);
4987
4988 /* prevent error when processing objects multiple times */
4990
4992}
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:3156
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3844
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:4074
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:1591
void RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4865
static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4599
static void expand_col_privileges(List *colnames, Oid table_oid, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
Definition: aclchk.c:1558
bool has_bypassrls_privilege(Oid roleid)
Definition: aclchk.c:4186
AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:4047
void aclcheck_error_col(AclResult aclerr, ObjectType objtype, const char *objectname, const char *colname)
Definition: aclchk.c:2941
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3919
void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, Acl *acl)
Definition: aclchk.c:4325
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:1637
static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2401
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:3533
static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3145
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:3410
AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
Definition: aclchk.c:3908
static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3474
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:4062
void ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4756
static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
Definition: aclchk.c:2113
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:4352
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:3280
static AclMode string_to_privilege(const char *privname)
Definition: aclchk.c:2564
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2652
static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3044
static void ExecGrant_Largeobject(InternalGrant *istmt)
Definition: aclchk.c:2265
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3866
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:3834
static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4628
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4088
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3878
static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3606
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:3270
static void ExecGrant_Parameter(InternalGrant *istmt)
Definition: aclchk.c:2421
static const char * privilege_to_string(AclMode privilege)
Definition: aclchk.c:2605
static Acl * get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
Definition: aclchk.c:4210
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2971
bool has_createrole_privilege(Oid roleid)
Definition: aclchk.c:4167
static void ExecGrant_Relation(InternalGrant *istmt)
Definition: aclchk.c:1782
static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3708
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:4245
void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
Definition: aclchk.c:1420
static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2249
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4037
static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:2983
static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3055
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:4516
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:752
#define gettext_noop(x)
Definition: c.h:1196
char * Pointer
Definition: c.h:530
int32_t int32
Definition: c.h:535
#define OidIsValid(objectId)
Definition: c.h:775
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:273
@ DEPENDENCY_AUTO
Definition: dependency.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:1207
int errhint(const char *fmt,...)
Definition: elog.c:1321
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#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:1375
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1346
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, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
void CatalogTupleDelete(Relation heapRel, ItemPointer 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:2095
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:951
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2926
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3650
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:476
Oid GetUserId(void)
Definition: miscinit.c:469
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3452
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3716
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3602
#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:422
#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:2394
@ DROP_CASCADE
Definition: parsenodes.h:2396
@ DROP_RESTRICT
Definition: parsenodes.h:2395
ObjectType
Definition: parsenodes.h:2321
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2336
@ OBJECT_FDW
Definition: parsenodes.h:2338
@ OBJECT_TSPARSER
Definition: parsenodes.h:2369
@ OBJECT_COLLATION
Definition: parsenodes.h:2329
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2372
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2322
@ OBJECT_OPCLASS
Definition: parsenodes.h:2346
@ OBJECT_DEFACL
Definition: parsenodes.h:2333
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2323
@ OBJECT_MATVIEW
Definition: parsenodes.h:2345
@ OBJECT_SCHEMA
Definition: parsenodes.h:2358
@ OBJECT_POLICY
Definition: parsenodes.h:2350
@ OBJECT_OPERATOR
Definition: parsenodes.h:2347
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2340
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2367
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2348
@ OBJECT_DOMAIN
Definition: parsenodes.h:2334
@ OBJECT_COLUMN
Definition: parsenodes.h:2328
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2364
@ OBJECT_ROLE
Definition: parsenodes.h:2355
@ OBJECT_ROUTINE
Definition: parsenodes.h:2356
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2344
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2353
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2351
@ OBJECT_EXTENSION
Definition: parsenodes.h:2337
@ OBJECT_INDEX
Definition: parsenodes.h:2342
@ OBJECT_DEFAULT
Definition: parsenodes.h:2332
@ OBJECT_DATABASE
Definition: parsenodes.h:2331
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2359
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2370
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2343
@ OBJECT_AMOP
Definition: parsenodes.h:2324
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2354
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2339
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2368
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2326
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2352
@ OBJECT_RULE
Definition: parsenodes.h:2357
@ OBJECT_CONVERSION
Definition: parsenodes.h:2330
@ OBJECT_AMPROC
Definition: parsenodes.h:2325
@ OBJECT_TABLE
Definition: parsenodes.h:2363
@ OBJECT_VIEW
Definition: parsenodes.h:2373
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2349
@ OBJECT_TYPE
Definition: parsenodes.h:2371
@ OBJECT_FUNCTION
Definition: parsenodes.h:2341
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2362
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2335
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2360
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2361
@ OBJECT_CAST
Definition: parsenodes.h:2327
@ OBJECT_TRIGGER
Definition: parsenodes.h:2366
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2365
@ ACL_TARGET_OBJECT
Definition: parsenodes.h:2567
@ ACL_TARGET_ALL_IN_SCHEMA
Definition: parsenodes.h:2568
#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:55
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:239
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:540
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:2624
List * cols
Definition: parsenodes.h:2625
Definition: acl.h:55
Oid ai_grantee
Definition: acl.h:56
Oid ai_grantor
Definition: acl.h:57
char * defname
Definition: parsenodes.h:841
Node * arg
Definition: parsenodes.h:842
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:428
Definition: c.h:693
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:1100