Make nbtree split REDO locking match original execution.
[pgsql.git] / src / backend / catalog / aclchk.c
blobc62616140859b38cdf6ec425606279f45298404d
1 /*-------------------------------------------------------------------------
3 * aclchk.c
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/catalog/aclchk.c
13 * NOTES
14 * See acl.h.
16 *-------------------------------------------------------------------------
18 #include "postgres.h"
20 #include "access/genam.h"
21 #include "access/heapam.h"
22 #include "access/htup_details.h"
23 #include "access/sysattr.h"
24 #include "access/tableam.h"
25 #include "access/xact.h"
26 #include "catalog/binary_upgrade.h"
27 #include "catalog/catalog.h"
28 #include "catalog/dependency.h"
29 #include "catalog/indexing.h"
30 #include "catalog/objectaccess.h"
31 #include "catalog/pg_aggregate.h"
32 #include "catalog/pg_am.h"
33 #include "catalog/pg_authid.h"
34 #include "catalog/pg_cast.h"
35 #include "catalog/pg_collation.h"
36 #include "catalog/pg_conversion.h"
37 #include "catalog/pg_database.h"
38 #include "catalog/pg_default_acl.h"
39 #include "catalog/pg_event_trigger.h"
40 #include "catalog/pg_extension.h"
41 #include "catalog/pg_foreign_data_wrapper.h"
42 #include "catalog/pg_foreign_server.h"
43 #include "catalog/pg_init_privs.h"
44 #include "catalog/pg_language.h"
45 #include "catalog/pg_largeobject.h"
46 #include "catalog/pg_largeobject_metadata.h"
47 #include "catalog/pg_namespace.h"
48 #include "catalog/pg_opclass.h"
49 #include "catalog/pg_operator.h"
50 #include "catalog/pg_opfamily.h"
51 #include "catalog/pg_proc.h"
52 #include "catalog/pg_statistic_ext.h"
53 #include "catalog/pg_subscription.h"
54 #include "catalog/pg_tablespace.h"
55 #include "catalog/pg_transform.h"
56 #include "catalog/pg_ts_config.h"
57 #include "catalog/pg_ts_dict.h"
58 #include "catalog/pg_ts_parser.h"
59 #include "catalog/pg_ts_template.h"
60 #include "catalog/pg_type.h"
61 #include "commands/dbcommands.h"
62 #include "commands/event_trigger.h"
63 #include "commands/extension.h"
64 #include "commands/proclang.h"
65 #include "commands/tablespace.h"
66 #include "foreign/foreign.h"
67 #include "miscadmin.h"
68 #include "nodes/makefuncs.h"
69 #include "parser/parse_func.h"
70 #include "parser/parse_type.h"
71 #include "utils/acl.h"
72 #include "utils/aclchk_internal.h"
73 #include "utils/builtins.h"
74 #include "utils/fmgroids.h"
75 #include "utils/lsyscache.h"
76 #include "utils/rel.h"
77 #include "utils/syscache.h"
80 * Internal format used by ALTER DEFAULT PRIVILEGES.
82 typedef struct
84 Oid roleid; /* owning role */
85 Oid nspid; /* namespace, or InvalidOid if none */
86 /* remaining fields are same as in InternalGrant: */
87 bool is_grant;
88 ObjectType objtype;
89 bool all_privs;
90 AclMode privileges;
91 List *grantees;
92 bool grant_option;
93 DropBehavior behavior;
94 } InternalDefaultACL;
97 * When performing a binary-upgrade, pg_dump will call a function to set
98 * this variable to let us know that we need to populate the pg_init_privs
99 * table for the GRANT/REVOKE commands while this variable is set to true.
101 bool binary_upgrade_record_init_privs = false;
103 static void ExecGrantStmt_oids(InternalGrant *istmt);
104 static void ExecGrant_Relation(InternalGrant *grantStmt);
105 static void ExecGrant_Database(InternalGrant *grantStmt);
106 static void ExecGrant_Fdw(InternalGrant *grantStmt);
107 static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
108 static void ExecGrant_Function(InternalGrant *grantStmt);
109 static void ExecGrant_Language(InternalGrant *grantStmt);
110 static void ExecGrant_Largeobject(InternalGrant *grantStmt);
111 static void ExecGrant_Namespace(InternalGrant *grantStmt);
112 static void ExecGrant_Tablespace(InternalGrant *grantStmt);
113 static void ExecGrant_Type(InternalGrant *grantStmt);
115 static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
116 static void SetDefaultACL(InternalDefaultACL *iacls);
118 static List *objectNamesToOids(ObjectType objtype, List *objnames);
119 static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
120 static List *getRelationsInNamespace(Oid namespaceId, char relkind);
121 static void expand_col_privileges(List *colnames, Oid table_oid,
122 AclMode this_privileges,
123 AclMode *col_privileges,
124 int num_col_privileges);
125 static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
126 AclMode this_privileges,
127 AclMode *col_privileges,
128 int num_col_privileges);
129 static AclMode string_to_privilege(const char *privname);
130 static const char *privilege_to_string(AclMode privilege);
131 static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
132 bool all_privs, AclMode privileges,
133 Oid objectId, Oid grantorId,
134 ObjectType objtype, const char *objname,
135 AttrNumber att_number, const char *colname);
136 static AclMode pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum,
137 Oid roleid, AclMode mask, AclMaskHow how);
138 static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
139 Acl *new_acl);
140 static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
141 Acl *new_acl);
145 * If is_grant is true, adds the given privileges for the list of
146 * grantees to the existing old_acl. If is_grant is false, the
147 * privileges for the given grantees are removed from old_acl.
149 * NB: the original old_acl is pfree'd.
151 static Acl *
152 merge_acl_with_grant(Acl *old_acl, bool is_grant,
153 bool grant_option, DropBehavior behavior,
154 List *grantees, AclMode privileges,
155 Oid grantorId, Oid ownerId)
157 unsigned modechg;
158 ListCell *j;
159 Acl *new_acl;
161 modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
163 new_acl = old_acl;
165 foreach(j, grantees)
167 AclItem aclitem;
168 Acl *newer_acl;
170 aclitem.ai_grantee = lfirst_oid(j);
173 * Grant options can only be granted to individual roles, not PUBLIC.
174 * The reason is that if a user would re-grant a privilege that he
175 * held through PUBLIC, and later the user is removed, the situation
176 * is impossible to clean up.
178 if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
179 ereport(ERROR,
180 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
181 errmsg("grant options can only be granted to roles")));
183 aclitem.ai_grantor = grantorId;
186 * The asymmetry in the conditions here comes from the spec. In
187 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
188 * to grant both the basic privilege and its grant option. But in
189 * REVOKE, plain revoke revokes both the basic privilege and its grant
190 * option, while REVOKE GRANT OPTION revokes only the option.
192 ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
193 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
194 (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
196 newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
198 /* avoid memory leak when there are many grantees */
199 pfree(new_acl);
200 new_acl = newer_acl;
203 return new_acl;
207 * Restrict the privileges to what we can actually grant, and emit
208 * the standards-mandated warning and error messages.
210 static AclMode
211 restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
212 AclMode privileges, Oid objectId, Oid grantorId,
213 ObjectType objtype, const char *objname,
214 AttrNumber att_number, const char *colname)
216 AclMode this_privileges;
217 AclMode whole_mask;
219 switch (objtype)
221 case OBJECT_COLUMN:
222 whole_mask = ACL_ALL_RIGHTS_COLUMN;
223 break;
224 case OBJECT_TABLE:
225 whole_mask = ACL_ALL_RIGHTS_RELATION;
226 break;
227 case OBJECT_SEQUENCE:
228 whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
229 break;
230 case OBJECT_DATABASE:
231 whole_mask = ACL_ALL_RIGHTS_DATABASE;
232 break;
233 case OBJECT_FUNCTION:
234 whole_mask = ACL_ALL_RIGHTS_FUNCTION;
235 break;
236 case OBJECT_LANGUAGE:
237 whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
238 break;
239 case OBJECT_LARGEOBJECT:
240 whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
241 break;
242 case OBJECT_SCHEMA:
243 whole_mask = ACL_ALL_RIGHTS_SCHEMA;
244 break;
245 case OBJECT_TABLESPACE:
246 whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
247 break;
248 case OBJECT_FDW:
249 whole_mask = ACL_ALL_RIGHTS_FDW;
250 break;
251 case OBJECT_FOREIGN_SERVER:
252 whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
253 break;
254 case OBJECT_EVENT_TRIGGER:
255 elog(ERROR, "grantable rights not supported for event triggers");
256 /* not reached, but keep compiler quiet */
257 return ACL_NO_RIGHTS;
258 case OBJECT_TYPE:
259 whole_mask = ACL_ALL_RIGHTS_TYPE;
260 break;
261 default:
262 elog(ERROR, "unrecognized object type: %d", objtype);
263 /* not reached, but keep compiler quiet */
264 return ACL_NO_RIGHTS;
268 * If we found no grant options, consider whether to issue a hard error.
269 * Per spec, having any privilege at all on the object will get you by
270 * here.
272 if (avail_goptions == ACL_NO_RIGHTS)
274 if (pg_aclmask(objtype, objectId, att_number, grantorId,
275 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
276 ACLMASK_ANY) == ACL_NO_RIGHTS)
278 if (objtype == OBJECT_COLUMN && colname)
279 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
280 else
281 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
286 * Restrict the operation to what we can actually grant or revoke, and
287 * issue a warning if appropriate. (For REVOKE this isn't quite what the
288 * spec says to do: the spec seems to want a warning only if no privilege
289 * bits actually change in the ACL. In practice that behavior seems much
290 * too noisy, as well as inconsistent with the GRANT case.)
292 this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
293 if (is_grant)
295 if (this_privileges == 0)
297 if (objtype == OBJECT_COLUMN && colname)
298 ereport(WARNING,
299 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
300 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
301 colname, objname)));
302 else
303 ereport(WARNING,
304 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
305 errmsg("no privileges were granted for \"%s\"",
306 objname)));
308 else if (!all_privs && this_privileges != privileges)
310 if (objtype == OBJECT_COLUMN && colname)
311 ereport(WARNING,
312 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
313 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
314 colname, objname)));
315 else
316 ereport(WARNING,
317 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
318 errmsg("not all privileges were granted for \"%s\"",
319 objname)));
322 else
324 if (this_privileges == 0)
326 if (objtype == OBJECT_COLUMN && colname)
327 ereport(WARNING,
328 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
329 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
330 colname, objname)));
331 else
332 ereport(WARNING,
333 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
334 errmsg("no privileges could be revoked for \"%s\"",
335 objname)));
337 else if (!all_privs && this_privileges != privileges)
339 if (objtype == OBJECT_COLUMN && colname)
340 ereport(WARNING,
341 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
342 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
343 colname, objname)));
344 else
345 ereport(WARNING,
346 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
347 errmsg("not all privileges could be revoked for \"%s\"",
348 objname)));
352 return this_privileges;
356 * Called to execute the utility commands GRANT and REVOKE
358 void
359 ExecuteGrantStmt(GrantStmt *stmt)
361 InternalGrant istmt;
362 ListCell *cell;
363 const char *errormsg;
364 AclMode all_privileges;
367 * Turn the regular GrantStmt into the InternalGrant form.
369 istmt.is_grant = stmt->is_grant;
370 istmt.objtype = stmt->objtype;
372 /* Collect the OIDs of the target objects */
373 switch (stmt->targtype)
375 case ACL_TARGET_OBJECT:
376 istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
377 break;
378 case ACL_TARGET_ALL_IN_SCHEMA:
379 istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
380 break;
381 /* ACL_TARGET_DEFAULTS should not be seen here */
382 default:
383 elog(ERROR, "unrecognized GrantStmt.targtype: %d",
384 (int) stmt->targtype);
387 /* all_privs to be filled below */
388 /* privileges to be filled below */
389 istmt.col_privs = NIL; /* may get filled below */
390 istmt.grantees = NIL; /* filled below */
391 istmt.grant_option = stmt->grant_option;
392 istmt.behavior = stmt->behavior;
395 * Convert the RoleSpec list into an Oid list. Note that at this point we
396 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
397 * there shouldn't be any additional work needed to support this case.
399 foreach(cell, stmt->grantees)
401 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
402 Oid grantee_uid;
404 switch (grantee->roletype)
406 case ROLESPEC_PUBLIC:
407 grantee_uid = ACL_ID_PUBLIC;
408 break;
409 default:
410 grantee_uid = get_rolespec_oid(grantee, false);
411 break;
413 istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
417 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
418 * bitmask. Note: objtype can't be OBJECT_COLUMN.
420 switch (stmt->objtype)
422 case OBJECT_TABLE:
425 * Because this might be a sequence, we test both relation and
426 * sequence bits, and later do a more limited test when we know
427 * the object type.
429 all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
430 errormsg = gettext_noop("invalid privilege type %s for relation");
431 break;
432 case OBJECT_SEQUENCE:
433 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
434 errormsg = gettext_noop("invalid privilege type %s for sequence");
435 break;
436 case OBJECT_DATABASE:
437 all_privileges = ACL_ALL_RIGHTS_DATABASE;
438 errormsg = gettext_noop("invalid privilege type %s for database");
439 break;
440 case OBJECT_DOMAIN:
441 all_privileges = ACL_ALL_RIGHTS_TYPE;
442 errormsg = gettext_noop("invalid privilege type %s for domain");
443 break;
444 case OBJECT_FUNCTION:
445 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
446 errormsg = gettext_noop("invalid privilege type %s for function");
447 break;
448 case OBJECT_LANGUAGE:
449 all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
450 errormsg = gettext_noop("invalid privilege type %s for language");
451 break;
452 case OBJECT_LARGEOBJECT:
453 all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
454 errormsg = gettext_noop("invalid privilege type %s for large object");
455 break;
456 case OBJECT_SCHEMA:
457 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
458 errormsg = gettext_noop("invalid privilege type %s for schema");
459 break;
460 case OBJECT_PROCEDURE:
461 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
462 errormsg = gettext_noop("invalid privilege type %s for procedure");
463 break;
464 case OBJECT_ROUTINE:
465 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
466 errormsg = gettext_noop("invalid privilege type %s for routine");
467 break;
468 case OBJECT_TABLESPACE:
469 all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
470 errormsg = gettext_noop("invalid privilege type %s for tablespace");
471 break;
472 case OBJECT_TYPE:
473 all_privileges = ACL_ALL_RIGHTS_TYPE;
474 errormsg = gettext_noop("invalid privilege type %s for type");
475 break;
476 case OBJECT_FDW:
477 all_privileges = ACL_ALL_RIGHTS_FDW;
478 errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
479 break;
480 case OBJECT_FOREIGN_SERVER:
481 all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
482 errormsg = gettext_noop("invalid privilege type %s for foreign server");
483 break;
484 default:
485 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
486 (int) stmt->objtype);
487 /* keep compiler quiet */
488 all_privileges = ACL_NO_RIGHTS;
489 errormsg = NULL;
492 if (stmt->privileges == NIL)
494 istmt.all_privs = true;
497 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
498 * depending on the object type
500 istmt.privileges = ACL_NO_RIGHTS;
502 else
504 istmt.all_privs = false;
505 istmt.privileges = ACL_NO_RIGHTS;
507 foreach(cell, stmt->privileges)
509 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
510 AclMode priv;
513 * If it's a column-level specification, we just set it aside in
514 * col_privs for the moment; but insist it's for a relation.
516 if (privnode->cols)
518 if (stmt->objtype != OBJECT_TABLE)
519 ereport(ERROR,
520 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
521 errmsg("column privileges are only valid for relations")));
522 istmt.col_privs = lappend(istmt.col_privs, privnode);
523 continue;
526 if (privnode->priv_name == NULL) /* parser mistake? */
527 elog(ERROR, "AccessPriv node must specify privilege or columns");
528 priv = string_to_privilege(privnode->priv_name);
530 if (priv & ~((AclMode) all_privileges))
531 ereport(ERROR,
532 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
533 errmsg(errormsg, privilege_to_string(priv))));
535 istmt.privileges |= priv;
539 ExecGrantStmt_oids(&istmt);
543 * ExecGrantStmt_oids
545 * Internal entry point for granting and revoking privileges.
547 static void
548 ExecGrantStmt_oids(InternalGrant *istmt)
550 switch (istmt->objtype)
552 case OBJECT_TABLE:
553 case OBJECT_SEQUENCE:
554 ExecGrant_Relation(istmt);
555 break;
556 case OBJECT_DATABASE:
557 ExecGrant_Database(istmt);
558 break;
559 case OBJECT_DOMAIN:
560 case OBJECT_TYPE:
561 ExecGrant_Type(istmt);
562 break;
563 case OBJECT_FDW:
564 ExecGrant_Fdw(istmt);
565 break;
566 case OBJECT_FOREIGN_SERVER:
567 ExecGrant_ForeignServer(istmt);
568 break;
569 case OBJECT_FUNCTION:
570 case OBJECT_PROCEDURE:
571 case OBJECT_ROUTINE:
572 ExecGrant_Function(istmt);
573 break;
574 case OBJECT_LANGUAGE:
575 ExecGrant_Language(istmt);
576 break;
577 case OBJECT_LARGEOBJECT:
578 ExecGrant_Largeobject(istmt);
579 break;
580 case OBJECT_SCHEMA:
581 ExecGrant_Namespace(istmt);
582 break;
583 case OBJECT_TABLESPACE:
584 ExecGrant_Tablespace(istmt);
585 break;
586 default:
587 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
588 (int) istmt->objtype);
592 * Pass the info to event triggers about the just-executed GRANT. Note
593 * that we prefer to do it after actually executing it, because that gives
594 * the functions a chance to adjust the istmt with privileges actually
595 * granted.
597 if (EventTriggerSupportsObjectType(istmt->objtype))
598 EventTriggerCollectGrant(istmt);
602 * objectNamesToOids
604 * Turn a list of object names of a given type into an Oid list.
606 * XXX: This function doesn't take any sort of locks on the objects whose
607 * names it looks up. In the face of concurrent DDL, we might easily latch
608 * onto an old version of an object, causing the GRANT or REVOKE statement
609 * to fail.
611 static List *
612 objectNamesToOids(ObjectType objtype, List *objnames)
614 List *objects = NIL;
615 ListCell *cell;
617 Assert(objnames != NIL);
619 switch (objtype)
621 case OBJECT_TABLE:
622 case OBJECT_SEQUENCE:
623 foreach(cell, objnames)
625 RangeVar *relvar = (RangeVar *) lfirst(cell);
626 Oid relOid;
628 relOid = RangeVarGetRelid(relvar, NoLock, false);
629 objects = lappend_oid(objects, relOid);
631 break;
632 case OBJECT_DATABASE:
633 foreach(cell, objnames)
635 char *dbname = strVal(lfirst(cell));
636 Oid dbid;
638 dbid = get_database_oid(dbname, false);
639 objects = lappend_oid(objects, dbid);
641 break;
642 case OBJECT_DOMAIN:
643 case OBJECT_TYPE:
644 foreach(cell, objnames)
646 List *typname = (List *) lfirst(cell);
647 Oid oid;
649 oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
650 objects = lappend_oid(objects, oid);
652 break;
653 case OBJECT_FUNCTION:
654 foreach(cell, objnames)
656 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
657 Oid funcid;
659 funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
660 objects = lappend_oid(objects, funcid);
662 break;
663 case OBJECT_LANGUAGE:
664 foreach(cell, objnames)
666 char *langname = strVal(lfirst(cell));
667 Oid oid;
669 oid = get_language_oid(langname, false);
670 objects = lappend_oid(objects, oid);
672 break;
673 case OBJECT_LARGEOBJECT:
674 foreach(cell, objnames)
676 Oid lobjOid = oidparse(lfirst(cell));
678 if (!LargeObjectExists(lobjOid))
679 ereport(ERROR,
680 (errcode(ERRCODE_UNDEFINED_OBJECT),
681 errmsg("large object %u does not exist",
682 lobjOid)));
684 objects = lappend_oid(objects, lobjOid);
686 break;
687 case OBJECT_SCHEMA:
688 foreach(cell, objnames)
690 char *nspname = strVal(lfirst(cell));
691 Oid oid;
693 oid = get_namespace_oid(nspname, false);
694 objects = lappend_oid(objects, oid);
696 break;
697 case OBJECT_PROCEDURE:
698 foreach(cell, objnames)
700 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
701 Oid procid;
703 procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
704 objects = lappend_oid(objects, procid);
706 break;
707 case OBJECT_ROUTINE:
708 foreach(cell, objnames)
710 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
711 Oid routid;
713 routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
714 objects = lappend_oid(objects, routid);
716 break;
717 case OBJECT_TABLESPACE:
718 foreach(cell, objnames)
720 char *spcname = strVal(lfirst(cell));
721 Oid spcoid;
723 spcoid = get_tablespace_oid(spcname, false);
724 objects = lappend_oid(objects, spcoid);
726 break;
727 case OBJECT_FDW:
728 foreach(cell, objnames)
730 char *fdwname = strVal(lfirst(cell));
731 Oid fdwid = get_foreign_data_wrapper_oid(fdwname, false);
733 objects = lappend_oid(objects, fdwid);
735 break;
736 case OBJECT_FOREIGN_SERVER:
737 foreach(cell, objnames)
739 char *srvname = strVal(lfirst(cell));
740 Oid srvid = get_foreign_server_oid(srvname, false);
742 objects = lappend_oid(objects, srvid);
744 break;
745 default:
746 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
747 (int) objtype);
750 return objects;
754 * objectsInSchemaToOids
756 * Find all objects of a given type in specified schemas, and make a list
757 * of their Oids. We check USAGE privilege on the schemas, but there is
758 * no privilege checking on the individual objects here.
760 static List *
761 objectsInSchemaToOids(ObjectType objtype, List *nspnames)
763 List *objects = NIL;
764 ListCell *cell;
766 foreach(cell, nspnames)
768 char *nspname = strVal(lfirst(cell));
769 Oid namespaceId;
770 List *objs;
772 namespaceId = LookupExplicitNamespace(nspname, false);
774 switch (objtype)
776 case OBJECT_TABLE:
777 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
778 objects = list_concat(objects, objs);
779 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
780 objects = list_concat(objects, objs);
781 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
782 objects = list_concat(objects, objs);
783 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
784 objects = list_concat(objects, objs);
785 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
786 objects = list_concat(objects, objs);
787 break;
788 case OBJECT_SEQUENCE:
789 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
790 objects = list_concat(objects, objs);
791 break;
792 case OBJECT_FUNCTION:
793 case OBJECT_PROCEDURE:
794 case OBJECT_ROUTINE:
796 ScanKeyData key[2];
797 int keycount;
798 Relation rel;
799 TableScanDesc scan;
800 HeapTuple tuple;
802 keycount = 0;
803 ScanKeyInit(&key[keycount++],
804 Anum_pg_proc_pronamespace,
805 BTEqualStrategyNumber, F_OIDEQ,
806 ObjectIdGetDatum(namespaceId));
808 if (objtype == OBJECT_FUNCTION)
809 /* includes aggregates and window functions */
810 ScanKeyInit(&key[keycount++],
811 Anum_pg_proc_prokind,
812 BTEqualStrategyNumber, F_CHARNE,
813 CharGetDatum(PROKIND_PROCEDURE));
814 else if (objtype == OBJECT_PROCEDURE)
815 ScanKeyInit(&key[keycount++],
816 Anum_pg_proc_prokind,
817 BTEqualStrategyNumber, F_CHAREQ,
818 CharGetDatum(PROKIND_PROCEDURE));
820 rel = table_open(ProcedureRelationId, AccessShareLock);
821 scan = table_beginscan_catalog(rel, keycount, key);
823 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
825 Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
827 objects = lappend_oid(objects, oid);
830 table_endscan(scan);
831 table_close(rel, AccessShareLock);
833 break;
834 default:
835 /* should not happen */
836 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
837 (int) objtype);
841 return objects;
845 * getRelationsInNamespace
847 * Return Oid list of relations in given namespace filtered by relation kind
849 static List *
850 getRelationsInNamespace(Oid namespaceId, char relkind)
852 List *relations = NIL;
853 ScanKeyData key[2];
854 Relation rel;
855 TableScanDesc scan;
856 HeapTuple tuple;
858 ScanKeyInit(&key[0],
859 Anum_pg_class_relnamespace,
860 BTEqualStrategyNumber, F_OIDEQ,
861 ObjectIdGetDatum(namespaceId));
862 ScanKeyInit(&key[1],
863 Anum_pg_class_relkind,
864 BTEqualStrategyNumber, F_CHAREQ,
865 CharGetDatum(relkind));
867 rel = table_open(RelationRelationId, AccessShareLock);
868 scan = table_beginscan_catalog(rel, 2, key);
870 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
872 Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
874 relations = lappend_oid(relations, oid);
877 table_endscan(scan);
878 table_close(rel, AccessShareLock);
880 return relations;
885 * ALTER DEFAULT PRIVILEGES statement
887 void
888 ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
890 GrantStmt *action = stmt->action;
891 InternalDefaultACL iacls;
892 ListCell *cell;
893 List *rolespecs = NIL;
894 List *nspnames = NIL;
895 DefElem *drolespecs = NULL;
896 DefElem *dnspnames = NULL;
897 AclMode all_privileges;
898 const char *errormsg;
900 /* Deconstruct the "options" part of the statement */
901 foreach(cell, stmt->options)
903 DefElem *defel = (DefElem *) lfirst(cell);
905 if (strcmp(defel->defname, "schemas") == 0)
907 if (dnspnames)
908 ereport(ERROR,
909 (errcode(ERRCODE_SYNTAX_ERROR),
910 errmsg("conflicting or redundant options"),
911 parser_errposition(pstate, defel->location)));
912 dnspnames = defel;
914 else if (strcmp(defel->defname, "roles") == 0)
916 if (drolespecs)
917 ereport(ERROR,
918 (errcode(ERRCODE_SYNTAX_ERROR),
919 errmsg("conflicting or redundant options"),
920 parser_errposition(pstate, defel->location)));
921 drolespecs = defel;
923 else
924 elog(ERROR, "option \"%s\" not recognized", defel->defname);
927 if (dnspnames)
928 nspnames = (List *) dnspnames->arg;
929 if (drolespecs)
930 rolespecs = (List *) drolespecs->arg;
932 /* Prepare the InternalDefaultACL representation of the statement */
933 /* roleid to be filled below */
934 /* nspid to be filled in SetDefaultACLsInSchemas */
935 iacls.is_grant = action->is_grant;
936 iacls.objtype = action->objtype;
937 /* all_privs to be filled below */
938 /* privileges to be filled below */
939 iacls.grantees = NIL; /* filled below */
940 iacls.grant_option = action->grant_option;
941 iacls.behavior = action->behavior;
944 * Convert the RoleSpec list into an Oid list. Note that at this point we
945 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
946 * there shouldn't be any additional work needed to support this case.
948 foreach(cell, action->grantees)
950 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
951 Oid grantee_uid;
953 switch (grantee->roletype)
955 case ROLESPEC_PUBLIC:
956 grantee_uid = ACL_ID_PUBLIC;
957 break;
958 default:
959 grantee_uid = get_rolespec_oid(grantee, false);
960 break;
962 iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
966 * Convert action->privileges, a list of privilege strings, into an
967 * AclMode bitmask.
969 switch (action->objtype)
971 case OBJECT_TABLE:
972 all_privileges = ACL_ALL_RIGHTS_RELATION;
973 errormsg = gettext_noop("invalid privilege type %s for relation");
974 break;
975 case OBJECT_SEQUENCE:
976 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
977 errormsg = gettext_noop("invalid privilege type %s for sequence");
978 break;
979 case OBJECT_FUNCTION:
980 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
981 errormsg = gettext_noop("invalid privilege type %s for function");
982 break;
983 case OBJECT_PROCEDURE:
984 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
985 errormsg = gettext_noop("invalid privilege type %s for procedure");
986 break;
987 case OBJECT_ROUTINE:
988 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
989 errormsg = gettext_noop("invalid privilege type %s for routine");
990 break;
991 case OBJECT_TYPE:
992 all_privileges = ACL_ALL_RIGHTS_TYPE;
993 errormsg = gettext_noop("invalid privilege type %s for type");
994 break;
995 case OBJECT_SCHEMA:
996 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
997 errormsg = gettext_noop("invalid privilege type %s for schema");
998 break;
999 default:
1000 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1001 (int) action->objtype);
1002 /* keep compiler quiet */
1003 all_privileges = ACL_NO_RIGHTS;
1004 errormsg = NULL;
1007 if (action->privileges == NIL)
1009 iacls.all_privs = true;
1012 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1013 * depending on the object type
1015 iacls.privileges = ACL_NO_RIGHTS;
1017 else
1019 iacls.all_privs = false;
1020 iacls.privileges = ACL_NO_RIGHTS;
1022 foreach(cell, action->privileges)
1024 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1025 AclMode priv;
1027 if (privnode->cols)
1028 ereport(ERROR,
1029 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1030 errmsg("default privileges cannot be set for columns")));
1032 if (privnode->priv_name == NULL) /* parser mistake? */
1033 elog(ERROR, "AccessPriv node must specify privilege");
1034 priv = string_to_privilege(privnode->priv_name);
1036 if (priv & ~((AclMode) all_privileges))
1037 ereport(ERROR,
1038 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1039 errmsg(errormsg, privilege_to_string(priv))));
1041 iacls.privileges |= priv;
1045 if (rolespecs == NIL)
1047 /* Set permissions for myself */
1048 iacls.roleid = GetUserId();
1050 SetDefaultACLsInSchemas(&iacls, nspnames);
1052 else
1054 /* Look up the role OIDs and do permissions checks */
1055 ListCell *rolecell;
1057 foreach(rolecell, rolespecs)
1059 RoleSpec *rolespec = lfirst(rolecell);
1061 iacls.roleid = get_rolespec_oid(rolespec, false);
1064 * We insist that calling user be a member of each target role. If
1065 * he has that, he could become that role anyway via SET ROLE, so
1066 * FOR ROLE is just a syntactic convenience and doesn't give any
1067 * special privileges.
1069 check_is_member_of_role(GetUserId(), iacls.roleid);
1071 SetDefaultACLsInSchemas(&iacls, nspnames);
1077 * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1079 * All fields of *iacls except nspid were filled already
1081 static void
1082 SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
1084 if (nspnames == NIL)
1086 /* Set database-wide permissions if no schema was specified */
1087 iacls->nspid = InvalidOid;
1089 SetDefaultACL(iacls);
1091 else
1093 /* Look up the schema OIDs and set permissions for each one */
1094 ListCell *nspcell;
1096 foreach(nspcell, nspnames)
1098 char *nspname = strVal(lfirst(nspcell));
1100 iacls->nspid = get_namespace_oid(nspname, false);
1103 * We used to insist that the target role have CREATE privileges
1104 * on the schema, since without that it wouldn't be able to create
1105 * an object for which these default privileges would apply.
1106 * However, this check proved to be more confusing than helpful,
1107 * and it also caused certain database states to not be
1108 * dumpable/restorable, since revoking CREATE doesn't cause
1109 * default privileges for the schema to go away. So now, we just
1110 * allow the ALTER; if the user lacks CREATE he'll find out when
1111 * he tries to create an object.
1114 SetDefaultACL(iacls);
1121 * Create or update a pg_default_acl entry
1123 static void
1124 SetDefaultACL(InternalDefaultACL *iacls)
1126 AclMode this_privileges = iacls->privileges;
1127 char objtype;
1128 Relation rel;
1129 HeapTuple tuple;
1130 bool isNew;
1131 Acl *def_acl;
1132 Acl *old_acl;
1133 Acl *new_acl;
1134 HeapTuple newtuple;
1135 Datum values[Natts_pg_default_acl];
1136 bool nulls[Natts_pg_default_acl];
1137 bool replaces[Natts_pg_default_acl];
1138 int noldmembers;
1139 int nnewmembers;
1140 Oid *oldmembers;
1141 Oid *newmembers;
1143 rel = table_open(DefaultAclRelationId, RowExclusiveLock);
1146 * The default for a global entry is the hard-wired default ACL for the
1147 * particular object type. The default for non-global entries is an empty
1148 * ACL. This must be so because global entries replace the hard-wired
1149 * defaults, while others are added on.
1151 if (!OidIsValid(iacls->nspid))
1152 def_acl = acldefault(iacls->objtype, iacls->roleid);
1153 else
1154 def_acl = make_empty_acl();
1157 * Convert ACL object type to pg_default_acl object type and handle
1158 * all_privs option
1160 switch (iacls->objtype)
1162 case OBJECT_TABLE:
1163 objtype = DEFACLOBJ_RELATION;
1164 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1165 this_privileges = ACL_ALL_RIGHTS_RELATION;
1166 break;
1168 case OBJECT_SEQUENCE:
1169 objtype = DEFACLOBJ_SEQUENCE;
1170 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1171 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1172 break;
1174 case OBJECT_FUNCTION:
1175 objtype = DEFACLOBJ_FUNCTION;
1176 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1177 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
1178 break;
1180 case OBJECT_TYPE:
1181 objtype = DEFACLOBJ_TYPE;
1182 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1183 this_privileges = ACL_ALL_RIGHTS_TYPE;
1184 break;
1186 case OBJECT_SCHEMA:
1187 if (OidIsValid(iacls->nspid))
1188 ereport(ERROR,
1189 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1190 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1191 objtype = DEFACLOBJ_NAMESPACE;
1192 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1193 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1194 break;
1196 default:
1197 elog(ERROR, "unrecognized objtype: %d",
1198 (int) iacls->objtype);
1199 objtype = 0; /* keep compiler quiet */
1200 break;
1203 /* Search for existing row for this object type in catalog */
1204 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1205 ObjectIdGetDatum(iacls->roleid),
1206 ObjectIdGetDatum(iacls->nspid),
1207 CharGetDatum(objtype));
1209 if (HeapTupleIsValid(tuple))
1211 Datum aclDatum;
1212 bool isNull;
1214 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1215 Anum_pg_default_acl_defaclacl,
1216 &isNull);
1217 if (!isNull)
1218 old_acl = DatumGetAclPCopy(aclDatum);
1219 else
1220 old_acl = NULL; /* this case shouldn't happen, probably */
1221 isNew = false;
1223 else
1225 old_acl = NULL;
1226 isNew = true;
1229 if (old_acl != NULL)
1232 * We need the members of both old and new ACLs so we can correct the
1233 * shared dependency information. Collect data before
1234 * merge_acl_with_grant throws away old_acl.
1236 noldmembers = aclmembers(old_acl, &oldmembers);
1238 else
1240 /* If no or null entry, start with the default ACL value */
1241 old_acl = aclcopy(def_acl);
1242 /* There are no old member roles according to the catalogs */
1243 noldmembers = 0;
1244 oldmembers = NULL;
1248 * Generate new ACL. Grantor of rights is always the same as the target
1249 * role.
1251 new_acl = merge_acl_with_grant(old_acl,
1252 iacls->is_grant,
1253 iacls->grant_option,
1254 iacls->behavior,
1255 iacls->grantees,
1256 this_privileges,
1257 iacls->roleid,
1258 iacls->roleid);
1261 * If the result is the same as the default value, we do not need an
1262 * explicit pg_default_acl entry, and should in fact remove the entry if
1263 * it exists. Must sort both arrays to compare properly.
1265 aclitemsort(new_acl);
1266 aclitemsort(def_acl);
1267 if (aclequal(new_acl, def_acl))
1269 /* delete old entry, if indeed there is one */
1270 if (!isNew)
1272 ObjectAddress myself;
1275 * The dependency machinery will take care of removing all
1276 * associated dependency entries. We use DROP_RESTRICT since
1277 * there shouldn't be anything depending on this entry.
1279 myself.classId = DefaultAclRelationId;
1280 myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1281 myself.objectSubId = 0;
1283 performDeletion(&myself, DROP_RESTRICT, 0);
1286 else
1288 Oid defAclOid;
1290 /* Prepare to insert or update pg_default_acl entry */
1291 MemSet(values, 0, sizeof(values));
1292 MemSet(nulls, false, sizeof(nulls));
1293 MemSet(replaces, false, sizeof(replaces));
1295 if (isNew)
1297 /* insert new entry */
1298 defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1299 Anum_pg_default_acl_oid);
1300 values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1301 values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1302 values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1303 values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1304 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1306 newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1307 CatalogTupleInsert(rel, newtuple);
1309 else
1311 defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1313 /* update existing entry */
1314 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1315 replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1317 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1318 values, nulls, replaces);
1319 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1322 /* these dependencies don't change in an update */
1323 if (isNew)
1325 /* dependency on role */
1326 recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1327 iacls->roleid);
1329 /* dependency on namespace */
1330 if (OidIsValid(iacls->nspid))
1332 ObjectAddress myself,
1333 referenced;
1335 myself.classId = DefaultAclRelationId;
1336 myself.objectId = defAclOid;
1337 myself.objectSubId = 0;
1339 referenced.classId = NamespaceRelationId;
1340 referenced.objectId = iacls->nspid;
1341 referenced.objectSubId = 0;
1343 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1348 * Update the shared dependency ACL info
1350 nnewmembers = aclmembers(new_acl, &newmembers);
1352 updateAclDependencies(DefaultAclRelationId,
1353 defAclOid, 0,
1354 iacls->roleid,
1355 noldmembers, oldmembers,
1356 nnewmembers, newmembers);
1358 if (isNew)
1359 InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1360 else
1361 InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1364 if (HeapTupleIsValid(tuple))
1365 ReleaseSysCache(tuple);
1367 table_close(rel, RowExclusiveLock);
1372 * RemoveRoleFromObjectACL
1374 * Used by shdepDropOwned to remove mentions of a role in ACLs
1376 void
1377 RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1379 if (classid == DefaultAclRelationId)
1381 InternalDefaultACL iacls;
1382 Form_pg_default_acl pg_default_acl_tuple;
1383 Relation rel;
1384 ScanKeyData skey[1];
1385 SysScanDesc scan;
1386 HeapTuple tuple;
1388 /* first fetch info needed by SetDefaultACL */
1389 rel = table_open(DefaultAclRelationId, AccessShareLock);
1391 ScanKeyInit(&skey[0],
1392 Anum_pg_default_acl_oid,
1393 BTEqualStrategyNumber, F_OIDEQ,
1394 ObjectIdGetDatum(objid));
1396 scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1397 NULL, 1, skey);
1399 tuple = systable_getnext(scan);
1401 if (!HeapTupleIsValid(tuple))
1402 elog(ERROR, "could not find tuple for default ACL %u", objid);
1404 pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1406 iacls.roleid = pg_default_acl_tuple->defaclrole;
1407 iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1409 switch (pg_default_acl_tuple->defaclobjtype)
1411 case DEFACLOBJ_RELATION:
1412 iacls.objtype = OBJECT_TABLE;
1413 break;
1414 case DEFACLOBJ_SEQUENCE:
1415 iacls.objtype = OBJECT_SEQUENCE;
1416 break;
1417 case DEFACLOBJ_FUNCTION:
1418 iacls.objtype = OBJECT_FUNCTION;
1419 break;
1420 case DEFACLOBJ_TYPE:
1421 iacls.objtype = OBJECT_TYPE;
1422 break;
1423 case DEFACLOBJ_NAMESPACE:
1424 iacls.objtype = OBJECT_SCHEMA;
1425 break;
1426 default:
1427 /* Shouldn't get here */
1428 elog(ERROR, "unexpected default ACL type: %d",
1429 (int) pg_default_acl_tuple->defaclobjtype);
1430 break;
1433 systable_endscan(scan);
1434 table_close(rel, AccessShareLock);
1436 iacls.is_grant = false;
1437 iacls.all_privs = true;
1438 iacls.privileges = ACL_NO_RIGHTS;
1439 iacls.grantees = list_make1_oid(roleid);
1440 iacls.grant_option = false;
1441 iacls.behavior = DROP_CASCADE;
1443 /* Do it */
1444 SetDefaultACL(&iacls);
1446 else
1448 InternalGrant istmt;
1450 switch (classid)
1452 case RelationRelationId:
1453 /* it's OK to use TABLE for a sequence */
1454 istmt.objtype = OBJECT_TABLE;
1455 break;
1456 case DatabaseRelationId:
1457 istmt.objtype = OBJECT_DATABASE;
1458 break;
1459 case TypeRelationId:
1460 istmt.objtype = OBJECT_TYPE;
1461 break;
1462 case ProcedureRelationId:
1463 istmt.objtype = OBJECT_ROUTINE;
1464 break;
1465 case LanguageRelationId:
1466 istmt.objtype = OBJECT_LANGUAGE;
1467 break;
1468 case LargeObjectRelationId:
1469 istmt.objtype = OBJECT_LARGEOBJECT;
1470 break;
1471 case NamespaceRelationId:
1472 istmt.objtype = OBJECT_SCHEMA;
1473 break;
1474 case TableSpaceRelationId:
1475 istmt.objtype = OBJECT_TABLESPACE;
1476 break;
1477 case ForeignServerRelationId:
1478 istmt.objtype = OBJECT_FOREIGN_SERVER;
1479 break;
1480 case ForeignDataWrapperRelationId:
1481 istmt.objtype = OBJECT_FDW;
1482 break;
1483 default:
1484 elog(ERROR, "unexpected object class %u", classid);
1485 break;
1487 istmt.is_grant = false;
1488 istmt.objects = list_make1_oid(objid);
1489 istmt.all_privs = true;
1490 istmt.privileges = ACL_NO_RIGHTS;
1491 istmt.col_privs = NIL;
1492 istmt.grantees = list_make1_oid(roleid);
1493 istmt.grant_option = false;
1494 istmt.behavior = DROP_CASCADE;
1496 ExecGrantStmt_oids(&istmt);
1502 * expand_col_privileges
1504 * OR the specified privilege(s) into per-column array entries for each
1505 * specified attribute. The per-column array is indexed starting at
1506 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1508 static void
1509 expand_col_privileges(List *colnames, Oid table_oid,
1510 AclMode this_privileges,
1511 AclMode *col_privileges,
1512 int num_col_privileges)
1514 ListCell *cell;
1516 foreach(cell, colnames)
1518 char *colname = strVal(lfirst(cell));
1519 AttrNumber attnum;
1521 attnum = get_attnum(table_oid, colname);
1522 if (attnum == InvalidAttrNumber)
1523 ereport(ERROR,
1524 (errcode(ERRCODE_UNDEFINED_COLUMN),
1525 errmsg("column \"%s\" of relation \"%s\" does not exist",
1526 colname, get_rel_name(table_oid))));
1527 attnum -= FirstLowInvalidHeapAttributeNumber;
1528 if (attnum <= 0 || attnum >= num_col_privileges)
1529 elog(ERROR, "column number out of range"); /* safety check */
1530 col_privileges[attnum] |= this_privileges;
1535 * expand_all_col_privileges
1537 * OR the specified privilege(s) into per-column array entries for each valid
1538 * attribute of a relation. The per-column array is indexed starting at
1539 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1541 static void
1542 expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
1543 AclMode this_privileges,
1544 AclMode *col_privileges,
1545 int num_col_privileges)
1547 AttrNumber curr_att;
1549 Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1550 for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1551 curr_att <= classForm->relnatts;
1552 curr_att++)
1554 HeapTuple attTuple;
1555 bool isdropped;
1557 if (curr_att == InvalidAttrNumber)
1558 continue;
1560 /* Views don't have any system columns at all */
1561 if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1562 continue;
1564 attTuple = SearchSysCache2(ATTNUM,
1565 ObjectIdGetDatum(table_oid),
1566 Int16GetDatum(curr_att));
1567 if (!HeapTupleIsValid(attTuple))
1568 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1569 curr_att, table_oid);
1571 isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1573 ReleaseSysCache(attTuple);
1575 /* ignore dropped columns */
1576 if (isdropped)
1577 continue;
1579 col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1584 * This processes attributes, but expects to be called from
1585 * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1587 static void
1588 ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1589 AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1590 Relation attRelation, const Acl *old_rel_acl)
1592 HeapTuple attr_tuple;
1593 Form_pg_attribute pg_attribute_tuple;
1594 Acl *old_acl;
1595 Acl *new_acl;
1596 Acl *merged_acl;
1597 Datum aclDatum;
1598 bool isNull;
1599 Oid grantorId;
1600 AclMode avail_goptions;
1601 bool need_update;
1602 HeapTuple newtuple;
1603 Datum values[Natts_pg_attribute];
1604 bool nulls[Natts_pg_attribute];
1605 bool replaces[Natts_pg_attribute];
1606 int noldmembers;
1607 int nnewmembers;
1608 Oid *oldmembers;
1609 Oid *newmembers;
1611 attr_tuple = SearchSysCache2(ATTNUM,
1612 ObjectIdGetDatum(relOid),
1613 Int16GetDatum(attnum));
1614 if (!HeapTupleIsValid(attr_tuple))
1615 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1616 attnum, relOid);
1617 pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1620 * Get working copy of existing ACL. If there's no ACL, substitute the
1621 * proper default.
1623 aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1624 &isNull);
1625 if (isNull)
1627 old_acl = acldefault(OBJECT_COLUMN, ownerId);
1628 /* There are no old member roles according to the catalogs */
1629 noldmembers = 0;
1630 oldmembers = NULL;
1632 else
1634 old_acl = DatumGetAclPCopy(aclDatum);
1635 /* Get the roles mentioned in the existing ACL */
1636 noldmembers = aclmembers(old_acl, &oldmembers);
1640 * In select_best_grantor we should consider existing table-level ACL bits
1641 * as well as the per-column ACL. Build a new ACL that is their
1642 * concatenation. (This is a bit cheap and dirty compared to merging them
1643 * properly with no duplications, but it's all we need here.)
1645 merged_acl = aclconcat(old_rel_acl, old_acl);
1647 /* Determine ID to do the grant as, and available grant options */
1648 select_best_grantor(GetUserId(), col_privileges,
1649 merged_acl, ownerId,
1650 &grantorId, &avail_goptions);
1652 pfree(merged_acl);
1655 * Restrict the privileges to what we can actually grant, and emit the
1656 * standards-mandated warning and error messages. Note: we don't track
1657 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1658 * each column; we just approximate it by whether all the possible
1659 * privileges are specified now. Since the all_privs flag only determines
1660 * whether a warning is issued, this seems close enough.
1662 col_privileges =
1663 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1664 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1665 col_privileges,
1666 relOid, grantorId, OBJECT_COLUMN,
1667 relname, attnum,
1668 NameStr(pg_attribute_tuple->attname));
1671 * Generate new ACL.
1673 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1674 istmt->grant_option,
1675 istmt->behavior, istmt->grantees,
1676 col_privileges, grantorId,
1677 ownerId);
1680 * We need the members of both old and new ACLs so we can correct the
1681 * shared dependency information.
1683 nnewmembers = aclmembers(new_acl, &newmembers);
1685 /* finished building new ACL value, now insert it */
1686 MemSet(values, 0, sizeof(values));
1687 MemSet(nulls, false, sizeof(nulls));
1688 MemSet(replaces, false, sizeof(replaces));
1691 * If the updated ACL is empty, we can set attacl to null, and maybe even
1692 * avoid an update of the pg_attribute row. This is worth testing because
1693 * we'll come through here multiple times for any relation-level REVOKE,
1694 * even if there were never any column GRANTs. Note we are assuming that
1695 * the "default" ACL state for columns is empty.
1697 if (ACL_NUM(new_acl) > 0)
1699 values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1700 need_update = true;
1702 else
1704 nulls[Anum_pg_attribute_attacl - 1] = true;
1705 need_update = !isNull;
1707 replaces[Anum_pg_attribute_attacl - 1] = true;
1709 if (need_update)
1711 newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1712 values, nulls, replaces);
1714 CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1716 /* Update initial privileges for extensions */
1717 recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1718 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1720 /* Update the shared dependency ACL info */
1721 updateAclDependencies(RelationRelationId, relOid, attnum,
1722 ownerId,
1723 noldmembers, oldmembers,
1724 nnewmembers, newmembers);
1727 pfree(new_acl);
1729 ReleaseSysCache(attr_tuple);
1733 * This processes both sequences and non-sequences.
1735 static void
1736 ExecGrant_Relation(InternalGrant *istmt)
1738 Relation relation;
1739 Relation attRelation;
1740 ListCell *cell;
1742 relation = table_open(RelationRelationId, RowExclusiveLock);
1743 attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1745 foreach(cell, istmt->objects)
1747 Oid relOid = lfirst_oid(cell);
1748 Datum aclDatum;
1749 Form_pg_class pg_class_tuple;
1750 bool isNull;
1751 AclMode this_privileges;
1752 AclMode *col_privileges;
1753 int num_col_privileges;
1754 bool have_col_privileges;
1755 Acl *old_acl;
1756 Acl *old_rel_acl;
1757 int noldmembers;
1758 Oid *oldmembers;
1759 Oid ownerId;
1760 HeapTuple tuple;
1761 ListCell *cell_colprivs;
1763 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1764 if (!HeapTupleIsValid(tuple))
1765 elog(ERROR, "cache lookup failed for relation %u", relOid);
1766 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1768 /* Not sensible to grant on an index */
1769 if (pg_class_tuple->relkind == RELKIND_INDEX ||
1770 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1771 ereport(ERROR,
1772 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1773 errmsg("\"%s\" is an index",
1774 NameStr(pg_class_tuple->relname))));
1776 /* Composite types aren't tables either */
1777 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1778 ereport(ERROR,
1779 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1780 errmsg("\"%s\" is a composite type",
1781 NameStr(pg_class_tuple->relname))));
1783 /* Used GRANT SEQUENCE on a non-sequence? */
1784 if (istmt->objtype == OBJECT_SEQUENCE &&
1785 pg_class_tuple->relkind != RELKIND_SEQUENCE)
1786 ereport(ERROR,
1787 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1788 errmsg("\"%s\" is not a sequence",
1789 NameStr(pg_class_tuple->relname))));
1791 /* Adjust the default permissions based on object type */
1792 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1794 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1795 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1796 else
1797 this_privileges = ACL_ALL_RIGHTS_RELATION;
1799 else
1800 this_privileges = istmt->privileges;
1803 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1804 * so we have to look at the relkind to determine the supported
1805 * permissions. The OR of table and sequence permissions were already
1806 * checked.
1808 if (istmt->objtype == OBJECT_TABLE)
1810 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1813 * For backward compatibility, just throw a warning for
1814 * invalid sequence permissions when using the non-sequence
1815 * GRANT syntax.
1817 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1820 * Mention the object name because the user needs to know
1821 * which operations succeeded. This is required because
1822 * WARNING allows the command to continue.
1824 ereport(WARNING,
1825 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1826 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1827 NameStr(pg_class_tuple->relname))));
1828 this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1831 else
1833 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1836 * USAGE is the only permission supported by sequences but
1837 * not by non-sequences. Don't mention the object name
1838 * because we didn't in the combined TABLE | SEQUENCE
1839 * check.
1841 ereport(ERROR,
1842 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1843 errmsg("invalid privilege type %s for table",
1844 "USAGE")));
1850 * Set up array in which we'll accumulate any column privilege bits
1851 * that need modification. The array is indexed such that entry [0]
1852 * corresponds to FirstLowInvalidHeapAttributeNumber.
1854 num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1855 col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1856 have_col_privileges = false;
1859 * If we are revoking relation privileges that are also column
1860 * privileges, we must implicitly revoke them from each column too,
1861 * per SQL spec. (We don't need to implicitly add column privileges
1862 * during GRANT because the permissions-checking code always checks
1863 * both relation and per-column privileges.)
1865 if (!istmt->is_grant &&
1866 (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1868 expand_all_col_privileges(relOid, pg_class_tuple,
1869 this_privileges & ACL_ALL_RIGHTS_COLUMN,
1870 col_privileges,
1871 num_col_privileges);
1872 have_col_privileges = true;
1876 * Get owner ID and working copy of existing ACL. If there's no ACL,
1877 * substitute the proper default.
1879 ownerId = pg_class_tuple->relowner;
1880 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1881 &isNull);
1882 if (isNull)
1884 switch (pg_class_tuple->relkind)
1886 case RELKIND_SEQUENCE:
1887 old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1888 break;
1889 default:
1890 old_acl = acldefault(OBJECT_TABLE, ownerId);
1891 break;
1893 /* There are no old member roles according to the catalogs */
1894 noldmembers = 0;
1895 oldmembers = NULL;
1897 else
1899 old_acl = DatumGetAclPCopy(aclDatum);
1900 /* Get the roles mentioned in the existing ACL */
1901 noldmembers = aclmembers(old_acl, &oldmembers);
1904 /* Need an extra copy of original rel ACL for column handling */
1905 old_rel_acl = aclcopy(old_acl);
1908 * Handle relation-level privileges, if any were specified
1910 if (this_privileges != ACL_NO_RIGHTS)
1912 AclMode avail_goptions;
1913 Acl *new_acl;
1914 Oid grantorId;
1915 HeapTuple newtuple;
1916 Datum values[Natts_pg_class];
1917 bool nulls[Natts_pg_class];
1918 bool replaces[Natts_pg_class];
1919 int nnewmembers;
1920 Oid *newmembers;
1921 ObjectType objtype;
1923 /* Determine ID to do the grant as, and available grant options */
1924 select_best_grantor(GetUserId(), this_privileges,
1925 old_acl, ownerId,
1926 &grantorId, &avail_goptions);
1928 switch (pg_class_tuple->relkind)
1930 case RELKIND_SEQUENCE:
1931 objtype = OBJECT_SEQUENCE;
1932 break;
1933 default:
1934 objtype = OBJECT_TABLE;
1935 break;
1939 * Restrict the privileges to what we can actually grant, and emit
1940 * the standards-mandated warning and error messages.
1942 this_privileges =
1943 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1944 istmt->all_privs, this_privileges,
1945 relOid, grantorId, objtype,
1946 NameStr(pg_class_tuple->relname),
1947 0, NULL);
1950 * Generate new ACL.
1952 new_acl = merge_acl_with_grant(old_acl,
1953 istmt->is_grant,
1954 istmt->grant_option,
1955 istmt->behavior,
1956 istmt->grantees,
1957 this_privileges,
1958 grantorId,
1959 ownerId);
1962 * We need the members of both old and new ACLs so we can correct
1963 * the shared dependency information.
1965 nnewmembers = aclmembers(new_acl, &newmembers);
1967 /* finished building new ACL value, now insert it */
1968 MemSet(values, 0, sizeof(values));
1969 MemSet(nulls, false, sizeof(nulls));
1970 MemSet(replaces, false, sizeof(replaces));
1972 replaces[Anum_pg_class_relacl - 1] = true;
1973 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
1975 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
1976 values, nulls, replaces);
1978 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1980 /* Update initial privileges for extensions */
1981 recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
1983 /* Update the shared dependency ACL info */
1984 updateAclDependencies(RelationRelationId, relOid, 0,
1985 ownerId,
1986 noldmembers, oldmembers,
1987 nnewmembers, newmembers);
1989 pfree(new_acl);
1993 * Handle column-level privileges, if any were specified or implied.
1994 * We first expand the user-specified column privileges into the
1995 * array, and then iterate over all nonempty array entries.
1997 foreach(cell_colprivs, istmt->col_privs)
1999 AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2001 if (col_privs->priv_name == NULL)
2002 this_privileges = ACL_ALL_RIGHTS_COLUMN;
2003 else
2004 this_privileges = string_to_privilege(col_privs->priv_name);
2006 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2007 ereport(ERROR,
2008 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2009 errmsg("invalid privilege type %s for column",
2010 privilege_to_string(this_privileges))));
2012 if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2013 this_privileges & ~((AclMode) ACL_SELECT))
2016 * The only column privilege allowed on sequences is SELECT.
2017 * This is a warning not error because we do it that way for
2018 * relation-level privileges.
2020 ereport(WARNING,
2021 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2022 errmsg("sequence \"%s\" only supports SELECT column privileges",
2023 NameStr(pg_class_tuple->relname))));
2025 this_privileges &= (AclMode) ACL_SELECT;
2028 expand_col_privileges(col_privs->cols, relOid,
2029 this_privileges,
2030 col_privileges,
2031 num_col_privileges);
2032 have_col_privileges = true;
2035 if (have_col_privileges)
2037 AttrNumber i;
2039 for (i = 0; i < num_col_privileges; i++)
2041 if (col_privileges[i] == ACL_NO_RIGHTS)
2042 continue;
2043 ExecGrant_Attribute(istmt,
2044 relOid,
2045 NameStr(pg_class_tuple->relname),
2046 i + FirstLowInvalidHeapAttributeNumber,
2047 ownerId,
2048 col_privileges[i],
2049 attRelation,
2050 old_rel_acl);
2054 pfree(old_rel_acl);
2055 pfree(col_privileges);
2057 ReleaseSysCache(tuple);
2059 /* prevent error when processing duplicate objects */
2060 CommandCounterIncrement();
2063 table_close(attRelation, RowExclusiveLock);
2064 table_close(relation, RowExclusiveLock);
2067 static void
2068 ExecGrant_Database(InternalGrant *istmt)
2070 Relation relation;
2071 ListCell *cell;
2073 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2074 istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
2076 relation = table_open(DatabaseRelationId, RowExclusiveLock);
2078 foreach(cell, istmt->objects)
2080 Oid datId = lfirst_oid(cell);
2081 Form_pg_database pg_database_tuple;
2082 Datum aclDatum;
2083 bool isNull;
2084 AclMode avail_goptions;
2085 AclMode this_privileges;
2086 Acl *old_acl;
2087 Acl *new_acl;
2088 Oid grantorId;
2089 Oid ownerId;
2090 HeapTuple newtuple;
2091 Datum values[Natts_pg_database];
2092 bool nulls[Natts_pg_database];
2093 bool replaces[Natts_pg_database];
2094 int noldmembers;
2095 int nnewmembers;
2096 Oid *oldmembers;
2097 Oid *newmembers;
2098 HeapTuple tuple;
2100 tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId));
2101 if (!HeapTupleIsValid(tuple))
2102 elog(ERROR, "cache lookup failed for database %u", datId);
2104 pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
2107 * Get owner ID and working copy of existing ACL. If there's no ACL,
2108 * substitute the proper default.
2110 ownerId = pg_database_tuple->datdba;
2111 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
2112 RelationGetDescr(relation), &isNull);
2113 if (isNull)
2115 old_acl = acldefault(OBJECT_DATABASE, ownerId);
2116 /* There are no old member roles according to the catalogs */
2117 noldmembers = 0;
2118 oldmembers = NULL;
2120 else
2122 old_acl = DatumGetAclPCopy(aclDatum);
2123 /* Get the roles mentioned in the existing ACL */
2124 noldmembers = aclmembers(old_acl, &oldmembers);
2127 /* Determine ID to do the grant as, and available grant options */
2128 select_best_grantor(GetUserId(), istmt->privileges,
2129 old_acl, ownerId,
2130 &grantorId, &avail_goptions);
2133 * Restrict the privileges to what we can actually grant, and emit the
2134 * standards-mandated warning and error messages.
2136 this_privileges =
2137 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2138 istmt->all_privs, istmt->privileges,
2139 datId, grantorId, OBJECT_DATABASE,
2140 NameStr(pg_database_tuple->datname),
2141 0, NULL);
2144 * Generate new ACL.
2146 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2147 istmt->grant_option, istmt->behavior,
2148 istmt->grantees, this_privileges,
2149 grantorId, ownerId);
2152 * We need the members of both old and new ACLs so we can correct the
2153 * shared dependency information.
2155 nnewmembers = aclmembers(new_acl, &newmembers);
2157 /* finished building new ACL value, now insert it */
2158 MemSet(values, 0, sizeof(values));
2159 MemSet(nulls, false, sizeof(nulls));
2160 MemSet(replaces, false, sizeof(replaces));
2162 replaces[Anum_pg_database_datacl - 1] = true;
2163 values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
2165 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2166 nulls, replaces);
2168 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2170 /* Update the shared dependency ACL info */
2171 updateAclDependencies(DatabaseRelationId, pg_database_tuple->oid, 0,
2172 ownerId,
2173 noldmembers, oldmembers,
2174 nnewmembers, newmembers);
2176 ReleaseSysCache(tuple);
2178 pfree(new_acl);
2180 /* prevent error when processing duplicate objects */
2181 CommandCounterIncrement();
2184 table_close(relation, RowExclusiveLock);
2187 static void
2188 ExecGrant_Fdw(InternalGrant *istmt)
2190 Relation relation;
2191 ListCell *cell;
2193 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2194 istmt->privileges = ACL_ALL_RIGHTS_FDW;
2196 relation = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
2198 foreach(cell, istmt->objects)
2200 Oid fdwid = lfirst_oid(cell);
2201 Form_pg_foreign_data_wrapper pg_fdw_tuple;
2202 Datum aclDatum;
2203 bool isNull;
2204 AclMode avail_goptions;
2205 AclMode this_privileges;
2206 Acl *old_acl;
2207 Acl *new_acl;
2208 Oid grantorId;
2209 Oid ownerId;
2210 HeapTuple tuple;
2211 HeapTuple newtuple;
2212 Datum values[Natts_pg_foreign_data_wrapper];
2213 bool nulls[Natts_pg_foreign_data_wrapper];
2214 bool replaces[Natts_pg_foreign_data_wrapper];
2215 int noldmembers;
2216 int nnewmembers;
2217 Oid *oldmembers;
2218 Oid *newmembers;
2220 tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
2221 ObjectIdGetDatum(fdwid));
2222 if (!HeapTupleIsValid(tuple))
2223 elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
2225 pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
2228 * Get owner ID and working copy of existing ACL. If there's no ACL,
2229 * substitute the proper default.
2231 ownerId = pg_fdw_tuple->fdwowner;
2232 aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
2233 Anum_pg_foreign_data_wrapper_fdwacl,
2234 &isNull);
2235 if (isNull)
2237 old_acl = acldefault(OBJECT_FDW, ownerId);
2238 /* There are no old member roles according to the catalogs */
2239 noldmembers = 0;
2240 oldmembers = NULL;
2242 else
2244 old_acl = DatumGetAclPCopy(aclDatum);
2245 /* Get the roles mentioned in the existing ACL */
2246 noldmembers = aclmembers(old_acl, &oldmembers);
2249 /* Determine ID to do the grant as, and available grant options */
2250 select_best_grantor(GetUserId(), istmt->privileges,
2251 old_acl, ownerId,
2252 &grantorId, &avail_goptions);
2255 * Restrict the privileges to what we can actually grant, and emit the
2256 * standards-mandated warning and error messages.
2258 this_privileges =
2259 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2260 istmt->all_privs, istmt->privileges,
2261 fdwid, grantorId, OBJECT_FDW,
2262 NameStr(pg_fdw_tuple->fdwname),
2263 0, NULL);
2266 * Generate new ACL.
2268 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2269 istmt->grant_option, istmt->behavior,
2270 istmt->grantees, this_privileges,
2271 grantorId, ownerId);
2274 * We need the members of both old and new ACLs so we can correct the
2275 * shared dependency information.
2277 nnewmembers = aclmembers(new_acl, &newmembers);
2279 /* finished building new ACL value, now insert it */
2280 MemSet(values, 0, sizeof(values));
2281 MemSet(nulls, false, sizeof(nulls));
2282 MemSet(replaces, false, sizeof(replaces));
2284 replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
2285 values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl);
2287 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2288 nulls, replaces);
2290 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2292 /* Update initial privileges for extensions */
2293 recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
2294 new_acl);
2296 /* Update the shared dependency ACL info */
2297 updateAclDependencies(ForeignDataWrapperRelationId,
2298 pg_fdw_tuple->oid, 0,
2299 ownerId,
2300 noldmembers, oldmembers,
2301 nnewmembers, newmembers);
2303 ReleaseSysCache(tuple);
2305 pfree(new_acl);
2307 /* prevent error when processing duplicate objects */
2308 CommandCounterIncrement();
2311 table_close(relation, RowExclusiveLock);
2314 static void
2315 ExecGrant_ForeignServer(InternalGrant *istmt)
2317 Relation relation;
2318 ListCell *cell;
2320 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2321 istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
2323 relation = table_open(ForeignServerRelationId, RowExclusiveLock);
2325 foreach(cell, istmt->objects)
2327 Oid srvid = lfirst_oid(cell);
2328 Form_pg_foreign_server pg_server_tuple;
2329 Datum aclDatum;
2330 bool isNull;
2331 AclMode avail_goptions;
2332 AclMode this_privileges;
2333 Acl *old_acl;
2334 Acl *new_acl;
2335 Oid grantorId;
2336 Oid ownerId;
2337 HeapTuple tuple;
2338 HeapTuple newtuple;
2339 Datum values[Natts_pg_foreign_server];
2340 bool nulls[Natts_pg_foreign_server];
2341 bool replaces[Natts_pg_foreign_server];
2342 int noldmembers;
2343 int nnewmembers;
2344 Oid *oldmembers;
2345 Oid *newmembers;
2347 tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid));
2348 if (!HeapTupleIsValid(tuple))
2349 elog(ERROR, "cache lookup failed for foreign server %u", srvid);
2351 pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple);
2354 * Get owner ID and working copy of existing ACL. If there's no ACL,
2355 * substitute the proper default.
2357 ownerId = pg_server_tuple->srvowner;
2358 aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
2359 Anum_pg_foreign_server_srvacl,
2360 &isNull);
2361 if (isNull)
2363 old_acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
2364 /* There are no old member roles according to the catalogs */
2365 noldmembers = 0;
2366 oldmembers = NULL;
2368 else
2370 old_acl = DatumGetAclPCopy(aclDatum);
2371 /* Get the roles mentioned in the existing ACL */
2372 noldmembers = aclmembers(old_acl, &oldmembers);
2375 /* Determine ID to do the grant as, and available grant options */
2376 select_best_grantor(GetUserId(), istmt->privileges,
2377 old_acl, ownerId,
2378 &grantorId, &avail_goptions);
2381 * Restrict the privileges to what we can actually grant, and emit the
2382 * standards-mandated warning and error messages.
2384 this_privileges =
2385 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2386 istmt->all_privs, istmt->privileges,
2387 srvid, grantorId, OBJECT_FOREIGN_SERVER,
2388 NameStr(pg_server_tuple->srvname),
2389 0, NULL);
2392 * Generate new ACL.
2394 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2395 istmt->grant_option, istmt->behavior,
2396 istmt->grantees, this_privileges,
2397 grantorId, ownerId);
2400 * We need the members of both old and new ACLs so we can correct the
2401 * shared dependency information.
2403 nnewmembers = aclmembers(new_acl, &newmembers);
2405 /* finished building new ACL value, now insert it */
2406 MemSet(values, 0, sizeof(values));
2407 MemSet(nulls, false, sizeof(nulls));
2408 MemSet(replaces, false, sizeof(replaces));
2410 replaces[Anum_pg_foreign_server_srvacl - 1] = true;
2411 values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl);
2413 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2414 nulls, replaces);
2416 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2418 /* Update initial privileges for extensions */
2419 recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
2421 /* Update the shared dependency ACL info */
2422 updateAclDependencies(ForeignServerRelationId,
2423 pg_server_tuple->oid, 0,
2424 ownerId,
2425 noldmembers, oldmembers,
2426 nnewmembers, newmembers);
2428 ReleaseSysCache(tuple);
2430 pfree(new_acl);
2432 /* prevent error when processing duplicate objects */
2433 CommandCounterIncrement();
2436 table_close(relation, RowExclusiveLock);
2439 static void
2440 ExecGrant_Function(InternalGrant *istmt)
2442 Relation relation;
2443 ListCell *cell;
2445 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2446 istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
2448 relation = table_open(ProcedureRelationId, RowExclusiveLock);
2450 foreach(cell, istmt->objects)
2452 Oid funcId = lfirst_oid(cell);
2453 Form_pg_proc pg_proc_tuple;
2454 Datum aclDatum;
2455 bool isNull;
2456 AclMode avail_goptions;
2457 AclMode this_privileges;
2458 Acl *old_acl;
2459 Acl *new_acl;
2460 Oid grantorId;
2461 Oid ownerId;
2462 HeapTuple tuple;
2463 HeapTuple newtuple;
2464 Datum values[Natts_pg_proc];
2465 bool nulls[Natts_pg_proc];
2466 bool replaces[Natts_pg_proc];
2467 int noldmembers;
2468 int nnewmembers;
2469 Oid *oldmembers;
2470 Oid *newmembers;
2472 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId));
2473 if (!HeapTupleIsValid(tuple))
2474 elog(ERROR, "cache lookup failed for function %u", funcId);
2476 pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
2479 * Get owner ID and working copy of existing ACL. If there's no ACL,
2480 * substitute the proper default.
2482 ownerId = pg_proc_tuple->proowner;
2483 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
2484 &isNull);
2485 if (isNull)
2487 old_acl = acldefault(OBJECT_FUNCTION, ownerId);
2488 /* There are no old member roles according to the catalogs */
2489 noldmembers = 0;
2490 oldmembers = NULL;
2492 else
2494 old_acl = DatumGetAclPCopy(aclDatum);
2495 /* Get the roles mentioned in the existing ACL */
2496 noldmembers = aclmembers(old_acl, &oldmembers);
2499 /* Determine ID to do the grant as, and available grant options */
2500 select_best_grantor(GetUserId(), istmt->privileges,
2501 old_acl, ownerId,
2502 &grantorId, &avail_goptions);
2505 * Restrict the privileges to what we can actually grant, and emit the
2506 * standards-mandated warning and error messages.
2508 this_privileges =
2509 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2510 istmt->all_privs, istmt->privileges,
2511 funcId, grantorId, OBJECT_FUNCTION,
2512 NameStr(pg_proc_tuple->proname),
2513 0, NULL);
2516 * Generate new ACL.
2518 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2519 istmt->grant_option, istmt->behavior,
2520 istmt->grantees, this_privileges,
2521 grantorId, ownerId);
2524 * We need the members of both old and new ACLs so we can correct the
2525 * shared dependency information.
2527 nnewmembers = aclmembers(new_acl, &newmembers);
2529 /* finished building new ACL value, now insert it */
2530 MemSet(values, 0, sizeof(values));
2531 MemSet(nulls, false, sizeof(nulls));
2532 MemSet(replaces, false, sizeof(replaces));
2534 replaces[Anum_pg_proc_proacl - 1] = true;
2535 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
2537 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2538 nulls, replaces);
2540 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2542 /* Update initial privileges for extensions */
2543 recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
2545 /* Update the shared dependency ACL info */
2546 updateAclDependencies(ProcedureRelationId, funcId, 0,
2547 ownerId,
2548 noldmembers, oldmembers,
2549 nnewmembers, newmembers);
2551 ReleaseSysCache(tuple);
2553 pfree(new_acl);
2555 /* prevent error when processing duplicate objects */
2556 CommandCounterIncrement();
2559 table_close(relation, RowExclusiveLock);
2562 static void
2563 ExecGrant_Language(InternalGrant *istmt)
2565 Relation relation;
2566 ListCell *cell;
2568 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2569 istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
2571 relation = table_open(LanguageRelationId, RowExclusiveLock);
2573 foreach(cell, istmt->objects)
2575 Oid langId = lfirst_oid(cell);
2576 Form_pg_language pg_language_tuple;
2577 Datum aclDatum;
2578 bool isNull;
2579 AclMode avail_goptions;
2580 AclMode this_privileges;
2581 Acl *old_acl;
2582 Acl *new_acl;
2583 Oid grantorId;
2584 Oid ownerId;
2585 HeapTuple tuple;
2586 HeapTuple newtuple;
2587 Datum values[Natts_pg_language];
2588 bool nulls[Natts_pg_language];
2589 bool replaces[Natts_pg_language];
2590 int noldmembers;
2591 int nnewmembers;
2592 Oid *oldmembers;
2593 Oid *newmembers;
2595 tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(langId));
2596 if (!HeapTupleIsValid(tuple))
2597 elog(ERROR, "cache lookup failed for language %u", langId);
2599 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2601 if (!pg_language_tuple->lanpltrusted)
2602 ereport(ERROR,
2603 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2604 errmsg("language \"%s\" is not trusted",
2605 NameStr(pg_language_tuple->lanname)),
2606 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2607 "because only superusers can use untrusted languages.")));
2610 * Get owner ID and working copy of existing ACL. If there's no ACL,
2611 * substitute the proper default.
2613 ownerId = pg_language_tuple->lanowner;
2614 aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
2615 &isNull);
2616 if (isNull)
2618 old_acl = acldefault(OBJECT_LANGUAGE, ownerId);
2619 /* There are no old member roles according to the catalogs */
2620 noldmembers = 0;
2621 oldmembers = NULL;
2623 else
2625 old_acl = DatumGetAclPCopy(aclDatum);
2626 /* Get the roles mentioned in the existing ACL */
2627 noldmembers = aclmembers(old_acl, &oldmembers);
2630 /* Determine ID to do the grant as, and available grant options */
2631 select_best_grantor(GetUserId(), istmt->privileges,
2632 old_acl, ownerId,
2633 &grantorId, &avail_goptions);
2636 * Restrict the privileges to what we can actually grant, and emit the
2637 * standards-mandated warning and error messages.
2639 this_privileges =
2640 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2641 istmt->all_privs, istmt->privileges,
2642 langId, grantorId, OBJECT_LANGUAGE,
2643 NameStr(pg_language_tuple->lanname),
2644 0, NULL);
2647 * Generate new ACL.
2649 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2650 istmt->grant_option, istmt->behavior,
2651 istmt->grantees, this_privileges,
2652 grantorId, ownerId);
2655 * We need the members of both old and new ACLs so we can correct the
2656 * shared dependency information.
2658 nnewmembers = aclmembers(new_acl, &newmembers);
2660 /* finished building new ACL value, now insert it */
2661 MemSet(values, 0, sizeof(values));
2662 MemSet(nulls, false, sizeof(nulls));
2663 MemSet(replaces, false, sizeof(replaces));
2665 replaces[Anum_pg_language_lanacl - 1] = true;
2666 values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
2668 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2669 nulls, replaces);
2671 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2673 /* Update initial privileges for extensions */
2674 recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
2676 /* Update the shared dependency ACL info */
2677 updateAclDependencies(LanguageRelationId, pg_language_tuple->oid, 0,
2678 ownerId,
2679 noldmembers, oldmembers,
2680 nnewmembers, newmembers);
2682 ReleaseSysCache(tuple);
2684 pfree(new_acl);
2686 /* prevent error when processing duplicate objects */
2687 CommandCounterIncrement();
2690 table_close(relation, RowExclusiveLock);
2693 static void
2694 ExecGrant_Largeobject(InternalGrant *istmt)
2696 Relation relation;
2697 ListCell *cell;
2699 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2700 istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
2702 relation = table_open(LargeObjectMetadataRelationId,
2703 RowExclusiveLock);
2705 foreach(cell, istmt->objects)
2707 Oid loid = lfirst_oid(cell);
2708 Form_pg_largeobject_metadata form_lo_meta;
2709 char loname[NAMEDATALEN];
2710 Datum aclDatum;
2711 bool isNull;
2712 AclMode avail_goptions;
2713 AclMode this_privileges;
2714 Acl *old_acl;
2715 Acl *new_acl;
2716 Oid grantorId;
2717 Oid ownerId;
2718 HeapTuple newtuple;
2719 Datum values[Natts_pg_largeobject_metadata];
2720 bool nulls[Natts_pg_largeobject_metadata];
2721 bool replaces[Natts_pg_largeobject_metadata];
2722 int noldmembers;
2723 int nnewmembers;
2724 Oid *oldmembers;
2725 Oid *newmembers;
2726 ScanKeyData entry[1];
2727 SysScanDesc scan;
2728 HeapTuple tuple;
2730 /* There's no syscache for pg_largeobject_metadata */
2731 ScanKeyInit(&entry[0],
2732 Anum_pg_largeobject_metadata_oid,
2733 BTEqualStrategyNumber, F_OIDEQ,
2734 ObjectIdGetDatum(loid));
2736 scan = systable_beginscan(relation,
2737 LargeObjectMetadataOidIndexId, true,
2738 NULL, 1, entry);
2740 tuple = systable_getnext(scan);
2741 if (!HeapTupleIsValid(tuple))
2742 elog(ERROR, "could not find tuple for large object %u", loid);
2744 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2747 * Get owner ID and working copy of existing ACL. If there's no ACL,
2748 * substitute the proper default.
2750 ownerId = form_lo_meta->lomowner;
2751 aclDatum = heap_getattr(tuple,
2752 Anum_pg_largeobject_metadata_lomacl,
2753 RelationGetDescr(relation), &isNull);
2754 if (isNull)
2756 old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2757 /* There are no old member roles according to the catalogs */
2758 noldmembers = 0;
2759 oldmembers = NULL;
2761 else
2763 old_acl = DatumGetAclPCopy(aclDatum);
2764 /* Get the roles mentioned in the existing ACL */
2765 noldmembers = aclmembers(old_acl, &oldmembers);
2768 /* Determine ID to do the grant as, and available grant options */
2769 select_best_grantor(GetUserId(), istmt->privileges,
2770 old_acl, ownerId,
2771 &grantorId, &avail_goptions);
2774 * Restrict the privileges to what we can actually grant, and emit the
2775 * standards-mandated warning and error messages.
2777 snprintf(loname, sizeof(loname), "large object %u", loid);
2778 this_privileges =
2779 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2780 istmt->all_privs, istmt->privileges,
2781 loid, grantorId, OBJECT_LARGEOBJECT,
2782 loname, 0, NULL);
2785 * Generate new ACL.
2787 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2788 istmt->grant_option, istmt->behavior,
2789 istmt->grantees, this_privileges,
2790 grantorId, ownerId);
2793 * We need the members of both old and new ACLs so we can correct the
2794 * shared dependency information.
2796 nnewmembers = aclmembers(new_acl, &newmembers);
2798 /* finished building new ACL value, now insert it */
2799 MemSet(values, 0, sizeof(values));
2800 MemSet(nulls, false, sizeof(nulls));
2801 MemSet(replaces, false, sizeof(replaces));
2803 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2804 values[Anum_pg_largeobject_metadata_lomacl - 1]
2805 = PointerGetDatum(new_acl);
2807 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2808 values, nulls, replaces);
2810 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2812 /* Update initial privileges for extensions */
2813 recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2815 /* Update the shared dependency ACL info */
2816 updateAclDependencies(LargeObjectRelationId,
2817 form_lo_meta->oid, 0,
2818 ownerId,
2819 noldmembers, oldmembers,
2820 nnewmembers, newmembers);
2822 systable_endscan(scan);
2824 pfree(new_acl);
2826 /* prevent error when processing duplicate objects */
2827 CommandCounterIncrement();
2830 table_close(relation, RowExclusiveLock);
2833 static void
2834 ExecGrant_Namespace(InternalGrant *istmt)
2836 Relation relation;
2837 ListCell *cell;
2839 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2840 istmt->privileges = ACL_ALL_RIGHTS_SCHEMA;
2842 relation = table_open(NamespaceRelationId, RowExclusiveLock);
2844 foreach(cell, istmt->objects)
2846 Oid nspid = lfirst_oid(cell);
2847 Form_pg_namespace pg_namespace_tuple;
2848 Datum aclDatum;
2849 bool isNull;
2850 AclMode avail_goptions;
2851 AclMode this_privileges;
2852 Acl *old_acl;
2853 Acl *new_acl;
2854 Oid grantorId;
2855 Oid ownerId;
2856 HeapTuple tuple;
2857 HeapTuple newtuple;
2858 Datum values[Natts_pg_namespace];
2859 bool nulls[Natts_pg_namespace];
2860 bool replaces[Natts_pg_namespace];
2861 int noldmembers;
2862 int nnewmembers;
2863 Oid *oldmembers;
2864 Oid *newmembers;
2866 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
2867 if (!HeapTupleIsValid(tuple))
2868 elog(ERROR, "cache lookup failed for namespace %u", nspid);
2870 pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
2873 * Get owner ID and working copy of existing ACL. If there's no ACL,
2874 * substitute the proper default.
2876 ownerId = pg_namespace_tuple->nspowner;
2877 aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
2878 Anum_pg_namespace_nspacl,
2879 &isNull);
2880 if (isNull)
2882 old_acl = acldefault(OBJECT_SCHEMA, ownerId);
2883 /* There are no old member roles according to the catalogs */
2884 noldmembers = 0;
2885 oldmembers = NULL;
2887 else
2889 old_acl = DatumGetAclPCopy(aclDatum);
2890 /* Get the roles mentioned in the existing ACL */
2891 noldmembers = aclmembers(old_acl, &oldmembers);
2894 /* Determine ID to do the grant as, and available grant options */
2895 select_best_grantor(GetUserId(), istmt->privileges,
2896 old_acl, ownerId,
2897 &grantorId, &avail_goptions);
2900 * Restrict the privileges to what we can actually grant, and emit the
2901 * standards-mandated warning and error messages.
2903 this_privileges =
2904 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2905 istmt->all_privs, istmt->privileges,
2906 nspid, grantorId, OBJECT_SCHEMA,
2907 NameStr(pg_namespace_tuple->nspname),
2908 0, NULL);
2911 * Generate new ACL.
2913 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2914 istmt->grant_option, istmt->behavior,
2915 istmt->grantees, this_privileges,
2916 grantorId, ownerId);
2919 * We need the members of both old and new ACLs so we can correct the
2920 * shared dependency information.
2922 nnewmembers = aclmembers(new_acl, &newmembers);
2924 /* finished building new ACL value, now insert it */
2925 MemSet(values, 0, sizeof(values));
2926 MemSet(nulls, false, sizeof(nulls));
2927 MemSet(replaces, false, sizeof(replaces));
2929 replaces[Anum_pg_namespace_nspacl - 1] = true;
2930 values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
2932 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2933 nulls, replaces);
2935 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2937 /* Update initial privileges for extensions */
2938 recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
2940 /* Update the shared dependency ACL info */
2941 updateAclDependencies(NamespaceRelationId, pg_namespace_tuple->oid, 0,
2942 ownerId,
2943 noldmembers, oldmembers,
2944 nnewmembers, newmembers);
2946 ReleaseSysCache(tuple);
2948 pfree(new_acl);
2950 /* prevent error when processing duplicate objects */
2951 CommandCounterIncrement();
2954 table_close(relation, RowExclusiveLock);
2957 static void
2958 ExecGrant_Tablespace(InternalGrant *istmt)
2960 Relation relation;
2961 ListCell *cell;
2963 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2964 istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
2966 relation = table_open(TableSpaceRelationId, RowExclusiveLock);
2968 foreach(cell, istmt->objects)
2970 Oid tblId = lfirst_oid(cell);
2971 Form_pg_tablespace pg_tablespace_tuple;
2972 Datum aclDatum;
2973 bool isNull;
2974 AclMode avail_goptions;
2975 AclMode this_privileges;
2976 Acl *old_acl;
2977 Acl *new_acl;
2978 Oid grantorId;
2979 Oid ownerId;
2980 HeapTuple newtuple;
2981 Datum values[Natts_pg_tablespace];
2982 bool nulls[Natts_pg_tablespace];
2983 bool replaces[Natts_pg_tablespace];
2984 int noldmembers;
2985 int nnewmembers;
2986 Oid *oldmembers;
2987 Oid *newmembers;
2988 HeapTuple tuple;
2990 /* Search syscache for pg_tablespace */
2991 tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId));
2992 if (!HeapTupleIsValid(tuple))
2993 elog(ERROR, "cache lookup failed for tablespace %u", tblId);
2995 pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
2998 * Get owner ID and working copy of existing ACL. If there's no ACL,
2999 * substitute the proper default.
3001 ownerId = pg_tablespace_tuple->spcowner;
3002 aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
3003 RelationGetDescr(relation), &isNull);
3004 if (isNull)
3006 old_acl = acldefault(OBJECT_TABLESPACE, ownerId);
3007 /* There are no old member roles according to the catalogs */
3008 noldmembers = 0;
3009 oldmembers = NULL;
3011 else
3013 old_acl = DatumGetAclPCopy(aclDatum);
3014 /* Get the roles mentioned in the existing ACL */
3015 noldmembers = aclmembers(old_acl, &oldmembers);
3018 /* Determine ID to do the grant as, and available grant options */
3019 select_best_grantor(GetUserId(), istmt->privileges,
3020 old_acl, ownerId,
3021 &grantorId, &avail_goptions);
3024 * Restrict the privileges to what we can actually grant, and emit the
3025 * standards-mandated warning and error messages.
3027 this_privileges =
3028 restrict_and_check_grant(istmt->is_grant, avail_goptions,
3029 istmt->all_privs, istmt->privileges,
3030 tblId, grantorId, OBJECT_TABLESPACE,
3031 NameStr(pg_tablespace_tuple->spcname),
3032 0, NULL);
3035 * Generate new ACL.
3037 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
3038 istmt->grant_option, istmt->behavior,
3039 istmt->grantees, this_privileges,
3040 grantorId, ownerId);
3043 * We need the members of both old and new ACLs so we can correct the
3044 * shared dependency information.
3046 nnewmembers = aclmembers(new_acl, &newmembers);
3048 /* finished building new ACL value, now insert it */
3049 MemSet(values, 0, sizeof(values));
3050 MemSet(nulls, false, sizeof(nulls));
3051 MemSet(replaces, false, sizeof(replaces));
3053 replaces[Anum_pg_tablespace_spcacl - 1] = true;
3054 values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
3056 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
3057 nulls, replaces);
3059 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
3061 /* Update the shared dependency ACL info */
3062 updateAclDependencies(TableSpaceRelationId, tblId, 0,
3063 ownerId,
3064 noldmembers, oldmembers,
3065 nnewmembers, newmembers);
3067 ReleaseSysCache(tuple);
3068 pfree(new_acl);
3070 /* prevent error when processing duplicate objects */
3071 CommandCounterIncrement();
3074 table_close(relation, RowExclusiveLock);
3077 static void
3078 ExecGrant_Type(InternalGrant *istmt)
3080 Relation relation;
3081 ListCell *cell;
3083 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
3084 istmt->privileges = ACL_ALL_RIGHTS_TYPE;
3086 relation = table_open(TypeRelationId, RowExclusiveLock);
3088 foreach(cell, istmt->objects)
3090 Oid typId = lfirst_oid(cell);
3091 Form_pg_type pg_type_tuple;
3092 Datum aclDatum;
3093 bool isNull;
3094 AclMode avail_goptions;
3095 AclMode this_privileges;
3096 Acl *old_acl;
3097 Acl *new_acl;
3098 Oid grantorId;
3099 Oid ownerId;
3100 HeapTuple newtuple;
3101 Datum values[Natts_pg_type];
3102 bool nulls[Natts_pg_type];
3103 bool replaces[Natts_pg_type];
3104 int noldmembers;
3105 int nnewmembers;
3106 Oid *oldmembers;
3107 Oid *newmembers;
3108 HeapTuple tuple;
3110 /* Search syscache for pg_type */
3111 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typId));
3112 if (!HeapTupleIsValid(tuple))
3113 elog(ERROR, "cache lookup failed for type %u", typId);
3115 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
3117 if (pg_type_tuple->typelem != 0 && pg_type_tuple->typlen == -1)
3118 ereport(ERROR,
3119 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
3120 errmsg("cannot set privileges of array types"),
3121 errhint("Set the privileges of the element type instead.")));
3123 /* Used GRANT DOMAIN on a non-domain? */
3124 if (istmt->objtype == OBJECT_DOMAIN &&
3125 pg_type_tuple->typtype != TYPTYPE_DOMAIN)
3126 ereport(ERROR,
3127 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3128 errmsg("\"%s\" is not a domain",
3129 NameStr(pg_type_tuple->typname))));
3132 * Get owner ID and working copy of existing ACL. If there's no ACL,
3133 * substitute the proper default.
3135 ownerId = pg_type_tuple->typowner;
3136 aclDatum = heap_getattr(tuple, Anum_pg_type_typacl,
3137 RelationGetDescr(relation), &isNull);
3138 if (isNull)
3140 old_acl = acldefault(istmt->objtype, ownerId);
3141 /* There are no old member roles according to the catalogs */
3142 noldmembers = 0;
3143 oldmembers = NULL;
3145 else
3147 old_acl = DatumGetAclPCopy(aclDatum);
3148 /* Get the roles mentioned in the existing ACL */
3149 noldmembers = aclmembers(old_acl, &oldmembers);
3152 /* Determine ID to do the grant as, and available grant options */
3153 select_best_grantor(GetUserId(), istmt->privileges,
3154 old_acl, ownerId,
3155 &grantorId, &avail_goptions);
3158 * Restrict the privileges to what we can actually grant, and emit the
3159 * standards-mandated warning and error messages.
3161 this_privileges =
3162 restrict_and_check_grant(istmt->is_grant, avail_goptions,
3163 istmt->all_privs, istmt->privileges,
3164 typId, grantorId, OBJECT_TYPE,
3165 NameStr(pg_type_tuple->typname),
3166 0, NULL);
3169 * Generate new ACL.
3171 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
3172 istmt->grant_option, istmt->behavior,
3173 istmt->grantees, this_privileges,
3174 grantorId, ownerId);
3177 * We need the members of both old and new ACLs so we can correct the
3178 * shared dependency information.
3180 nnewmembers = aclmembers(new_acl, &newmembers);
3182 /* finished building new ACL value, now insert it */
3183 MemSet(values, 0, sizeof(values));
3184 MemSet(nulls, false, sizeof(nulls));
3185 MemSet(replaces, false, sizeof(replaces));
3187 replaces[Anum_pg_type_typacl - 1] = true;
3188 values[Anum_pg_type_typacl - 1] = PointerGetDatum(new_acl);
3190 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
3191 nulls, replaces);
3193 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
3195 /* Update initial privileges for extensions */
3196 recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
3198 /* Update the shared dependency ACL info */
3199 updateAclDependencies(TypeRelationId, typId, 0,
3200 ownerId,
3201 noldmembers, oldmembers,
3202 nnewmembers, newmembers);
3204 ReleaseSysCache(tuple);
3205 pfree(new_acl);
3207 /* prevent error when processing duplicate objects */
3208 CommandCounterIncrement();
3211 table_close(relation, RowExclusiveLock);
3215 static AclMode
3216 string_to_privilege(const char *privname)
3218 if (strcmp(privname, "insert") == 0)
3219 return ACL_INSERT;
3220 if (strcmp(privname, "select") == 0)
3221 return ACL_SELECT;
3222 if (strcmp(privname, "update") == 0)
3223 return ACL_UPDATE;
3224 if (strcmp(privname, "delete") == 0)
3225 return ACL_DELETE;
3226 if (strcmp(privname, "truncate") == 0)
3227 return ACL_TRUNCATE;
3228 if (strcmp(privname, "references") == 0)
3229 return ACL_REFERENCES;
3230 if (strcmp(privname, "trigger") == 0)
3231 return ACL_TRIGGER;
3232 if (strcmp(privname, "execute") == 0)
3233 return ACL_EXECUTE;
3234 if (strcmp(privname, "usage") == 0)
3235 return ACL_USAGE;
3236 if (strcmp(privname, "create") == 0)
3237 return ACL_CREATE;
3238 if (strcmp(privname, "temporary") == 0)
3239 return ACL_CREATE_TEMP;
3240 if (strcmp(privname, "temp") == 0)
3241 return ACL_CREATE_TEMP;
3242 if (strcmp(privname, "connect") == 0)
3243 return ACL_CONNECT;
3244 if (strcmp(privname, "rule") == 0)
3245 return 0; /* ignore old RULE privileges */
3246 ereport(ERROR,
3247 (errcode(ERRCODE_SYNTAX_ERROR),
3248 errmsg("unrecognized privilege type \"%s\"", privname)));
3249 return 0; /* appease compiler */
3252 static const char *
3253 privilege_to_string(AclMode privilege)
3255 switch (privilege)
3257 case ACL_INSERT:
3258 return "INSERT";
3259 case ACL_SELECT:
3260 return "SELECT";
3261 case ACL_UPDATE:
3262 return "UPDATE";
3263 case ACL_DELETE:
3264 return "DELETE";
3265 case ACL_TRUNCATE:
3266 return "TRUNCATE";
3267 case ACL_REFERENCES:
3268 return "REFERENCES";
3269 case ACL_TRIGGER:
3270 return "TRIGGER";
3271 case ACL_EXECUTE:
3272 return "EXECUTE";
3273 case ACL_USAGE:
3274 return "USAGE";
3275 case ACL_CREATE:
3276 return "CREATE";
3277 case ACL_CREATE_TEMP:
3278 return "TEMP";
3279 case ACL_CONNECT:
3280 return "CONNECT";
3281 default:
3282 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
3284 return NULL; /* appease compiler */
3288 * Standardized reporting of aclcheck permissions failures.
3290 * Note: we do not double-quote the %s's below, because many callers
3291 * supply strings that might be already quoted.
3293 void
3294 aclcheck_error(AclResult aclerr, ObjectType objtype,
3295 const char *objectname)
3297 switch (aclerr)
3299 case ACLCHECK_OK:
3300 /* no error, so return to caller */
3301 break;
3302 case ACLCHECK_NO_PRIV:
3304 const char *msg = "???";
3306 switch (objtype)
3308 case OBJECT_AGGREGATE:
3309 msg = gettext_noop("permission denied for aggregate %s");
3310 break;
3311 case OBJECT_COLLATION:
3312 msg = gettext_noop("permission denied for collation %s");
3313 break;
3314 case OBJECT_COLUMN:
3315 msg = gettext_noop("permission denied for column %s");
3316 break;
3317 case OBJECT_CONVERSION:
3318 msg = gettext_noop("permission denied for conversion %s");
3319 break;
3320 case OBJECT_DATABASE:
3321 msg = gettext_noop("permission denied for database %s");
3322 break;
3323 case OBJECT_DOMAIN:
3324 msg = gettext_noop("permission denied for domain %s");
3325 break;
3326 case OBJECT_EVENT_TRIGGER:
3327 msg = gettext_noop("permission denied for event trigger %s");
3328 break;
3329 case OBJECT_EXTENSION:
3330 msg = gettext_noop("permission denied for extension %s");
3331 break;
3332 case OBJECT_FDW:
3333 msg = gettext_noop("permission denied for foreign-data wrapper %s");
3334 break;
3335 case OBJECT_FOREIGN_SERVER:
3336 msg = gettext_noop("permission denied for foreign server %s");
3337 break;
3338 case OBJECT_FOREIGN_TABLE:
3339 msg = gettext_noop("permission denied for foreign table %s");
3340 break;
3341 case OBJECT_FUNCTION:
3342 msg = gettext_noop("permission denied for function %s");
3343 break;
3344 case OBJECT_INDEX:
3345 msg = gettext_noop("permission denied for index %s");
3346 break;
3347 case OBJECT_LANGUAGE:
3348 msg = gettext_noop("permission denied for language %s");
3349 break;
3350 case OBJECT_LARGEOBJECT:
3351 msg = gettext_noop("permission denied for large object %s");
3352 break;
3353 case OBJECT_MATVIEW:
3354 msg = gettext_noop("permission denied for materialized view %s");
3355 break;
3356 case OBJECT_OPCLASS:
3357 msg = gettext_noop("permission denied for operator class %s");
3358 break;
3359 case OBJECT_OPERATOR:
3360 msg = gettext_noop("permission denied for operator %s");
3361 break;
3362 case OBJECT_OPFAMILY:
3363 msg = gettext_noop("permission denied for operator family %s");
3364 break;
3365 case OBJECT_POLICY:
3366 msg = gettext_noop("permission denied for policy %s");
3367 break;
3368 case OBJECT_PROCEDURE:
3369 msg = gettext_noop("permission denied for procedure %s");
3370 break;
3371 case OBJECT_PUBLICATION:
3372 msg = gettext_noop("permission denied for publication %s");
3373 break;
3374 case OBJECT_ROUTINE:
3375 msg = gettext_noop("permission denied for routine %s");
3376 break;
3377 case OBJECT_SCHEMA:
3378 msg = gettext_noop("permission denied for schema %s");
3379 break;
3380 case OBJECT_SEQUENCE:
3381 msg = gettext_noop("permission denied for sequence %s");
3382 break;
3383 case OBJECT_STATISTIC_EXT:
3384 msg = gettext_noop("permission denied for statistics object %s");
3385 break;
3386 case OBJECT_SUBSCRIPTION:
3387 msg = gettext_noop("permission denied for subscription %s");
3388 break;
3389 case OBJECT_TABLE:
3390 msg = gettext_noop("permission denied for table %s");
3391 break;
3392 case OBJECT_TABLESPACE:
3393 msg = gettext_noop("permission denied for tablespace %s");
3394 break;
3395 case OBJECT_TSCONFIGURATION:
3396 msg = gettext_noop("permission denied for text search configuration %s");
3397 break;
3398 case OBJECT_TSDICTIONARY:
3399 msg = gettext_noop("permission denied for text search dictionary %s");
3400 break;
3401 case OBJECT_TYPE:
3402 msg = gettext_noop("permission denied for type %s");
3403 break;
3404 case OBJECT_VIEW:
3405 msg = gettext_noop("permission denied for view %s");
3406 break;
3407 /* these currently aren't used */
3408 case OBJECT_ACCESS_METHOD:
3409 case OBJECT_AMOP:
3410 case OBJECT_AMPROC:
3411 case OBJECT_ATTRIBUTE:
3412 case OBJECT_CAST:
3413 case OBJECT_DEFAULT:
3414 case OBJECT_DEFACL:
3415 case OBJECT_DOMCONSTRAINT:
3416 case OBJECT_PUBLICATION_REL:
3417 case OBJECT_ROLE:
3418 case OBJECT_RULE:
3419 case OBJECT_TABCONSTRAINT:
3420 case OBJECT_TRANSFORM:
3421 case OBJECT_TRIGGER:
3422 case OBJECT_TSPARSER:
3423 case OBJECT_TSTEMPLATE:
3424 case OBJECT_USER_MAPPING:
3425 elog(ERROR, "unsupported object type %d", objtype);
3428 ereport(ERROR,
3429 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3430 errmsg(msg, objectname)));
3431 break;
3433 case ACLCHECK_NOT_OWNER:
3435 const char *msg = "???";
3437 switch (objtype)
3439 case OBJECT_AGGREGATE:
3440 msg = gettext_noop("must be owner of aggregate %s");
3441 break;
3442 case OBJECT_COLLATION:
3443 msg = gettext_noop("must be owner of collation %s");
3444 break;
3445 case OBJECT_CONVERSION:
3446 msg = gettext_noop("must be owner of conversion %s");
3447 break;
3448 case OBJECT_DATABASE:
3449 msg = gettext_noop("must be owner of database %s");
3450 break;
3451 case OBJECT_DOMAIN:
3452 msg = gettext_noop("must be owner of domain %s");
3453 break;
3454 case OBJECT_EVENT_TRIGGER:
3455 msg = gettext_noop("must be owner of event trigger %s");
3456 break;
3457 case OBJECT_EXTENSION:
3458 msg = gettext_noop("must be owner of extension %s");
3459 break;
3460 case OBJECT_FDW:
3461 msg = gettext_noop("must be owner of foreign-data wrapper %s");
3462 break;
3463 case OBJECT_FOREIGN_SERVER:
3464 msg = gettext_noop("must be owner of foreign server %s");
3465 break;
3466 case OBJECT_FOREIGN_TABLE:
3467 msg = gettext_noop("must be owner of foreign table %s");
3468 break;
3469 case OBJECT_FUNCTION:
3470 msg = gettext_noop("must be owner of function %s");
3471 break;
3472 case OBJECT_INDEX:
3473 msg = gettext_noop("must be owner of index %s");
3474 break;
3475 case OBJECT_LANGUAGE:
3476 msg = gettext_noop("must be owner of language %s");
3477 break;
3478 case OBJECT_LARGEOBJECT:
3479 msg = gettext_noop("must be owner of large object %s");
3480 break;
3481 case OBJECT_MATVIEW:
3482 msg = gettext_noop("must be owner of materialized view %s");
3483 break;
3484 case OBJECT_OPCLASS:
3485 msg = gettext_noop("must be owner of operator class %s");
3486 break;
3487 case OBJECT_OPERATOR:
3488 msg = gettext_noop("must be owner of operator %s");
3489 break;
3490 case OBJECT_OPFAMILY:
3491 msg = gettext_noop("must be owner of operator family %s");
3492 break;
3493 case OBJECT_PROCEDURE:
3494 msg = gettext_noop("must be owner of procedure %s");
3495 break;
3496 case OBJECT_PUBLICATION:
3497 msg = gettext_noop("must be owner of publication %s");
3498 break;
3499 case OBJECT_ROUTINE:
3500 msg = gettext_noop("must be owner of routine %s");
3501 break;
3502 case OBJECT_SEQUENCE:
3503 msg = gettext_noop("must be owner of sequence %s");
3504 break;
3505 case OBJECT_SUBSCRIPTION:
3506 msg = gettext_noop("must be owner of subscription %s");
3507 break;
3508 case OBJECT_TABLE:
3509 msg = gettext_noop("must be owner of table %s");
3510 break;
3511 case OBJECT_TYPE:
3512 msg = gettext_noop("must be owner of type %s");
3513 break;
3514 case OBJECT_VIEW:
3515 msg = gettext_noop("must be owner of view %s");
3516 break;
3517 case OBJECT_SCHEMA:
3518 msg = gettext_noop("must be owner of schema %s");
3519 break;
3520 case OBJECT_STATISTIC_EXT:
3521 msg = gettext_noop("must be owner of statistics object %s");
3522 break;
3523 case OBJECT_TABLESPACE:
3524 msg = gettext_noop("must be owner of tablespace %s");
3525 break;
3526 case OBJECT_TSCONFIGURATION:
3527 msg = gettext_noop("must be owner of text search configuration %s");
3528 break;
3529 case OBJECT_TSDICTIONARY:
3530 msg = gettext_noop("must be owner of text search dictionary %s");
3531 break;
3534 * Special cases: For these, the error message talks
3535 * about "relation", because that's where the
3536 * ownership is attached. See also
3537 * check_object_ownership().
3539 case OBJECT_COLUMN:
3540 case OBJECT_POLICY:
3541 case OBJECT_RULE:
3542 case OBJECT_TABCONSTRAINT:
3543 case OBJECT_TRIGGER:
3544 msg = gettext_noop("must be owner of relation %s");
3545 break;
3546 /* these currently aren't used */
3547 case OBJECT_ACCESS_METHOD:
3548 case OBJECT_AMOP:
3549 case OBJECT_AMPROC:
3550 case OBJECT_ATTRIBUTE:
3551 case OBJECT_CAST:
3552 case OBJECT_DEFAULT:
3553 case OBJECT_DEFACL:
3554 case OBJECT_DOMCONSTRAINT:
3555 case OBJECT_PUBLICATION_REL:
3556 case OBJECT_ROLE:
3557 case OBJECT_TRANSFORM:
3558 case OBJECT_TSPARSER:
3559 case OBJECT_TSTEMPLATE:
3560 case OBJECT_USER_MAPPING:
3561 elog(ERROR, "unsupported object type %d", objtype);
3564 ereport(ERROR,
3565 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3566 errmsg(msg, objectname)));
3567 break;
3569 default:
3570 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3571 break;
3576 void
3577 aclcheck_error_col(AclResult aclerr, ObjectType objtype,
3578 const char *objectname, const char *colname)
3580 switch (aclerr)
3582 case ACLCHECK_OK:
3583 /* no error, so return to caller */
3584 break;
3585 case ACLCHECK_NO_PRIV:
3586 ereport(ERROR,
3587 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3588 errmsg("permission denied for column \"%s\" of relation \"%s\"",
3589 colname, objectname)));
3590 break;
3591 case ACLCHECK_NOT_OWNER:
3592 /* relation msg is OK since columns don't have separate owners */
3593 aclcheck_error(aclerr, objtype, objectname);
3594 break;
3595 default:
3596 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3597 break;
3603 * Special common handling for types: use element type instead of array type,
3604 * and format nicely
3606 void
3607 aclcheck_error_type(AclResult aclerr, Oid typeOid)
3609 Oid element_type = get_element_type(typeOid);
3611 aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
3616 * Relay for the various pg_*_mask routines depending on object kind
3618 static AclMode
3619 pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid,
3620 AclMode mask, AclMaskHow how)
3622 switch (objtype)
3624 case OBJECT_COLUMN:
3625 return
3626 pg_class_aclmask(table_oid, roleid, mask, how) |
3627 pg_attribute_aclmask(table_oid, attnum, roleid, mask, how);
3628 case OBJECT_TABLE:
3629 case OBJECT_SEQUENCE:
3630 return pg_class_aclmask(table_oid, roleid, mask, how);
3631 case OBJECT_DATABASE:
3632 return pg_database_aclmask(table_oid, roleid, mask, how);
3633 case OBJECT_FUNCTION:
3634 return pg_proc_aclmask(table_oid, roleid, mask, how);
3635 case OBJECT_LANGUAGE:
3636 return pg_language_aclmask(table_oid, roleid, mask, how);
3637 case OBJECT_LARGEOBJECT:
3638 return pg_largeobject_aclmask_snapshot(table_oid, roleid,
3639 mask, how, NULL);
3640 case OBJECT_SCHEMA:
3641 return pg_namespace_aclmask(table_oid, roleid, mask, how);
3642 case OBJECT_STATISTIC_EXT:
3643 elog(ERROR, "grantable rights not supported for statistics objects");
3644 /* not reached, but keep compiler quiet */
3645 return ACL_NO_RIGHTS;
3646 case OBJECT_TABLESPACE:
3647 return pg_tablespace_aclmask(table_oid, roleid, mask, how);
3648 case OBJECT_FDW:
3649 return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
3650 case OBJECT_FOREIGN_SERVER:
3651 return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
3652 case OBJECT_EVENT_TRIGGER:
3653 elog(ERROR, "grantable rights not supported for event triggers");
3654 /* not reached, but keep compiler quiet */
3655 return ACL_NO_RIGHTS;
3656 case OBJECT_TYPE:
3657 return pg_type_aclmask(table_oid, roleid, mask, how);
3658 default:
3659 elog(ERROR, "unrecognized objtype: %d",
3660 (int) objtype);
3661 /* not reached, but keep compiler quiet */
3662 return ACL_NO_RIGHTS;
3667 /* ****************************************************************
3668 * Exported routines for examining a user's privileges for various objects
3670 * See aclmask() for a description of the common API for these functions.
3672 * Note: we give lookup failure the full ereport treatment because the
3673 * has_xxx_privilege() family of functions allow users to pass any random
3674 * OID to these functions.
3675 * ****************************************************************
3679 * Exported routine for examining a user's privileges for a column
3681 * Note: this considers only privileges granted specifically on the column.
3682 * It is caller's responsibility to take relation-level privileges into account
3683 * as appropriate. (For the same reason, we have no special case for
3684 * superuser-ness here.)
3686 AclMode
3687 pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
3688 AclMode mask, AclMaskHow how)
3690 AclMode result;
3691 HeapTuple classTuple;
3692 HeapTuple attTuple;
3693 Form_pg_class classForm;
3694 Form_pg_attribute attributeForm;
3695 Datum aclDatum;
3696 bool isNull;
3697 Acl *acl;
3698 Oid ownerId;
3701 * First, get the column's ACL from its pg_attribute entry
3703 attTuple = SearchSysCache2(ATTNUM,
3704 ObjectIdGetDatum(table_oid),
3705 Int16GetDatum(attnum));
3706 if (!HeapTupleIsValid(attTuple))
3707 ereport(ERROR,
3708 (errcode(ERRCODE_UNDEFINED_COLUMN),
3709 errmsg("attribute %d of relation with OID %u does not exist",
3710 attnum, table_oid)));
3711 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3713 /* Throw error on dropped columns, too */
3714 if (attributeForm->attisdropped)
3715 ereport(ERROR,
3716 (errcode(ERRCODE_UNDEFINED_COLUMN),
3717 errmsg("attribute %d of relation with OID %u does not exist",
3718 attnum, table_oid)));
3720 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3721 &isNull);
3724 * Here we hard-wire knowledge that the default ACL for a column grants no
3725 * privileges, so that we can fall out quickly in the very common case
3726 * where attacl is null.
3728 if (isNull)
3730 ReleaseSysCache(attTuple);
3731 return 0;
3735 * Must get the relation's ownerId from pg_class. Since we already found
3736 * a pg_attribute entry, the only likely reason for this to fail is that a
3737 * concurrent DROP of the relation committed since then (which could only
3738 * happen if we don't have lock on the relation). We prefer to report "no
3739 * privileges" rather than failing in such a case, so as to avoid unwanted
3740 * failures in has_column_privilege() tests.
3742 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3743 if (!HeapTupleIsValid(classTuple))
3745 ReleaseSysCache(attTuple);
3746 return 0;
3748 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3750 ownerId = classForm->relowner;
3752 ReleaseSysCache(classTuple);
3754 /* detoast column's ACL if necessary */
3755 acl = DatumGetAclP(aclDatum);
3757 result = aclmask(acl, roleid, ownerId, mask, how);
3759 /* if we have a detoasted copy, free it */
3760 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3761 pfree(acl);
3763 ReleaseSysCache(attTuple);
3765 return result;
3769 * Exported routine for examining a user's privileges for a table
3771 AclMode
3772 pg_class_aclmask(Oid table_oid, Oid roleid,
3773 AclMode mask, AclMaskHow how)
3775 AclMode result;
3776 HeapTuple tuple;
3777 Form_pg_class classForm;
3778 Datum aclDatum;
3779 bool isNull;
3780 Acl *acl;
3781 Oid ownerId;
3784 * Must get the relation's tuple from pg_class
3786 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3787 if (!HeapTupleIsValid(tuple))
3788 ereport(ERROR,
3789 (errcode(ERRCODE_UNDEFINED_TABLE),
3790 errmsg("relation with OID %u does not exist",
3791 table_oid)));
3792 classForm = (Form_pg_class) GETSTRUCT(tuple);
3795 * Deny anyone permission to update a system catalog unless
3796 * pg_authid.rolsuper is set.
3798 * As of 7.4 we have some updatable system views; those shouldn't be
3799 * protected in this way. Assume the view rules can take care of
3800 * themselves. ACL_USAGE is if we ever have system sequences.
3802 if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3803 IsSystemClass(table_oid, classForm) &&
3804 classForm->relkind != RELKIND_VIEW &&
3805 !superuser_arg(roleid))
3806 mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
3809 * Otherwise, superusers bypass all permission-checking.
3811 if (superuser_arg(roleid))
3813 ReleaseSysCache(tuple);
3814 return mask;
3818 * Normal case: get the relation's ACL from pg_class
3820 ownerId = classForm->relowner;
3822 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3823 &isNull);
3824 if (isNull)
3826 /* No ACL, so build default ACL */
3827 switch (classForm->relkind)
3829 case RELKIND_SEQUENCE:
3830 acl = acldefault(OBJECT_SEQUENCE, ownerId);
3831 break;
3832 default:
3833 acl = acldefault(OBJECT_TABLE, ownerId);
3834 break;
3836 aclDatum = (Datum) 0;
3838 else
3840 /* detoast rel's ACL if necessary */
3841 acl = DatumGetAclP(aclDatum);
3844 result = aclmask(acl, roleid, ownerId, mask, how);
3846 /* if we have a detoasted copy, free it */
3847 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3848 pfree(acl);
3850 ReleaseSysCache(tuple);
3852 return result;
3856 * Exported routine for examining a user's privileges for a database
3858 AclMode
3859 pg_database_aclmask(Oid db_oid, Oid roleid,
3860 AclMode mask, AclMaskHow how)
3862 AclMode result;
3863 HeapTuple tuple;
3864 Datum aclDatum;
3865 bool isNull;
3866 Acl *acl;
3867 Oid ownerId;
3869 /* Superusers bypass all permission checking. */
3870 if (superuser_arg(roleid))
3871 return mask;
3874 * Get the database's ACL from pg_database
3876 tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
3877 if (!HeapTupleIsValid(tuple))
3878 ereport(ERROR,
3879 (errcode(ERRCODE_UNDEFINED_DATABASE),
3880 errmsg("database with OID %u does not exist", db_oid)));
3882 ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
3884 aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
3885 &isNull);
3886 if (isNull)
3888 /* No ACL, so build default ACL */
3889 acl = acldefault(OBJECT_DATABASE, ownerId);
3890 aclDatum = (Datum) 0;
3892 else
3894 /* detoast ACL if necessary */
3895 acl = DatumGetAclP(aclDatum);
3898 result = aclmask(acl, roleid, ownerId, mask, how);
3900 /* if we have a detoasted copy, free it */
3901 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3902 pfree(acl);
3904 ReleaseSysCache(tuple);
3906 return result;
3910 * Exported routine for examining a user's privileges for a function
3912 AclMode
3913 pg_proc_aclmask(Oid proc_oid, Oid roleid,
3914 AclMode mask, AclMaskHow how)
3916 AclMode result;
3917 HeapTuple tuple;
3918 Datum aclDatum;
3919 bool isNull;
3920 Acl *acl;
3921 Oid ownerId;
3923 /* Superusers bypass all permission checking. */
3924 if (superuser_arg(roleid))
3925 return mask;
3928 * Get the function's ACL from pg_proc
3930 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
3931 if (!HeapTupleIsValid(tuple))
3932 ereport(ERROR,
3933 (errcode(ERRCODE_UNDEFINED_FUNCTION),
3934 errmsg("function with OID %u does not exist", proc_oid)));
3936 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
3938 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
3939 &isNull);
3940 if (isNull)
3942 /* No ACL, so build default ACL */
3943 acl = acldefault(OBJECT_FUNCTION, ownerId);
3944 aclDatum = (Datum) 0;
3946 else
3948 /* detoast ACL if necessary */
3949 acl = DatumGetAclP(aclDatum);
3952 result = aclmask(acl, roleid, ownerId, mask, how);
3954 /* if we have a detoasted copy, free it */
3955 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3956 pfree(acl);
3958 ReleaseSysCache(tuple);
3960 return result;
3964 * Exported routine for examining a user's privileges for a language
3966 AclMode
3967 pg_language_aclmask(Oid lang_oid, Oid roleid,
3968 AclMode mask, AclMaskHow how)
3970 AclMode result;
3971 HeapTuple tuple;
3972 Datum aclDatum;
3973 bool isNull;
3974 Acl *acl;
3975 Oid ownerId;
3977 /* Superusers bypass all permission checking. */
3978 if (superuser_arg(roleid))
3979 return mask;
3982 * Get the language's ACL from pg_language
3984 tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid));
3985 if (!HeapTupleIsValid(tuple))
3986 ereport(ERROR,
3987 (errcode(ERRCODE_UNDEFINED_OBJECT),
3988 errmsg("language with OID %u does not exist", lang_oid)));
3990 ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
3992 aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
3993 &isNull);
3994 if (isNull)
3996 /* No ACL, so build default ACL */
3997 acl = acldefault(OBJECT_LANGUAGE, ownerId);
3998 aclDatum = (Datum) 0;
4000 else
4002 /* detoast ACL if necessary */
4003 acl = DatumGetAclP(aclDatum);
4006 result = aclmask(acl, roleid, ownerId, mask, how);
4008 /* if we have a detoasted copy, free it */
4009 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4010 pfree(acl);
4012 ReleaseSysCache(tuple);
4014 return result;
4018 * Exported routine for examining a user's privileges for a largeobject
4020 * When a large object is opened for reading, it is opened relative to the
4021 * caller's snapshot, but when it is opened for writing, a current
4022 * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
4023 * takes a snapshot argument so that the permissions check can be made
4024 * relative to the same snapshot that will be used to read the underlying
4025 * data. The caller will actually pass NULL for an instantaneous MVCC
4026 * snapshot, since all we do with the snapshot argument is pass it through
4027 * to systable_beginscan().
4029 AclMode
4030 pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
4031 AclMode mask, AclMaskHow how,
4032 Snapshot snapshot)
4034 AclMode result;
4035 Relation pg_lo_meta;
4036 ScanKeyData entry[1];
4037 SysScanDesc scan;
4038 HeapTuple tuple;
4039 Datum aclDatum;
4040 bool isNull;
4041 Acl *acl;
4042 Oid ownerId;
4044 /* Superusers bypass all permission checking. */
4045 if (superuser_arg(roleid))
4046 return mask;
4049 * Get the largeobject's ACL from pg_largeobject_metadata
4051 pg_lo_meta = table_open(LargeObjectMetadataRelationId,
4052 AccessShareLock);
4054 ScanKeyInit(&entry[0],
4055 Anum_pg_largeobject_metadata_oid,
4056 BTEqualStrategyNumber, F_OIDEQ,
4057 ObjectIdGetDatum(lobj_oid));
4059 scan = systable_beginscan(pg_lo_meta,
4060 LargeObjectMetadataOidIndexId, true,
4061 snapshot, 1, entry);
4063 tuple = systable_getnext(scan);
4064 if (!HeapTupleIsValid(tuple))
4065 ereport(ERROR,
4066 (errcode(ERRCODE_UNDEFINED_OBJECT),
4067 errmsg("large object %u does not exist", lobj_oid)));
4069 ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
4071 aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
4072 RelationGetDescr(pg_lo_meta), &isNull);
4074 if (isNull)
4076 /* No ACL, so build default ACL */
4077 acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
4078 aclDatum = (Datum) 0;
4080 else
4082 /* detoast ACL if necessary */
4083 acl = DatumGetAclP(aclDatum);
4086 result = aclmask(acl, roleid, ownerId, mask, how);
4088 /* if we have a detoasted copy, free it */
4089 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4090 pfree(acl);
4092 systable_endscan(scan);
4094 table_close(pg_lo_meta, AccessShareLock);
4096 return result;
4100 * Exported routine for examining a user's privileges for a namespace
4102 AclMode
4103 pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
4104 AclMode mask, AclMaskHow how)
4106 AclMode result;
4107 HeapTuple tuple;
4108 Datum aclDatum;
4109 bool isNull;
4110 Acl *acl;
4111 Oid ownerId;
4113 /* Superusers bypass all permission checking. */
4114 if (superuser_arg(roleid))
4115 return mask;
4118 * If we have been assigned this namespace as a temp namespace, check to
4119 * make sure we have CREATE TEMP permission on the database, and if so act
4120 * as though we have all standard (but not GRANT OPTION) permissions on
4121 * the namespace. If we don't have CREATE TEMP, act as though we have
4122 * only USAGE (and not CREATE) rights.
4124 * This may seem redundant given the check in InitTempTableNamespace, but
4125 * it really isn't since current user ID may have changed since then. The
4126 * upshot of this behavior is that a SECURITY DEFINER function can create
4127 * temp tables that can then be accessed (if permission is granted) by
4128 * code in the same session that doesn't have permissions to create temp
4129 * tables.
4131 * XXX Would it be safe to ereport a special error message as
4132 * InitTempTableNamespace does? Returning zero here means we'll get a
4133 * generic "permission denied for schema pg_temp_N" message, which is not
4134 * remarkably user-friendly.
4136 if (isTempNamespace(nsp_oid))
4138 if (pg_database_aclcheck(MyDatabaseId, roleid,
4139 ACL_CREATE_TEMP) == ACLCHECK_OK)
4140 return mask & ACL_ALL_RIGHTS_SCHEMA;
4141 else
4142 return mask & ACL_USAGE;
4146 * Get the schema's ACL from pg_namespace
4148 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
4149 if (!HeapTupleIsValid(tuple))
4150 ereport(ERROR,
4151 (errcode(ERRCODE_UNDEFINED_SCHEMA),
4152 errmsg("schema with OID %u does not exist", nsp_oid)));
4154 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
4156 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
4157 &isNull);
4158 if (isNull)
4160 /* No ACL, so build default ACL */
4161 acl = acldefault(OBJECT_SCHEMA, ownerId);
4162 aclDatum = (Datum) 0;
4164 else
4166 /* detoast ACL if necessary */
4167 acl = DatumGetAclP(aclDatum);
4170 result = aclmask(acl, roleid, ownerId, mask, how);
4172 /* if we have a detoasted copy, free it */
4173 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4174 pfree(acl);
4176 ReleaseSysCache(tuple);
4178 return result;
4182 * Exported routine for examining a user's privileges for a tablespace
4184 AclMode
4185 pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
4186 AclMode mask, AclMaskHow how)
4188 AclMode result;
4189 HeapTuple tuple;
4190 Datum aclDatum;
4191 bool isNull;
4192 Acl *acl;
4193 Oid ownerId;
4195 /* Superusers bypass all permission checking. */
4196 if (superuser_arg(roleid))
4197 return mask;
4200 * Get the tablespace's ACL from pg_tablespace
4202 tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
4203 if (!HeapTupleIsValid(tuple))
4204 ereport(ERROR,
4205 (errcode(ERRCODE_UNDEFINED_OBJECT),
4206 errmsg("tablespace with OID %u does not exist", spc_oid)));
4208 ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
4210 aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple,
4211 Anum_pg_tablespace_spcacl,
4212 &isNull);
4214 if (isNull)
4216 /* No ACL, so build default ACL */
4217 acl = acldefault(OBJECT_TABLESPACE, ownerId);
4218 aclDatum = (Datum) 0;
4220 else
4222 /* detoast ACL if necessary */
4223 acl = DatumGetAclP(aclDatum);
4226 result = aclmask(acl, roleid, ownerId, mask, how);
4228 /* if we have a detoasted copy, free it */
4229 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4230 pfree(acl);
4232 ReleaseSysCache(tuple);
4234 return result;
4238 * Exported routine for examining a user's privileges for a foreign
4239 * data wrapper
4241 AclMode
4242 pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
4243 AclMode mask, AclMaskHow how)
4245 AclMode result;
4246 HeapTuple tuple;
4247 Datum aclDatum;
4248 bool isNull;
4249 Acl *acl;
4250 Oid ownerId;
4252 Form_pg_foreign_data_wrapper fdwForm;
4254 /* Bypass permission checks for superusers */
4255 if (superuser_arg(roleid))
4256 return mask;
4259 * Must get the FDW's tuple from pg_foreign_data_wrapper
4261 tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdw_oid));
4262 if (!HeapTupleIsValid(tuple))
4263 ereport(ERROR,
4264 (errcode(ERRCODE_UNDEFINED_OBJECT),
4265 errmsg("foreign-data wrapper with OID %u does not exist",
4266 fdw_oid)));
4267 fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
4270 * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
4272 ownerId = fdwForm->fdwowner;
4274 aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
4275 Anum_pg_foreign_data_wrapper_fdwacl, &isNull);
4276 if (isNull)
4278 /* No ACL, so build default ACL */
4279 acl = acldefault(OBJECT_FDW, ownerId);
4280 aclDatum = (Datum) 0;
4282 else
4284 /* detoast rel's ACL if necessary */
4285 acl = DatumGetAclP(aclDatum);
4288 result = aclmask(acl, roleid, ownerId, mask, how);
4290 /* if we have a detoasted copy, free it */
4291 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4292 pfree(acl);
4294 ReleaseSysCache(tuple);
4296 return result;
4300 * Exported routine for examining a user's privileges for a foreign
4301 * server.
4303 AclMode
4304 pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
4305 AclMode mask, AclMaskHow how)
4307 AclMode result;
4308 HeapTuple tuple;
4309 Datum aclDatum;
4310 bool isNull;
4311 Acl *acl;
4312 Oid ownerId;
4314 Form_pg_foreign_server srvForm;
4316 /* Bypass permission checks for superusers */
4317 if (superuser_arg(roleid))
4318 return mask;
4321 * Must get the FDW's tuple from pg_foreign_data_wrapper
4323 tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
4324 if (!HeapTupleIsValid(tuple))
4325 ereport(ERROR,
4326 (errcode(ERRCODE_UNDEFINED_OBJECT),
4327 errmsg("foreign server with OID %u does not exist",
4328 srv_oid)));
4329 srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
4332 * Normal case: get the foreign server's ACL from pg_foreign_server
4334 ownerId = srvForm->srvowner;
4336 aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
4337 Anum_pg_foreign_server_srvacl, &isNull);
4338 if (isNull)
4340 /* No ACL, so build default ACL */
4341 acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
4342 aclDatum = (Datum) 0;
4344 else
4346 /* detoast rel's ACL if necessary */
4347 acl = DatumGetAclP(aclDatum);
4350 result = aclmask(acl, roleid, ownerId, mask, how);
4352 /* if we have a detoasted copy, free it */
4353 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4354 pfree(acl);
4356 ReleaseSysCache(tuple);
4358 return result;
4362 * Exported routine for examining a user's privileges for a type.
4364 AclMode
4365 pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
4367 AclMode result;
4368 HeapTuple tuple;
4369 Datum aclDatum;
4370 bool isNull;
4371 Acl *acl;
4372 Oid ownerId;
4374 Form_pg_type typeForm;
4376 /* Bypass permission checks for superusers */
4377 if (superuser_arg(roleid))
4378 return mask;
4381 * Must get the type's tuple from pg_type
4383 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
4384 if (!HeapTupleIsValid(tuple))
4385 ereport(ERROR,
4386 (errcode(ERRCODE_UNDEFINED_OBJECT),
4387 errmsg("type with OID %u does not exist",
4388 type_oid)));
4389 typeForm = (Form_pg_type) GETSTRUCT(tuple);
4392 * "True" array types don't manage permissions of their own; consult the
4393 * element type instead.
4395 if (OidIsValid(typeForm->typelem) && typeForm->typlen == -1)
4397 Oid elttype_oid = typeForm->typelem;
4399 ReleaseSysCache(tuple);
4401 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
4402 /* this case is not a user-facing error, so elog not ereport */
4403 if (!HeapTupleIsValid(tuple))
4404 elog(ERROR, "cache lookup failed for type %u", elttype_oid);
4405 typeForm = (Form_pg_type) GETSTRUCT(tuple);
4409 * Now get the type's owner and ACL from the tuple
4411 ownerId = typeForm->typowner;
4413 aclDatum = SysCacheGetAttr(TYPEOID, tuple,
4414 Anum_pg_type_typacl, &isNull);
4415 if (isNull)
4417 /* No ACL, so build default ACL */
4418 acl = acldefault(OBJECT_TYPE, ownerId);
4419 aclDatum = (Datum) 0;
4421 else
4423 /* detoast rel's ACL if necessary */
4424 acl = DatumGetAclP(aclDatum);
4427 result = aclmask(acl, roleid, ownerId, mask, how);
4429 /* if we have a detoasted copy, free it */
4430 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4431 pfree(acl);
4433 ReleaseSysCache(tuple);
4435 return result;
4439 * Exported routine for checking a user's access privileges to a column
4441 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4442 * 'mode'; otherwise returns a suitable error code (in practice, always
4443 * ACLCHECK_NO_PRIV).
4445 * As with pg_attribute_aclmask, only privileges granted directly on the
4446 * column are considered here.
4448 AclResult
4449 pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
4450 Oid roleid, AclMode mode)
4452 if (pg_attribute_aclmask(table_oid, attnum, roleid, mode, ACLMASK_ANY) != 0)
4453 return ACLCHECK_OK;
4454 else
4455 return ACLCHECK_NO_PRIV;
4459 * Exported routine for checking a user's access privileges to any/all columns
4461 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
4462 * privileges identified by 'mode' on any non-dropped column in the relation;
4463 * otherwise returns a suitable error code (in practice, always
4464 * ACLCHECK_NO_PRIV).
4466 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
4467 * privileges identified by 'mode' on each non-dropped column in the relation
4468 * (and there must be at least one such column); otherwise returns a suitable
4469 * error code (in practice, always ACLCHECK_NO_PRIV).
4471 * As with pg_attribute_aclmask, only privileges granted directly on the
4472 * column(s) are considered here.
4474 * Note: system columns are not considered here; there are cases where that
4475 * might be appropriate but there are also cases where it wouldn't.
4477 AclResult
4478 pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
4479 AclMaskHow how)
4481 AclResult result;
4482 HeapTuple classTuple;
4483 Form_pg_class classForm;
4484 AttrNumber nattrs;
4485 AttrNumber curr_att;
4488 * Must fetch pg_class row to check number of attributes. As in
4489 * pg_attribute_aclmask, we prefer to return "no privileges" instead of
4490 * throwing an error if we get any unexpected lookup errors.
4492 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
4493 if (!HeapTupleIsValid(classTuple))
4494 return ACLCHECK_NO_PRIV;
4495 classForm = (Form_pg_class) GETSTRUCT(classTuple);
4497 nattrs = classForm->relnatts;
4499 ReleaseSysCache(classTuple);
4502 * Initialize result in case there are no non-dropped columns. We want to
4503 * report failure in such cases for either value of 'how'.
4505 result = ACLCHECK_NO_PRIV;
4507 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4509 HeapTuple attTuple;
4510 AclMode attmask;
4512 attTuple = SearchSysCache2(ATTNUM,
4513 ObjectIdGetDatum(table_oid),
4514 Int16GetDatum(curr_att));
4515 if (!HeapTupleIsValid(attTuple))
4516 continue;
4518 /* ignore dropped columns */
4519 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4521 ReleaseSysCache(attTuple);
4522 continue;
4526 * Here we hard-wire knowledge that the default ACL for a column
4527 * grants no privileges, so that we can fall out quickly in the very
4528 * common case where attacl is null.
4530 if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
4531 attmask = 0;
4532 else
4533 attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
4534 mode, ACLMASK_ANY);
4536 ReleaseSysCache(attTuple);
4538 if (attmask != 0)
4540 result = ACLCHECK_OK;
4541 if (how == ACLMASK_ANY)
4542 break; /* succeed on any success */
4544 else
4546 result = ACLCHECK_NO_PRIV;
4547 if (how == ACLMASK_ALL)
4548 break; /* fail on any failure */
4552 return result;
4556 * Exported routine for checking a user's access privileges to a table
4558 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4559 * 'mode'; otherwise returns a suitable error code (in practice, always
4560 * ACLCHECK_NO_PRIV).
4562 AclResult
4563 pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
4565 if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
4566 return ACLCHECK_OK;
4567 else
4568 return ACLCHECK_NO_PRIV;
4572 * Exported routine for checking a user's access privileges to a database
4574 AclResult
4575 pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
4577 if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
4578 return ACLCHECK_OK;
4579 else
4580 return ACLCHECK_NO_PRIV;
4584 * Exported routine for checking a user's access privileges to a function
4586 AclResult
4587 pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
4589 if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
4590 return ACLCHECK_OK;
4591 else
4592 return ACLCHECK_NO_PRIV;
4596 * Exported routine for checking a user's access privileges to a language
4598 AclResult
4599 pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
4601 if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
4602 return ACLCHECK_OK;
4603 else
4604 return ACLCHECK_NO_PRIV;
4608 * Exported routine for checking a user's access privileges to a largeobject
4610 AclResult
4611 pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
4612 Snapshot snapshot)
4614 if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4615 ACLMASK_ANY, snapshot) != 0)
4616 return ACLCHECK_OK;
4617 else
4618 return ACLCHECK_NO_PRIV;
4622 * Exported routine for checking a user's access privileges to a namespace
4624 AclResult
4625 pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
4627 if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
4628 return ACLCHECK_OK;
4629 else
4630 return ACLCHECK_NO_PRIV;
4634 * Exported routine for checking a user's access privileges to a tablespace
4636 AclResult
4637 pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
4639 if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
4640 return ACLCHECK_OK;
4641 else
4642 return ACLCHECK_NO_PRIV;
4646 * Exported routine for checking a user's access privileges to a foreign
4647 * data wrapper
4649 AclResult
4650 pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode)
4652 if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0)
4653 return ACLCHECK_OK;
4654 else
4655 return ACLCHECK_NO_PRIV;
4659 * Exported routine for checking a user's access privileges to a foreign
4660 * server
4662 AclResult
4663 pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
4665 if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0)
4666 return ACLCHECK_OK;
4667 else
4668 return ACLCHECK_NO_PRIV;
4672 * Exported routine for checking a user's access privileges to a type
4674 AclResult
4675 pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
4677 if (pg_type_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0)
4678 return ACLCHECK_OK;
4679 else
4680 return ACLCHECK_NO_PRIV;
4684 * Ownership check for a relation (specified by OID).
4686 bool
4687 pg_class_ownercheck(Oid class_oid, Oid roleid)
4689 HeapTuple tuple;
4690 Oid ownerId;
4692 /* Superusers bypass all permission checking. */
4693 if (superuser_arg(roleid))
4694 return true;
4696 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid));
4697 if (!HeapTupleIsValid(tuple))
4698 ereport(ERROR,
4699 (errcode(ERRCODE_UNDEFINED_TABLE),
4700 errmsg("relation with OID %u does not exist", class_oid)));
4702 ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
4704 ReleaseSysCache(tuple);
4706 return has_privs_of_role(roleid, ownerId);
4710 * Ownership check for a type (specified by OID).
4712 bool
4713 pg_type_ownercheck(Oid type_oid, Oid roleid)
4715 HeapTuple tuple;
4716 Oid ownerId;
4718 /* Superusers bypass all permission checking. */
4719 if (superuser_arg(roleid))
4720 return true;
4722 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
4723 if (!HeapTupleIsValid(tuple))
4724 ereport(ERROR,
4725 (errcode(ERRCODE_UNDEFINED_OBJECT),
4726 errmsg("type with OID %u does not exist", type_oid)));
4728 ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
4730 ReleaseSysCache(tuple);
4732 return has_privs_of_role(roleid, ownerId);
4736 * Ownership check for an operator (specified by OID).
4738 bool
4739 pg_oper_ownercheck(Oid oper_oid, Oid roleid)
4741 HeapTuple tuple;
4742 Oid ownerId;
4744 /* Superusers bypass all permission checking. */
4745 if (superuser_arg(roleid))
4746 return true;
4748 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(oper_oid));
4749 if (!HeapTupleIsValid(tuple))
4750 ereport(ERROR,
4751 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4752 errmsg("operator with OID %u does not exist", oper_oid)));
4754 ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
4756 ReleaseSysCache(tuple);
4758 return has_privs_of_role(roleid, ownerId);
4762 * Ownership check for a function (specified by OID).
4764 bool
4765 pg_proc_ownercheck(Oid proc_oid, Oid roleid)
4767 HeapTuple tuple;
4768 Oid ownerId;
4770 /* Superusers bypass all permission checking. */
4771 if (superuser_arg(roleid))
4772 return true;
4774 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
4775 if (!HeapTupleIsValid(tuple))
4776 ereport(ERROR,
4777 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4778 errmsg("function with OID %u does not exist", proc_oid)));
4780 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
4782 ReleaseSysCache(tuple);
4784 return has_privs_of_role(roleid, ownerId);
4788 * Ownership check for a procedural language (specified by OID)
4790 bool
4791 pg_language_ownercheck(Oid lan_oid, Oid roleid)
4793 HeapTuple tuple;
4794 Oid ownerId;
4796 /* Superusers bypass all permission checking. */
4797 if (superuser_arg(roleid))
4798 return true;
4800 tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lan_oid));
4801 if (!HeapTupleIsValid(tuple))
4802 ereport(ERROR,
4803 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4804 errmsg("language with OID %u does not exist", lan_oid)));
4806 ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
4808 ReleaseSysCache(tuple);
4810 return has_privs_of_role(roleid, ownerId);
4814 * Ownership check for a largeobject (specified by OID)
4816 * This is only used for operations like ALTER LARGE OBJECT that are always
4817 * relative to an up-to-date snapshot.
4819 bool
4820 pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
4822 Relation pg_lo_meta;
4823 ScanKeyData entry[1];
4824 SysScanDesc scan;
4825 HeapTuple tuple;
4826 Oid ownerId;
4828 /* Superusers bypass all permission checking. */
4829 if (superuser_arg(roleid))
4830 return true;
4832 /* There's no syscache for pg_largeobject_metadata */
4833 pg_lo_meta = table_open(LargeObjectMetadataRelationId,
4834 AccessShareLock);
4836 ScanKeyInit(&entry[0],
4837 Anum_pg_largeobject_metadata_oid,
4838 BTEqualStrategyNumber, F_OIDEQ,
4839 ObjectIdGetDatum(lobj_oid));
4841 scan = systable_beginscan(pg_lo_meta,
4842 LargeObjectMetadataOidIndexId, true,
4843 NULL, 1, entry);
4845 tuple = systable_getnext(scan);
4846 if (!HeapTupleIsValid(tuple))
4847 ereport(ERROR,
4848 (errcode(ERRCODE_UNDEFINED_OBJECT),
4849 errmsg("large object %u does not exist", lobj_oid)));
4851 ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
4853 systable_endscan(scan);
4854 table_close(pg_lo_meta, AccessShareLock);
4856 return has_privs_of_role(roleid, ownerId);
4860 * Ownership check for a namespace (specified by OID).
4862 bool
4863 pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
4865 HeapTuple tuple;
4866 Oid ownerId;
4868 /* Superusers bypass all permission checking. */
4869 if (superuser_arg(roleid))
4870 return true;
4872 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
4873 if (!HeapTupleIsValid(tuple))
4874 ereport(ERROR,
4875 (errcode(ERRCODE_UNDEFINED_SCHEMA),
4876 errmsg("schema with OID %u does not exist", nsp_oid)));
4878 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
4880 ReleaseSysCache(tuple);
4882 return has_privs_of_role(roleid, ownerId);
4886 * Ownership check for a tablespace (specified by OID).
4888 bool
4889 pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
4891 HeapTuple spctuple;
4892 Oid spcowner;
4894 /* Superusers bypass all permission checking. */
4895 if (superuser_arg(roleid))
4896 return true;
4898 /* Search syscache for pg_tablespace */
4899 spctuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
4900 if (!HeapTupleIsValid(spctuple))
4901 ereport(ERROR,
4902 (errcode(ERRCODE_UNDEFINED_OBJECT),
4903 errmsg("tablespace with OID %u does not exist", spc_oid)));
4905 spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
4907 ReleaseSysCache(spctuple);
4909 return has_privs_of_role(roleid, spcowner);
4913 * Ownership check for an operator class (specified by OID).
4915 bool
4916 pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
4918 HeapTuple tuple;
4919 Oid ownerId;
4921 /* Superusers bypass all permission checking. */
4922 if (superuser_arg(roleid))
4923 return true;
4925 tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opc_oid));
4926 if (!HeapTupleIsValid(tuple))
4927 ereport(ERROR,
4928 (errcode(ERRCODE_UNDEFINED_OBJECT),
4929 errmsg("operator class with OID %u does not exist",
4930 opc_oid)));
4932 ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
4934 ReleaseSysCache(tuple);
4936 return has_privs_of_role(roleid, ownerId);
4940 * Ownership check for an operator family (specified by OID).
4942 bool
4943 pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
4945 HeapTuple tuple;
4946 Oid ownerId;
4948 /* Superusers bypass all permission checking. */
4949 if (superuser_arg(roleid))
4950 return true;
4952 tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opf_oid));
4953 if (!HeapTupleIsValid(tuple))
4954 ereport(ERROR,
4955 (errcode(ERRCODE_UNDEFINED_OBJECT),
4956 errmsg("operator family with OID %u does not exist",
4957 opf_oid)));
4959 ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
4961 ReleaseSysCache(tuple);
4963 return has_privs_of_role(roleid, ownerId);
4967 * Ownership check for a text search dictionary (specified by OID).
4969 bool
4970 pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid)
4972 HeapTuple tuple;
4973 Oid ownerId;
4975 /* Superusers bypass all permission checking. */
4976 if (superuser_arg(roleid))
4977 return true;
4979 tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dict_oid));
4980 if (!HeapTupleIsValid(tuple))
4981 ereport(ERROR,
4982 (errcode(ERRCODE_UNDEFINED_OBJECT),
4983 errmsg("text search dictionary with OID %u does not exist",
4984 dict_oid)));
4986 ownerId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictowner;
4988 ReleaseSysCache(tuple);
4990 return has_privs_of_role(roleid, ownerId);
4994 * Ownership check for a text search configuration (specified by OID).
4996 bool
4997 pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid)
4999 HeapTuple tuple;
5000 Oid ownerId;
5002 /* Superusers bypass all permission checking. */
5003 if (superuser_arg(roleid))
5004 return true;
5006 tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfg_oid));
5007 if (!HeapTupleIsValid(tuple))
5008 ereport(ERROR,
5009 (errcode(ERRCODE_UNDEFINED_OBJECT),
5010 errmsg("text search configuration with OID %u does not exist",
5011 cfg_oid)));
5013 ownerId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgowner;
5015 ReleaseSysCache(tuple);
5017 return has_privs_of_role(roleid, ownerId);
5021 * Ownership check for a foreign-data wrapper (specified by OID).
5023 bool
5024 pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid)
5026 HeapTuple tuple;
5027 Oid ownerId;
5029 /* Superusers bypass all permission checking. */
5030 if (superuser_arg(roleid))
5031 return true;
5033 tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(srv_oid));
5034 if (!HeapTupleIsValid(tuple))
5035 ereport(ERROR,
5036 (errcode(ERRCODE_UNDEFINED_OBJECT),
5037 errmsg("foreign-data wrapper with OID %u does not exist",
5038 srv_oid)));
5040 ownerId = ((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwowner;
5042 ReleaseSysCache(tuple);
5044 return has_privs_of_role(roleid, ownerId);
5048 * Ownership check for a foreign server (specified by OID).
5050 bool
5051 pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
5053 HeapTuple tuple;
5054 Oid ownerId;
5056 /* Superusers bypass all permission checking. */
5057 if (superuser_arg(roleid))
5058 return true;
5060 tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
5061 if (!HeapTupleIsValid(tuple))
5062 ereport(ERROR,
5063 (errcode(ERRCODE_UNDEFINED_OBJECT),
5064 errmsg("foreign server with OID %u does not exist",
5065 srv_oid)));
5067 ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner;
5069 ReleaseSysCache(tuple);
5071 return has_privs_of_role(roleid, ownerId);
5075 * Ownership check for an event trigger (specified by OID).
5077 bool
5078 pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
5080 HeapTuple tuple;
5081 Oid ownerId;
5083 /* Superusers bypass all permission checking. */
5084 if (superuser_arg(roleid))
5085 return true;
5087 tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid));
5088 if (!HeapTupleIsValid(tuple))
5089 ereport(ERROR,
5090 (errcode(ERRCODE_UNDEFINED_OBJECT),
5091 errmsg("event trigger with OID %u does not exist",
5092 et_oid)));
5094 ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
5096 ReleaseSysCache(tuple);
5098 return has_privs_of_role(roleid, ownerId);
5102 * Ownership check for a database (specified by OID).
5104 bool
5105 pg_database_ownercheck(Oid db_oid, Oid roleid)
5107 HeapTuple tuple;
5108 Oid dba;
5110 /* Superusers bypass all permission checking. */
5111 if (superuser_arg(roleid))
5112 return true;
5114 tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
5115 if (!HeapTupleIsValid(tuple))
5116 ereport(ERROR,
5117 (errcode(ERRCODE_UNDEFINED_DATABASE),
5118 errmsg("database with OID %u does not exist", db_oid)));
5120 dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
5122 ReleaseSysCache(tuple);
5124 return has_privs_of_role(roleid, dba);
5128 * Ownership check for a collation (specified by OID).
5130 bool
5131 pg_collation_ownercheck(Oid coll_oid, Oid roleid)
5133 HeapTuple tuple;
5134 Oid ownerId;
5136 /* Superusers bypass all permission checking. */
5137 if (superuser_arg(roleid))
5138 return true;
5140 tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(coll_oid));
5141 if (!HeapTupleIsValid(tuple))
5142 ereport(ERROR,
5143 (errcode(ERRCODE_UNDEFINED_OBJECT),
5144 errmsg("collation with OID %u does not exist", coll_oid)));
5146 ownerId = ((Form_pg_collation) GETSTRUCT(tuple))->collowner;
5148 ReleaseSysCache(tuple);
5150 return has_privs_of_role(roleid, ownerId);
5154 * Ownership check for a conversion (specified by OID).
5156 bool
5157 pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
5159 HeapTuple tuple;
5160 Oid ownerId;
5162 /* Superusers bypass all permission checking. */
5163 if (superuser_arg(roleid))
5164 return true;
5166 tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conv_oid));
5167 if (!HeapTupleIsValid(tuple))
5168 ereport(ERROR,
5169 (errcode(ERRCODE_UNDEFINED_OBJECT),
5170 errmsg("conversion with OID %u does not exist", conv_oid)));
5172 ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
5174 ReleaseSysCache(tuple);
5176 return has_privs_of_role(roleid, ownerId);
5180 * Ownership check for an extension (specified by OID).
5182 bool
5183 pg_extension_ownercheck(Oid ext_oid, Oid roleid)
5185 Relation pg_extension;
5186 ScanKeyData entry[1];
5187 SysScanDesc scan;
5188 HeapTuple tuple;
5189 Oid ownerId;
5191 /* Superusers bypass all permission checking. */
5192 if (superuser_arg(roleid))
5193 return true;
5195 /* There's no syscache for pg_extension, so do it the hard way */
5196 pg_extension = table_open(ExtensionRelationId, AccessShareLock);
5198 ScanKeyInit(&entry[0],
5199 Anum_pg_extension_oid,
5200 BTEqualStrategyNumber, F_OIDEQ,
5201 ObjectIdGetDatum(ext_oid));
5203 scan = systable_beginscan(pg_extension,
5204 ExtensionOidIndexId, true,
5205 NULL, 1, entry);
5207 tuple = systable_getnext(scan);
5208 if (!HeapTupleIsValid(tuple))
5209 ereport(ERROR,
5210 (errcode(ERRCODE_UNDEFINED_OBJECT),
5211 errmsg("extension with OID %u does not exist", ext_oid)));
5213 ownerId = ((Form_pg_extension) GETSTRUCT(tuple))->extowner;
5215 systable_endscan(scan);
5216 table_close(pg_extension, AccessShareLock);
5218 return has_privs_of_role(roleid, ownerId);
5222 * Ownership check for a publication (specified by OID).
5224 bool
5225 pg_publication_ownercheck(Oid pub_oid, Oid roleid)
5227 HeapTuple tuple;
5228 Oid ownerId;
5230 /* Superusers bypass all permission checking. */
5231 if (superuser_arg(roleid))
5232 return true;
5234 tuple = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pub_oid));
5235 if (!HeapTupleIsValid(tuple))
5236 ereport(ERROR,
5237 (errcode(ERRCODE_UNDEFINED_OBJECT),
5238 errmsg("publication with OID %u does not exist", pub_oid)));
5240 ownerId = ((Form_pg_publication) GETSTRUCT(tuple))->pubowner;
5242 ReleaseSysCache(tuple);
5244 return has_privs_of_role(roleid, ownerId);
5248 * Ownership check for a subscription (specified by OID).
5250 bool
5251 pg_subscription_ownercheck(Oid sub_oid, Oid roleid)
5253 HeapTuple tuple;
5254 Oid ownerId;
5256 /* Superusers bypass all permission checking. */
5257 if (superuser_arg(roleid))
5258 return true;
5260 tuple = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(sub_oid));
5261 if (!HeapTupleIsValid(tuple))
5262 ereport(ERROR,
5263 (errcode(ERRCODE_UNDEFINED_OBJECT),
5264 errmsg("subscription with OID %u does not exist", sub_oid)));
5266 ownerId = ((Form_pg_subscription) GETSTRUCT(tuple))->subowner;
5268 ReleaseSysCache(tuple);
5270 return has_privs_of_role(roleid, ownerId);
5274 * Ownership check for a statistics object (specified by OID).
5276 bool
5277 pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
5279 HeapTuple tuple;
5280 Oid ownerId;
5282 /* Superusers bypass all permission checking. */
5283 if (superuser_arg(roleid))
5284 return true;
5286 tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stat_oid));
5287 if (!HeapTupleIsValid(tuple))
5288 ereport(ERROR,
5289 (errcode(ERRCODE_UNDEFINED_OBJECT),
5290 errmsg("statistics object with OID %u does not exist",
5291 stat_oid)));
5293 ownerId = ((Form_pg_statistic_ext) GETSTRUCT(tuple))->stxowner;
5295 ReleaseSysCache(tuple);
5297 return has_privs_of_role(roleid, ownerId);
5301 * Check whether specified role has CREATEROLE privilege (or is a superuser)
5303 * Note: roles do not have owners per se; instead we use this test in
5304 * places where an ownership-like permissions test is needed for a role.
5305 * Be sure to apply it to the role trying to do the operation, not the
5306 * role being operated on! Also note that this generally should not be
5307 * considered enough privilege if the target role is a superuser.
5308 * (We don't handle that consideration here because we want to give a
5309 * separate error message for such cases, so the caller has to deal with it.)
5311 bool
5312 has_createrole_privilege(Oid roleid)
5314 bool result = false;
5315 HeapTuple utup;
5317 /* Superusers bypass all permission checking. */
5318 if (superuser_arg(roleid))
5319 return true;
5321 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
5322 if (HeapTupleIsValid(utup))
5324 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
5325 ReleaseSysCache(utup);
5327 return result;
5330 bool
5331 has_bypassrls_privilege(Oid roleid)
5333 bool result = false;
5334 HeapTuple utup;
5336 /* Superusers bypass all permission checking. */
5337 if (superuser_arg(roleid))
5338 return true;
5340 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
5341 if (HeapTupleIsValid(utup))
5343 result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
5344 ReleaseSysCache(utup);
5346 return result;
5350 * Fetch pg_default_acl entry for given role, namespace and object type
5351 * (object type must be given in pg_default_acl's encoding).
5352 * Returns NULL if no such entry.
5354 static Acl *
5355 get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
5357 Acl *result = NULL;
5358 HeapTuple tuple;
5360 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
5361 ObjectIdGetDatum(roleId),
5362 ObjectIdGetDatum(nsp_oid),
5363 CharGetDatum(objtype));
5365 if (HeapTupleIsValid(tuple))
5367 Datum aclDatum;
5368 bool isNull;
5370 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
5371 Anum_pg_default_acl_defaclacl,
5372 &isNull);
5373 if (!isNull)
5374 result = DatumGetAclPCopy(aclDatum);
5375 ReleaseSysCache(tuple);
5378 return result;
5382 * Get default permissions for newly created object within given schema
5384 * Returns NULL if built-in system defaults should be used.
5386 * If the result is not NULL, caller must call recordDependencyOnNewAcl
5387 * once the OID of the new object is known.
5389 Acl *
5390 get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
5392 Acl *result;
5393 Acl *glob_acl;
5394 Acl *schema_acl;
5395 Acl *def_acl;
5396 char defaclobjtype;
5399 * Use NULL during bootstrap, since pg_default_acl probably isn't there
5400 * yet.
5402 if (IsBootstrapProcessingMode())
5403 return NULL;
5405 /* Check if object type is supported in pg_default_acl */
5406 switch (objtype)
5408 case OBJECT_TABLE:
5409 defaclobjtype = DEFACLOBJ_RELATION;
5410 break;
5412 case OBJECT_SEQUENCE:
5413 defaclobjtype = DEFACLOBJ_SEQUENCE;
5414 break;
5416 case OBJECT_FUNCTION:
5417 defaclobjtype = DEFACLOBJ_FUNCTION;
5418 break;
5420 case OBJECT_TYPE:
5421 defaclobjtype = DEFACLOBJ_TYPE;
5422 break;
5424 case OBJECT_SCHEMA:
5425 defaclobjtype = DEFACLOBJ_NAMESPACE;
5426 break;
5428 default:
5429 return NULL;
5432 /* Look up the relevant pg_default_acl entries */
5433 glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
5434 schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
5436 /* Quick out if neither entry exists */
5437 if (glob_acl == NULL && schema_acl == NULL)
5438 return NULL;
5440 /* We need to know the hard-wired default value, too */
5441 def_acl = acldefault(objtype, ownerId);
5443 /* If there's no global entry, substitute the hard-wired default */
5444 if (glob_acl == NULL)
5445 glob_acl = def_acl;
5447 /* Merge in any per-schema privileges */
5448 result = aclmerge(glob_acl, schema_acl, ownerId);
5451 * For efficiency, we want to return NULL if the result equals default.
5452 * This requires sorting both arrays to get an accurate comparison.
5454 aclitemsort(result);
5455 aclitemsort(def_acl);
5456 if (aclequal(result, def_acl))
5457 result = NULL;
5459 return result;
5463 * Record dependencies on roles mentioned in a new object's ACL.
5465 void
5466 recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
5467 Oid ownerId, Acl *acl)
5469 int nmembers;
5470 Oid *members;
5472 /* Nothing to do if ACL is defaulted */
5473 if (acl == NULL)
5474 return;
5476 /* Extract roles mentioned in ACL */
5477 nmembers = aclmembers(acl, &members);
5479 /* Update the shared dependency ACL info */
5480 updateAclDependencies(classId, objectId, objsubId,
5481 ownerId,
5482 0, NULL,
5483 nmembers, members);
5487 * Record initial privileges for the top-level object passed in.
5489 * For the object passed in, this will record its ACL (if any) and the ACLs of
5490 * any sub-objects (eg: columns) into pg_init_privs.
5492 * Any new kinds of objects which have ACLs associated with them and can be
5493 * added to an extension should be added to the if-else tree below.
5495 void
5496 recordExtObjInitPriv(Oid objoid, Oid classoid)
5499 * pg_class / pg_attribute
5501 * If this is a relation then we need to see if there are any sub-objects
5502 * (eg: columns) for it and, if so, be sure to call
5503 * recordExtensionInitPrivWorker() for each one.
5505 if (classoid == RelationRelationId)
5507 Form_pg_class pg_class_tuple;
5508 Datum aclDatum;
5509 bool isNull;
5510 HeapTuple tuple;
5512 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
5513 if (!HeapTupleIsValid(tuple))
5514 elog(ERROR, "cache lookup failed for relation %u", objoid);
5515 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
5518 * Indexes don't have permissions, neither do the pg_class rows for
5519 * composite types. (These cases are unreachable given the
5520 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
5522 if (pg_class_tuple->relkind == RELKIND_INDEX ||
5523 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
5524 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
5526 ReleaseSysCache(tuple);
5527 return;
5531 * If this isn't a sequence then it's possibly going to have
5532 * column-level ACLs associated with it.
5534 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
5536 AttrNumber curr_att;
5537 AttrNumber nattrs = pg_class_tuple->relnatts;
5539 for (curr_att = 1; curr_att <= nattrs; curr_att++)
5541 HeapTuple attTuple;
5542 Datum attaclDatum;
5544 attTuple = SearchSysCache2(ATTNUM,
5545 ObjectIdGetDatum(objoid),
5546 Int16GetDatum(curr_att));
5548 if (!HeapTupleIsValid(attTuple))
5549 continue;
5551 /* ignore dropped columns */
5552 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
5554 ReleaseSysCache(attTuple);
5555 continue;
5558 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
5559 Anum_pg_attribute_attacl,
5560 &isNull);
5562 /* no need to do anything for a NULL ACL */
5563 if (isNull)
5565 ReleaseSysCache(attTuple);
5566 continue;
5569 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
5570 DatumGetAclP(attaclDatum));
5572 ReleaseSysCache(attTuple);
5576 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
5577 &isNull);
5579 /* Add the record, if any, for the top-level object */
5580 if (!isNull)
5581 recordExtensionInitPrivWorker(objoid, classoid, 0,
5582 DatumGetAclP(aclDatum));
5584 ReleaseSysCache(tuple);
5586 /* pg_foreign_data_wrapper */
5587 else if (classoid == ForeignDataWrapperRelationId)
5589 Datum aclDatum;
5590 bool isNull;
5591 HeapTuple tuple;
5593 tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
5594 ObjectIdGetDatum(objoid));
5595 if (!HeapTupleIsValid(tuple))
5596 elog(ERROR, "cache lookup failed for foreign data wrapper %u",
5597 objoid);
5599 aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
5600 Anum_pg_foreign_data_wrapper_fdwacl,
5601 &isNull);
5603 /* Add the record, if any, for the top-level object */
5604 if (!isNull)
5605 recordExtensionInitPrivWorker(objoid, classoid, 0,
5606 DatumGetAclP(aclDatum));
5608 ReleaseSysCache(tuple);
5610 /* pg_foreign_server */
5611 else if (classoid == ForeignServerRelationId)
5613 Datum aclDatum;
5614 bool isNull;
5615 HeapTuple tuple;
5617 tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(objoid));
5618 if (!HeapTupleIsValid(tuple))
5619 elog(ERROR, "cache lookup failed for foreign data wrapper %u",
5620 objoid);
5622 aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
5623 Anum_pg_foreign_server_srvacl,
5624 &isNull);
5626 /* Add the record, if any, for the top-level object */
5627 if (!isNull)
5628 recordExtensionInitPrivWorker(objoid, classoid, 0,
5629 DatumGetAclP(aclDatum));
5631 ReleaseSysCache(tuple);
5633 /* pg_language */
5634 else if (classoid == LanguageRelationId)
5636 Datum aclDatum;
5637 bool isNull;
5638 HeapTuple tuple;
5640 tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(objoid));
5641 if (!HeapTupleIsValid(tuple))
5642 elog(ERROR, "cache lookup failed for language %u", objoid);
5644 aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
5645 &isNull);
5647 /* Add the record, if any, for the top-level object */
5648 if (!isNull)
5649 recordExtensionInitPrivWorker(objoid, classoid, 0,
5650 DatumGetAclP(aclDatum));
5652 ReleaseSysCache(tuple);
5654 /* pg_largeobject_metadata */
5655 else if (classoid == LargeObjectMetadataRelationId)
5657 Datum aclDatum;
5658 bool isNull;
5659 HeapTuple tuple;
5660 ScanKeyData entry[1];
5661 SysScanDesc scan;
5662 Relation relation;
5665 * Note: this is dead code, given that we don't allow large objects to
5666 * be made extension members. But it seems worth carrying in case
5667 * some future caller of this function has need for it.
5669 relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
5671 /* There's no syscache for pg_largeobject_metadata */
5672 ScanKeyInit(&entry[0],
5673 Anum_pg_largeobject_metadata_oid,
5674 BTEqualStrategyNumber, F_OIDEQ,
5675 ObjectIdGetDatum(objoid));
5677 scan = systable_beginscan(relation,
5678 LargeObjectMetadataOidIndexId, true,
5679 NULL, 1, entry);
5681 tuple = systable_getnext(scan);
5682 if (!HeapTupleIsValid(tuple))
5683 elog(ERROR, "could not find tuple for large object %u", objoid);
5685 aclDatum = heap_getattr(tuple,
5686 Anum_pg_largeobject_metadata_lomacl,
5687 RelationGetDescr(relation), &isNull);
5689 /* Add the record, if any, for the top-level object */
5690 if (!isNull)
5691 recordExtensionInitPrivWorker(objoid, classoid, 0,
5692 DatumGetAclP(aclDatum));
5694 systable_endscan(scan);
5696 /* pg_namespace */
5697 else if (classoid == NamespaceRelationId)
5699 Datum aclDatum;
5700 bool isNull;
5701 HeapTuple tuple;
5703 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(objoid));
5704 if (!HeapTupleIsValid(tuple))
5705 elog(ERROR, "cache lookup failed for function %u", objoid);
5707 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple,
5708 Anum_pg_namespace_nspacl, &isNull);
5710 /* Add the record, if any, for the top-level object */
5711 if (!isNull)
5712 recordExtensionInitPrivWorker(objoid, classoid, 0,
5713 DatumGetAclP(aclDatum));
5715 ReleaseSysCache(tuple);
5717 /* pg_proc */
5718 else if (classoid == ProcedureRelationId)
5720 Datum aclDatum;
5721 bool isNull;
5722 HeapTuple tuple;
5724 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(objoid));
5725 if (!HeapTupleIsValid(tuple))
5726 elog(ERROR, "cache lookup failed for function %u", objoid);
5728 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
5729 &isNull);
5731 /* Add the record, if any, for the top-level object */
5732 if (!isNull)
5733 recordExtensionInitPrivWorker(objoid, classoid, 0,
5734 DatumGetAclP(aclDatum));
5736 ReleaseSysCache(tuple);
5738 /* pg_type */
5739 else if (classoid == TypeRelationId)
5741 Datum aclDatum;
5742 bool isNull;
5743 HeapTuple tuple;
5745 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(objoid));
5746 if (!HeapTupleIsValid(tuple))
5747 elog(ERROR, "cache lookup failed for function %u", objoid);
5749 aclDatum = SysCacheGetAttr(TYPEOID, tuple, Anum_pg_type_typacl,
5750 &isNull);
5752 /* Add the record, if any, for the top-level object */
5753 if (!isNull)
5754 recordExtensionInitPrivWorker(objoid, classoid, 0,
5755 DatumGetAclP(aclDatum));
5757 ReleaseSysCache(tuple);
5759 else if (classoid == AccessMethodRelationId ||
5760 classoid == AggregateRelationId ||
5761 classoid == CastRelationId ||
5762 classoid == CollationRelationId ||
5763 classoid == ConversionRelationId ||
5764 classoid == EventTriggerRelationId ||
5765 classoid == OperatorRelationId ||
5766 classoid == OperatorClassRelationId ||
5767 classoid == OperatorFamilyRelationId ||
5768 classoid == NamespaceRelationId ||
5769 classoid == TSConfigRelationId ||
5770 classoid == TSDictionaryRelationId ||
5771 classoid == TSParserRelationId ||
5772 classoid == TSTemplateRelationId ||
5773 classoid == TransformRelationId
5776 /* no ACL for these object types, so do nothing. */
5780 * complain if we are given a class OID for a class that extensions don't
5781 * support or that we don't recognize.
5783 else
5785 elog(ERROR, "unrecognized or unsupported class OID: %u", classoid);
5790 * For the object passed in, remove its ACL and the ACLs of any object subIds
5791 * from pg_init_privs (via recordExtensionInitPrivWorker()).
5793 void
5794 removeExtObjInitPriv(Oid objoid, Oid classoid)
5797 * If this is a relation then we need to see if there are any sub-objects
5798 * (eg: columns) for it and, if so, be sure to call
5799 * recordExtensionInitPrivWorker() for each one.
5801 if (classoid == RelationRelationId)
5803 Form_pg_class pg_class_tuple;
5804 HeapTuple tuple;
5806 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
5807 if (!HeapTupleIsValid(tuple))
5808 elog(ERROR, "cache lookup failed for relation %u", objoid);
5809 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
5812 * Indexes don't have permissions, neither do the pg_class rows for
5813 * composite types. (These cases are unreachable given the
5814 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
5816 if (pg_class_tuple->relkind == RELKIND_INDEX ||
5817 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
5818 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
5820 ReleaseSysCache(tuple);
5821 return;
5825 * If this isn't a sequence then it's possibly going to have
5826 * column-level ACLs associated with it.
5828 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
5830 AttrNumber curr_att;
5831 AttrNumber nattrs = pg_class_tuple->relnatts;
5833 for (curr_att = 1; curr_att <= nattrs; curr_att++)
5835 HeapTuple attTuple;
5837 attTuple = SearchSysCache2(ATTNUM,
5838 ObjectIdGetDatum(objoid),
5839 Int16GetDatum(curr_att));
5841 if (!HeapTupleIsValid(attTuple))
5842 continue;
5844 /* when removing, remove all entries, even dropped columns */
5846 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
5848 ReleaseSysCache(attTuple);
5852 ReleaseSysCache(tuple);
5855 /* Remove the record, if any, for the top-level object */
5856 recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
5860 * Record initial ACL for an extension object
5862 * Can be called at any time, we check if 'creating_extension' is set and, if
5863 * not, exit immediately.
5865 * Pass in the object OID, the OID of the class (the OID of the table which
5866 * the object is defined in) and the 'sub' id of the object (objsubid), if
5867 * any. If there is no 'sub' id (they are currently only used for columns of
5868 * tables) then pass in '0'. Finally, pass in the complete ACL to store.
5870 * If an ACL already exists for this object/sub-object then we will replace
5871 * it with what is passed in.
5873 * Passing in NULL for 'new_acl' will result in the entry for the object being
5874 * removed, if one is found.
5876 static void
5877 recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
5880 * Generally, we only record the initial privileges when an extension is
5881 * being created, but because we don't actually use CREATE EXTENSION
5882 * during binary upgrades with pg_upgrade, there is a variable to let us
5883 * know that the GRANT and REVOKE statements being issued, while this
5884 * variable is true, are for the initial privileges of the extension
5885 * object and therefore we need to record them.
5887 if (!creating_extension && !binary_upgrade_record_init_privs)
5888 return;
5890 recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
5894 * Record initial ACL for an extension object, worker.
5896 * This will perform a wholesale replacement of the entire ACL for the object
5897 * passed in, therefore be sure to pass in the complete new ACL to use.
5899 * Generally speaking, do *not* use this function directly but instead use
5900 * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
5901 * This function does *not* check if 'creating_extension' is set as it is also
5902 * used when an object is added to or removed from an extension via ALTER
5903 * EXTENSION ... ADD/DROP.
5905 static void
5906 recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
5908 Relation relation;
5909 ScanKeyData key[3];
5910 SysScanDesc scan;
5911 HeapTuple tuple;
5912 HeapTuple oldtuple;
5914 relation = table_open(InitPrivsRelationId, RowExclusiveLock);
5916 ScanKeyInit(&key[0],
5917 Anum_pg_init_privs_objoid,
5918 BTEqualStrategyNumber, F_OIDEQ,
5919 ObjectIdGetDatum(objoid));
5920 ScanKeyInit(&key[1],
5921 Anum_pg_init_privs_classoid,
5922 BTEqualStrategyNumber, F_OIDEQ,
5923 ObjectIdGetDatum(classoid));
5924 ScanKeyInit(&key[2],
5925 Anum_pg_init_privs_objsubid,
5926 BTEqualStrategyNumber, F_INT4EQ,
5927 Int32GetDatum(objsubid));
5929 scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
5930 NULL, 3, key);
5932 /* There should exist only one entry or none. */
5933 oldtuple = systable_getnext(scan);
5935 /* If we find an entry, update it with the latest ACL. */
5936 if (HeapTupleIsValid(oldtuple))
5938 Datum values[Natts_pg_init_privs];
5939 bool nulls[Natts_pg_init_privs];
5940 bool replace[Natts_pg_init_privs];
5942 /* If we have a new ACL to set, then update the row with it. */
5943 if (new_acl)
5945 MemSet(values, 0, sizeof(values));
5946 MemSet(nulls, false, sizeof(nulls));
5947 MemSet(replace, false, sizeof(replace));
5949 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
5950 replace[Anum_pg_init_privs_initprivs - 1] = true;
5952 oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
5953 values, nulls, replace);
5955 CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
5957 else
5959 /* new_acl is NULL, so delete the entry we found. */
5960 CatalogTupleDelete(relation, &oldtuple->t_self);
5963 else
5965 Datum values[Natts_pg_init_privs];
5966 bool nulls[Natts_pg_init_privs];
5969 * Only add a new entry if the new ACL is non-NULL.
5971 * If we are passed in a NULL ACL and no entry exists, we can just
5972 * fall through and do nothing.
5974 if (new_acl)
5976 /* No entry found, so add it. */
5977 MemSet(nulls, false, sizeof(nulls));
5979 values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
5980 values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
5981 values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
5983 /* This function only handles initial privileges of extensions */
5984 values[Anum_pg_init_privs_privtype - 1] =
5985 CharGetDatum(INITPRIVS_EXTENSION);
5987 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
5989 tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
5991 CatalogTupleInsert(relation, tuple);
5995 systable_endscan(scan);
5997 /* prevent error when processing objects multiple times */
5998 CommandCounterIncrement();
6000 table_close(relation, RowExclusiveLock);