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