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