1/*-------------------------------------------------------------------------
2 *
3 * aclchk.c
4 * Routines to check access control permissions.
5 *
6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/catalog/aclchk.c
12 *
13 * NOTES
14 * See acl.h.
15 *
16 *-------------------------------------------------------------------------
17 */
18#include "postgres.h"
19
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_type.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_transform.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"
78
79
80/*
81 * Internal format used by ALTER DEFAULT PRIVILEGES.
82 */
83typedef struct
84{
85 Oid roleid; /* owning role */
86 Oid nspid; /* namespace, or InvalidOid if none */
87 /* remaining fields are same as in InternalGrant: */
88 bool is_grant;
89 ObjectType objtype;
90 bool all_privs;
91 AclMode privileges;
92 List *grantees;
93 bool grant_option;
94 DropBehavior behavior;
95} InternalDefaultACL;
96
97/*
98 * When performing a binary-upgrade, pg_dump will call a function to set
99 * this variable to let us know that we need to populate the pg_init_privs
100 * table for the GRANT/REVOKE commands while this variable is set to true.
101 */
102bool binary_upgrade_record_init_privs = false;
103
104static void ExecGrantStmt_oids(InternalGrant *istmt);
105static void ExecGrant_Relation(InternalGrant *grantStmt);
106static void ExecGrant_Database(InternalGrant *grantStmt);
107static void ExecGrant_Fdw(InternalGrant *grantStmt);
108static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
109static void ExecGrant_Function(InternalGrant *grantStmt);
110static void ExecGrant_Language(InternalGrant *grantStmt);
111static void ExecGrant_Largeobject(InternalGrant *grantStmt);
112static void ExecGrant_Namespace(InternalGrant *grantStmt);
113static void ExecGrant_Tablespace(InternalGrant *grantStmt);
114static void ExecGrant_Type(InternalGrant *grantStmt);
115
116static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
117static void SetDefaultACL(InternalDefaultACL *iacls);
118
119static List *objectNamesToOids(ObjectType objtype, List *objnames);
120static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
121static List *getRelationsInNamespace(Oid namespaceId, char relkind);
122static void expand_col_privileges(List *colnames, Oid table_oid,
123 AclMode this_privileges,
124 AclMode *col_privileges,
125 int num_col_privileges);
126static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
127 AclMode this_privileges,
128 AclMode *col_privileges,
129 int num_col_privileges);
130static AclMode string_to_privilege(const char *privname);
131static const char *privilege_to_string(AclMode privilege);
132static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
133 bool all_privs, AclMode privileges,
134 Oid objectId, Oid grantorId,
135 ObjectType objtype, const char *objname,
136 AttrNumber att_number, const char *colname);
137static AclMode pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum,
138 Oid roleid, AclMode mask, AclMaskHow how);
139static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
140 Acl *new_acl);
141static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
142 Acl *new_acl);
143
144
145#ifdef ACLDEBUG
146static void
147dumpacl(Acl *acl)
148{
149 int i;
150 AclItem *aip;
151
152 elog(DEBUG2, "acl size = %d, # acls = %d",
153 ACL_SIZE(acl), ACL_NUM(acl));
154 aip = ACL_DAT(acl);
155 for (i = 0; i < ACL_NUM(acl); ++i)
156 elog(DEBUG2, " acl[%d]: %s", i,
157 DatumGetCString(DirectFunctionCall1(aclitemout,
158 PointerGetDatum(aip + i))));
159}
160#endif /* ACLDEBUG */
161
162
163/*
164 * If is_grant is true, adds the given privileges for the list of
165 * grantees to the existing old_acl. If is_grant is false, the
166 * privileges for the given grantees are removed from old_acl.
167 *
168 * NB: the original old_acl is pfree'd.
169 */
170static Acl *
171merge_acl_with_grant(Acl *old_acl, bool is_grant,
172 bool grant_option, DropBehavior behavior,
173 List *grantees, AclMode privileges,
174 Oid grantorId, Oid ownerId)
175{
176 unsigned modechg;
177 ListCell *j;
178 Acl *new_acl;
179
180 modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
181
182#ifdef ACLDEBUG
183 dumpacl(old_acl);
184#endif
185 new_acl = old_acl;
186
187 foreach(j, grantees)
188 {
189 AclItem aclitem;
190 Acl *newer_acl;
191
192 aclitem.ai_grantee = lfirst_oid(j);
193
194 /*
195 * Grant options can only be granted to individual roles, not PUBLIC.
196 * The reason is that if a user would re-grant a privilege that he
197 * held through PUBLIC, and later the user is removed, the situation
198 * is impossible to clean up.
199 */
200 if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
201 ereport(ERROR,
202 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
203 errmsg("grant options can only be granted to roles")));
204
205 aclitem.ai_grantor = grantorId;
206
207 /*
208 * The asymmetry in the conditions here comes from the spec. In
209 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
210 * to grant both the basic privilege and its grant option. But in
211 * REVOKE, plain revoke revokes both the basic privilege and its grant
212 * option, while REVOKE GRANT OPTION revokes only the option.
213 */
214 ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
215 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
216 (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
217
218 newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
219
220 /* avoid memory leak when there are many grantees */
221 pfree(new_acl);
222 new_acl = newer_acl;
223
224#ifdef ACLDEBUG
225 dumpacl(new_acl);
226#endif
227 }
228
229 return new_acl;
230}
231
232/*
233 * Restrict the privileges to what we can actually grant, and emit
234 * the standards-mandated warning and error messages.
235 */
236static AclMode
237restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
238 AclMode privileges, Oid objectId, Oid grantorId,
239 ObjectType objtype, const char *objname,
240 AttrNumber att_number, const char *colname)
241{
242 AclMode this_privileges;
243 AclMode whole_mask;
244
245 switch (objtype)
246 {
247 case OBJECT_COLUMN:
248 whole_mask = ACL_ALL_RIGHTS_COLUMN;
249 break;
250 case OBJECT_TABLE:
251 whole_mask = ACL_ALL_RIGHTS_RELATION;
252 break;
253 case OBJECT_SEQUENCE:
254 whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
255 break;
256 case OBJECT_DATABASE:
257 whole_mask = ACL_ALL_RIGHTS_DATABASE;
258 break;
259 case OBJECT_FUNCTION:
260 whole_mask = ACL_ALL_RIGHTS_FUNCTION;
261 break;
262 case OBJECT_LANGUAGE:
263 whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
264 break;
265 case OBJECT_LARGEOBJECT:
266 whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
267 break;
268 case OBJECT_SCHEMA:
269 whole_mask = ACL_ALL_RIGHTS_SCHEMA;
270 break;
271 case OBJECT_TABLESPACE:
272 whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
273 break;
274 case OBJECT_FDW:
275 whole_mask = ACL_ALL_RIGHTS_FDW;
276 break;
277 case OBJECT_FOREIGN_SERVER:
278 whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
279 break;
280 case OBJECT_EVENT_TRIGGER:
281 elog(ERROR, "grantable rights not supported for event triggers");
282 /* not reached, but keep compiler quiet */
283 return ACL_NO_RIGHTS;
284 case OBJECT_TYPE:
285 whole_mask = ACL_ALL_RIGHTS_TYPE;
286 break;
287 default:
288 elog(ERROR, "unrecognized object type: %d", objtype);
289 /* not reached, but keep compiler quiet */
290 return ACL_NO_RIGHTS;
291 }
292
293 /*
294 * If we found no grant options, consider whether to issue a hard error.
295 * Per spec, having any privilege at all on the object will get you by
296 * here.
297 */
298 if (avail_goptions == ACL_NO_RIGHTS)
299 {
300 if (pg_aclmask(objtype, objectId, att_number, grantorId,
301 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
302 ACLMASK_ANY) == ACL_NO_RIGHTS)
303 {
304 if (objtype == OBJECT_COLUMN && colname)
305 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
306 else
307 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
308 }
309 }
310
311 /*
312 * Restrict the operation to what we can actually grant or revoke, and
313 * issue a warning if appropriate. (For REVOKE this isn't quite what the
314 * spec says to do: the spec seems to want a warning only if no privilege
315 * bits actually change in the ACL. In practice that behavior seems much
316 * too noisy, as well as inconsistent with the GRANT case.)
317 */
318 this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
319 if (is_grant)
320 {
321 if (this_privileges == 0)
322 {
323 if (objtype == OBJECT_COLUMN && colname)
324 ereport(WARNING,
325 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
326 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
327 colname, objname)));
328 else
329 ereport(WARNING,
330 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
331 errmsg("no privileges were granted for \"%s\"",
332 objname)));
333 }
334 else if (!all_privs && this_privileges != privileges)
335 {
336 if (objtype == OBJECT_COLUMN && colname)
337 ereport(WARNING,
338 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
339 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
340 colname, objname)));
341 else
342 ereport(WARNING,
343 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
344 errmsg("not all privileges were granted for \"%s\"",
345 objname)));
346 }
347 }
348 else
349 {
350 if (this_privileges == 0)
351 {
352 if (objtype == OBJECT_COLUMN && colname)
353 ereport(WARNING,
354 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
355 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
356 colname, objname)));
357 else
358 ereport(WARNING,
359 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
360 errmsg("no privileges could be revoked for \"%s\"",
361 objname)));
362 }
363 else if (!all_privs && this_privileges != privileges)
364 {
365 if (objtype == OBJECT_COLUMN && colname)
366 ereport(WARNING,
367 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
368 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
369 colname, objname)));
370 else
371 ereport(WARNING,
372 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
373 errmsg("not all privileges could be revoked for \"%s\"",
374 objname)));
375 }
376 }
377
378 return this_privileges;
379}
380
381/*
382 * Called to execute the utility commands GRANT and REVOKE
383 */
384void
385ExecuteGrantStmt(GrantStmt *stmt)
386{
387 InternalGrant istmt;
388 ListCell *cell;
389 const char *errormsg;
390 AclMode all_privileges;
391
392 /*
393 * Turn the regular GrantStmt into the InternalGrant form.
394 */
395 istmt.is_grant = stmt->is_grant;
396 istmt.objtype = stmt->objtype;
397
398 /* Collect the OIDs of the target objects */
399 switch (stmt->targtype)
400 {
401 case ACL_TARGET_OBJECT:
402 istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
403 break;
404 case ACL_TARGET_ALL_IN_SCHEMA:
405 istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
406 break;
407 /* ACL_TARGET_DEFAULTS should not be seen here */
408 default:
409 elog(ERROR, "unrecognized GrantStmt.targtype: %d",
410 (int) stmt->targtype);
411 }
412
413 /* all_privs to be filled below */
414 /* privileges to be filled below */
415 istmt.col_privs = NIL; /* may get filled below */
416 istmt.grantees = NIL; /* filled below */
417 istmt.grant_option = stmt->grant_option;
418 istmt.behavior = stmt->behavior;
419
420 /*
421 * Convert the RoleSpec list into an Oid list. Note that at this point we
422 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
423 * there shouldn't be any additional work needed to support this case.
424 */
425 foreach(cell, stmt->grantees)
426 {
427 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
428 Oid grantee_uid;
429
430 switch (grantee->roletype)
431 {
432 case ROLESPEC_PUBLIC:
433 grantee_uid = ACL_ID_PUBLIC;
434 break;
435 default:
436 grantee_uid = get_rolespec_oid(grantee, false);
437 break;
438 }
439 istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
440 }
441
442 /*
443 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
444 * bitmask. Note: objtype can't be OBJECT_COLUMN.
445 */
446 switch (stmt->objtype)
447 {
448 case OBJECT_TABLE:
449
450 /*
451 * Because this might be a sequence, we test both relation and
452 * sequence bits, and later do a more limited test when we know
453 * the object type.
454 */
455 all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
456 errormsg = gettext_noop("invalid privilege type %s for relation");
457 break;
458 case OBJECT_SEQUENCE:
459 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
460 errormsg = gettext_noop("invalid privilege type %s for sequence");
461 break;
462 case OBJECT_DATABASE:
463 all_privileges = ACL_ALL_RIGHTS_DATABASE;
464 errormsg = gettext_noop("invalid privilege type %s for database");
465 break;
466 case OBJECT_DOMAIN:
467 all_privileges = ACL_ALL_RIGHTS_TYPE;
468 errormsg = gettext_noop("invalid privilege type %s for domain");
469 break;
470 case OBJECT_FUNCTION:
471 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
472 errormsg = gettext_noop("invalid privilege type %s for function");
473 break;
474 case OBJECT_LANGUAGE:
475 all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
476 errormsg = gettext_noop("invalid privilege type %s for language");
477 break;
478 case OBJECT_LARGEOBJECT:
479 all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
480 errormsg = gettext_noop("invalid privilege type %s for large object");
481 break;
482 case OBJECT_SCHEMA:
483 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
484 errormsg = gettext_noop("invalid privilege type %s for schema");
485 break;
486 case OBJECT_PROCEDURE:
487 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
488 errormsg = gettext_noop("invalid privilege type %s for procedure");
489 break;
490 case OBJECT_ROUTINE:
491 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
492 errormsg = gettext_noop("invalid privilege type %s for routine");
493 break;
494 case OBJECT_TABLESPACE:
495 all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
496 errormsg = gettext_noop("invalid privilege type %s for tablespace");
497 break;
498 case OBJECT_TYPE:
499 all_privileges = ACL_ALL_RIGHTS_TYPE;
500 errormsg = gettext_noop("invalid privilege type %s for type");
501 break;
502 case OBJECT_FDW:
503 all_privileges = ACL_ALL_RIGHTS_FDW;
504 errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
505 break;
506 case OBJECT_FOREIGN_SERVER:
507 all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
508 errormsg = gettext_noop("invalid privilege type %s for foreign server");
509 break;
510 default:
511 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
512 (int) stmt->objtype);
513 /* keep compiler quiet */
514 all_privileges = ACL_NO_RIGHTS;
515 errormsg = NULL;
516 }
517
518 if (stmt->privileges == NIL)
519 {
520 istmt.all_privs = true;
521
522 /*
523 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
524 * depending on the object type
525 */
526 istmt.privileges = ACL_NO_RIGHTS;
527 }
528 else
529 {
530 istmt.all_privs = false;
531 istmt.privileges = ACL_NO_RIGHTS;
532
533 foreach(cell, stmt->privileges)
534 {
535 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
536 AclMode priv;
537
538 /*
539 * If it's a column-level specification, we just set it aside in
540 * col_privs for the moment; but insist it's for a relation.
541 */
542 if (privnode->cols)
543 {
544 if (stmt->objtype != OBJECT_TABLE)
545 ereport(ERROR,
546 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
547 errmsg("column privileges are only valid for relations")));
548 istmt.col_privs = lappend(istmt.col_privs, privnode);
549 continue;
550 }
551
552 if (privnode->priv_name == NULL) /* parser mistake? */
553 elog(ERROR, "AccessPriv node must specify privilege or columns");
554 priv = string_to_privilege(privnode->priv_name);
555
556 if (priv & ~((AclMode) all_privileges))
557 ereport(ERROR,
558 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
559 errmsg(errormsg, privilege_to_string(priv))));
560
561 istmt.privileges |= priv;
562 }
563 }
564
565 ExecGrantStmt_oids(&istmt);
566}
567
568/*
569 * ExecGrantStmt_oids
570 *
571 * Internal entry point for granting and revoking privileges.
572 */
573static void
574ExecGrantStmt_oids(InternalGrant *istmt)
575{
576 switch (istmt->objtype)
577 {
578 case OBJECT_TABLE:
579 case OBJECT_SEQUENCE:
580 ExecGrant_Relation(istmt);
581 break;
582 case OBJECT_DATABASE:
583 ExecGrant_Database(istmt);
584 break;
585 case OBJECT_DOMAIN:
586 case OBJECT_TYPE:
587 ExecGrant_Type(istmt);
588 break;
589 case OBJECT_FDW:
590 ExecGrant_Fdw(istmt);
591 break;
592 case OBJECT_FOREIGN_SERVER:
593 ExecGrant_ForeignServer(istmt);
594 break;
595 case OBJECT_FUNCTION:
596 case OBJECT_PROCEDURE:
597 case OBJECT_ROUTINE:
598 ExecGrant_Function(istmt);
599 break;
600 case OBJECT_LANGUAGE:
601 ExecGrant_Language(istmt);
602 break;
603 case OBJECT_LARGEOBJECT:
604 ExecGrant_Largeobject(istmt);
605 break;
606 case OBJECT_SCHEMA:
607 ExecGrant_Namespace(istmt);
608 break;
609 case OBJECT_TABLESPACE:
610 ExecGrant_Tablespace(istmt);
611 break;
612 default:
613 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
614 (int) istmt->objtype);
615 }
616
617 /*
618 * Pass the info to event triggers about the just-executed GRANT. Note
619 * that we prefer to do it after actually executing it, because that gives
620 * the functions a chance to adjust the istmt with privileges actually
621 * granted.
622 */
623 if (EventTriggerSupportsObjectType(istmt->objtype))
624 EventTriggerCollectGrant(istmt);
625}
626
627/*
628 * objectNamesToOids
629 *
630 * Turn a list of object names of a given type into an Oid list.
631 *
632 * XXX: This function doesn't take any sort of locks on the objects whose
633 * names it looks up. In the face of concurrent DDL, we might easily latch
634 * onto an old version of an object, causing the GRANT or REVOKE statement
635 * to fail.
636 */
637static List *
638objectNamesToOids(ObjectType objtype, List *objnames)
639{
640 List *objects = NIL;
641 ListCell *cell;
642
643 Assert(objnames != NIL);
644
645 switch (objtype)
646 {
647 case OBJECT_TABLE:
648 case OBJECT_SEQUENCE:
649 foreach(cell, objnames)
650 {
651 RangeVar *relvar = (RangeVar *) lfirst(cell);
652 Oid relOid;
653
654 relOid = RangeVarGetRelid(relvar, NoLock, false);
655 objects = lappend_oid(objects, relOid);
656 }
657 break;
658 case OBJECT_DATABASE:
659 foreach(cell, objnames)
660 {
661 char *dbname = strVal(lfirst(cell));
662 Oid dbid;
663
664 dbid = get_database_oid(dbname, false);
665 objects = lappend_oid(objects, dbid);
666 }
667 break;
668 case OBJECT_DOMAIN:
669 case OBJECT_TYPE:
670 foreach(cell, objnames)
671 {
672 List *typname = (List *) lfirst(cell);
673 Oid oid;
674
675 oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
676 objects = lappend_oid(objects, oid);
677 }
678 break;
679 case OBJECT_FUNCTION:
680 foreach(cell, objnames)
681 {
682 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
683 Oid funcid;
684
685 funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
686 objects = lappend_oid(objects, funcid);
687 }
688 break;
689 case OBJECT_LANGUAGE:
690 foreach(cell, objnames)
691 {
692 char *langname = strVal(lfirst(cell));
693 Oid oid;
694
695 oid = get_language_oid(langname, false);
696 objects = lappend_oid(objects, oid);
697 }
698 break;
699 case OBJECT_LARGEOBJECT:
700 foreach(cell, objnames)
701 {
702 Oid lobjOid = oidparse(lfirst(cell));
703
704 if (!LargeObjectExists(lobjOid))
705 ereport(ERROR,
706 (errcode(ERRCODE_UNDEFINED_OBJECT),
707 errmsg("large object %u does not exist",
708 lobjOid)));
709
710 objects = lappend_oid(objects, lobjOid);
711 }
712 break;
713 case OBJECT_SCHEMA:
714 foreach(cell, objnames)
715 {
716 char *nspname = strVal(lfirst(cell));
717 Oid oid;
718
719 oid = get_namespace_oid(nspname, false);
720 objects = lappend_oid(objects, oid);
721 }
722 break;
723 case OBJECT_PROCEDURE:
724 foreach(cell, objnames)
725 {
726 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
727 Oid procid;
728
729 procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
730 objects = lappend_oid(objects, procid);
731 }
732 break;
733 case OBJECT_ROUTINE:
734 foreach(cell, objnames)
735 {
736 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
737 Oid routid;
738
739 routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
740 objects = lappend_oid(objects, routid);
741 }
742 break;
743 case OBJECT_TABLESPACE:
744 foreach(cell, objnames)
745 {
746 char *spcname = strVal(lfirst(cell));
747 Oid spcoid;
748
749 spcoid = get_tablespace_oid(spcname, false);
750 objects = lappend_oid(objects, spcoid);
751 }
752 break;
753 case OBJECT_FDW:
754 foreach(cell, objnames)
755 {
756 char *fdwname = strVal(lfirst(cell));
757 Oid fdwid = get_foreign_data_wrapper_oid(fdwname, false);
758
759 objects = lappend_oid(objects, fdwid);
760 }
761 break;
762 case OBJECT_FOREIGN_SERVER:
763 foreach(cell, objnames)
764 {
765 char *srvname = strVal(lfirst(cell));
766 Oid srvid = get_foreign_server_oid(srvname, false);
767
768 objects = lappend_oid(objects, srvid);
769 }
770 break;
771 default:
772 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
773 (int) objtype);
774 }
775
776 return objects;
777}
778
779/*
780 * objectsInSchemaToOids
781 *
782 * Find all objects of a given type in specified schemas, and make a list
783 * of their Oids. We check USAGE privilege on the schemas, but there is
784 * no privilege checking on the individual objects here.
785 */
786static List *
787objectsInSchemaToOids(ObjectType objtype, List *nspnames)
788{
789 List *objects = NIL;
790 ListCell *cell;
791
792 foreach(cell, nspnames)
793 {
794 char *nspname = strVal(lfirst(cell));
795 Oid namespaceId;
796 List *objs;
797
798 namespaceId = LookupExplicitNamespace(nspname, false);
799
800 switch (objtype)
801 {
802 case OBJECT_TABLE:
803 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
804 objects = list_concat(objects, objs);
805 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
806 objects = list_concat(objects, objs);
807 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
808 objects = list_concat(objects, objs);
809 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
810 objects = list_concat(objects, objs);
811 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
812 objects = list_concat(objects, objs);
813 break;
814 case OBJECT_SEQUENCE:
815 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
816 objects = list_concat(objects, objs);
817 break;
818 case OBJECT_FUNCTION:
819 case OBJECT_PROCEDURE:
820 case OBJECT_ROUTINE:
821 {
822 ScanKeyData key[2];
823 int keycount;
824 Relation rel;
825 TableScanDesc scan;
826 HeapTuple tuple;
827
828 keycount = 0;
829 ScanKeyInit(&key[keycount++],
830 Anum_pg_proc_pronamespace,
831 BTEqualStrategyNumber, F_OIDEQ,
832 ObjectIdGetDatum(namespaceId));
833
834 if (objtype == OBJECT_FUNCTION)
835 /* includes aggregates and window functions */
836 ScanKeyInit(&key[keycount++],
837 Anum_pg_proc_prokind,
838 BTEqualStrategyNumber, F_CHARNE,
839 CharGetDatum(PROKIND_PROCEDURE));
840 else if (objtype == OBJECT_PROCEDURE)
841 ScanKeyInit(&key[keycount++],
842 Anum_pg_proc_prokind,
843 BTEqualStrategyNumber, F_CHAREQ,
844 CharGetDatum(PROKIND_PROCEDURE));
845
846 rel = table_open(ProcedureRelationId, AccessShareLock);
847 scan = table_beginscan_catalog(rel, keycount, key);
848
849 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
850 {
851 Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
852
853 objects = lappend_oid(objects, oid);
854 }
855
856 table_endscan(scan);
857 table_close(rel, AccessShareLock);
858 }
859 break;
860 default:
861 /* should not happen */
862 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
863 (int) objtype);
864 }
865 }
866
867 return objects;
868}
869
870/*
871 * getRelationsInNamespace
872 *
873 * Return Oid list of relations in given namespace filtered by relation kind
874 */
875static List *
876getRelationsInNamespace(Oid namespaceId, char relkind)
877{
878 List *relations = NIL;
879 ScanKeyData key[2];
880 Relation rel;
881 TableScanDesc scan;
882 HeapTuple tuple;
883
884 ScanKeyInit(&key[0],
885 Anum_pg_class_relnamespace,
886 BTEqualStrategyNumber, F_OIDEQ,
887 ObjectIdGetDatum(namespaceId));
888 ScanKeyInit(&key[1],
889 Anum_pg_class_relkind,
890 BTEqualStrategyNumber, F_CHAREQ,
891 CharGetDatum(relkind));
892
893 rel = table_open(RelationRelationId, AccessShareLock);
894 scan = table_beginscan_catalog(rel, 2, key);
895
896 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
897 {
898 Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
899
900 relations = lappend_oid(relations, oid);
901 }
902
903 table_endscan(scan);
904 table_close(rel, AccessShareLock);
905
906 return relations;
907}
908
909
910/*
911 * ALTER DEFAULT PRIVILEGES statement
912 */
913void
914ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
915{
916 GrantStmt *action = stmt->action;
917 InternalDefaultACL iacls;
918 ListCell *cell;
919 List *rolespecs = NIL;
920 List *nspnames = NIL;
921 DefElem *drolespecs = NULL;
922 DefElem *dnspnames = NULL;
923 AclMode all_privileges;
924 const char *errormsg;
925
926 /* Deconstruct the "options" part of the statement */
927 foreach(cell, stmt->options)
928 {
929 DefElem *defel = (DefElem *) lfirst(cell);
930
931 if (strcmp(defel->defname, "schemas") == 0)
932 {
933 if (dnspnames)
934 ereport(ERROR,
935 (errcode(ERRCODE_SYNTAX_ERROR),
936 errmsg("conflicting or redundant options"),
937 parser_errposition(pstate, defel->location)));
938 dnspnames = defel;
939 }
940 else if (strcmp(defel->defname, "roles") == 0)
941 {
942 if (drolespecs)
943 ereport(ERROR,
944 (errcode(ERRCODE_SYNTAX_ERROR),
945 errmsg("conflicting or redundant options"),
946 parser_errposition(pstate, defel->location)));
947 drolespecs = defel;
948 }
949 else
950 elog(ERROR, "option \"%s\" not recognized", defel->defname);
951 }
952
953 if (dnspnames)
954 nspnames = (List *) dnspnames->arg;
955 if (drolespecs)
956 rolespecs = (List *) drolespecs->arg;
957
958 /* Prepare the InternalDefaultACL representation of the statement */
959 /* roleid to be filled below */
960 /* nspid to be filled in SetDefaultACLsInSchemas */
961 iacls.is_grant = action->is_grant;
962 iacls.objtype = action->objtype;
963 /* all_privs to be filled below */
964 /* privileges to be filled below */
965 iacls.grantees = NIL; /* filled below */
966 iacls.grant_option = action->grant_option;
967 iacls.behavior = action->behavior;
968
969 /*
970 * Convert the RoleSpec list into an Oid list. Note that at this point we
971 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
972 * there shouldn't be any additional work needed to support this case.
973 */
974 foreach(cell, action->grantees)
975 {
976 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
977 Oid grantee_uid;
978
979 switch (grantee->roletype)
980 {
981 case ROLESPEC_PUBLIC:
982 grantee_uid = ACL_ID_PUBLIC;
983 break;
984 default:
985 grantee_uid = get_rolespec_oid(grantee, false);
986 break;
987 }
988 iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
989 }
990
991 /*
992 * Convert action->privileges, a list of privilege strings, into an
993 * AclMode bitmask.
994 */
995 switch (action->objtype)
996 {
997 case OBJECT_TABLE:
998 all_privileges = ACL_ALL_RIGHTS_RELATION;
999 errormsg = gettext_noop("invalid privilege type %s for relation");
1000 break;
1001 case OBJECT_SEQUENCE:
1002 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1003 errormsg = gettext_noop("invalid privilege type %s for sequence");
1004 break;
1005 case OBJECT_FUNCTION:
1006 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1007 errormsg = gettext_noop("invalid privilege type %s for function");
1008 break;
1009 case OBJECT_PROCEDURE:
1010 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1011 errormsg = gettext_noop("invalid privilege type %s for procedure");
1012 break;
1013 case OBJECT_ROUTINE:
1014 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1015 errormsg = gettext_noop("invalid privilege type %s for routine");
1016 break;
1017 case OBJECT_TYPE:
1018 all_privileges = ACL_ALL_RIGHTS_TYPE;
1019 errormsg = gettext_noop("invalid privilege type %s for type");
1020 break;
1021 case OBJECT_SCHEMA:
1022 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
1023 errormsg = gettext_noop("invalid privilege type %s for schema");
1024 break;
1025 default:
1026 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1027 (int) action->objtype);
1028 /* keep compiler quiet */
1029 all_privileges = ACL_NO_RIGHTS;
1030 errormsg = NULL;
1031 }
1032
1033 if (action->privileges == NIL)
1034 {
1035 iacls.all_privs = true;
1036
1037 /*
1038 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1039 * depending on the object type
1040 */
1041 iacls.privileges = ACL_NO_RIGHTS;
1042 }
1043 else
1044 {
1045 iacls.all_privs = false;
1046 iacls.privileges = ACL_NO_RIGHTS;
1047
1048 foreach(cell, action->privileges)
1049 {
1050 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1051 AclMode priv;
1052
1053 if (privnode->cols)
1054 ereport(ERROR,
1055 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1056 errmsg("default privileges cannot be set for columns")));
1057
1058 if (privnode->priv_name == NULL) /* parser mistake? */
1059 elog(ERROR, "AccessPriv node must specify privilege");
1060 priv = string_to_privilege(privnode->priv_name);
1061
1062 if (priv & ~((AclMode) all_privileges))
1063 ereport(ERROR,
1064 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1065 errmsg(errormsg, privilege_to_string(priv))));
1066
1067 iacls.privileges |= priv;
1068 }
1069 }
1070
1071 if (rolespecs == NIL)
1072 {
1073 /* Set permissions for myself */
1074 iacls.roleid = GetUserId();
1075
1076 SetDefaultACLsInSchemas(&iacls, nspnames);
1077 }
1078 else
1079 {
1080 /* Look up the role OIDs and do permissions checks */
1081 ListCell *rolecell;
1082
1083 foreach(rolecell, rolespecs)
1084 {
1085 RoleSpec *rolespec = lfirst(rolecell);
1086
1087 iacls.roleid = get_rolespec_oid(rolespec, false);
1088
1089 /*
1090 * We insist that calling user be a member of each target role. If
1091 * he has that, he could become that role anyway via SET ROLE, so
1092 * FOR ROLE is just a syntactic convenience and doesn't give any
1093 * special privileges.
1094 */
1095 check_is_member_of_role(GetUserId(), iacls.roleid);
1096
1097 SetDefaultACLsInSchemas(&iacls, nspnames);
1098 }
1099 }
1100}
1101
1102/*
1103 * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1104 *
1105 * All fields of *iacls except nspid were filled already
1106 */
1107static void
1108SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
1109{
1110 if (nspnames == NIL)
1111 {
1112 /* Set database-wide permissions if no schema was specified */
1113 iacls->nspid = InvalidOid;
1114
1115 SetDefaultACL(iacls);
1116 }
1117 else
1118 {
1119 /* Look up the schema OIDs and set permissions for each one */
1120 ListCell *nspcell;
1121
1122 foreach(nspcell, nspnames)
1123 {
1124 char *nspname = strVal(lfirst(nspcell));
1125
1126 iacls->nspid = get_namespace_oid(nspname, false);
1127
1128 /*
1129 * We used to insist that the target role have CREATE privileges
1130 * on the schema, since without that it wouldn't be able to create
1131 * an object for which these default privileges would apply.
1132 * However, this check proved to be more confusing than helpful,
1133 * and it also caused certain database states to not be
1134 * dumpable/restorable, since revoking CREATE doesn't cause
1135 * default privileges for the schema to go away. So now, we just
1136 * allow the ALTER; if the user lacks CREATE he'll find out when
1137 * he tries to create an object.
1138 */
1139
1140 SetDefaultACL(iacls);
1141 }
1142 }
1143}
1144
1145
1146/*
1147 * Create or update a pg_default_acl entry
1148 */
1149static void
1150SetDefaultACL(InternalDefaultACL *iacls)
1151{
1152 AclMode this_privileges = iacls->privileges;
1153 char objtype;
1154 Relation rel;
1155 HeapTuple tuple;
1156 bool isNew;
1157 Acl *def_acl;
1158 Acl *old_acl;
1159 Acl *new_acl;
1160 HeapTuple newtuple;
1161 Datum values[Natts_pg_default_acl];
1162 bool nulls[Natts_pg_default_acl];
1163 bool replaces[Natts_pg_default_acl];
1164 int noldmembers;
1165 int nnewmembers;
1166 Oid *oldmembers;
1167 Oid *newmembers;
1168
1169 rel = table_open(DefaultAclRelationId, RowExclusiveLock);
1170
1171 /*
1172 * The default for a global entry is the hard-wired default ACL for the
1173 * particular object type. The default for non-global entries is an empty
1174 * ACL. This must be so because global entries replace the hard-wired
1175 * defaults, while others are added on.
1176 */
1177 if (!OidIsValid(iacls->nspid))
1178 def_acl = acldefault(iacls->objtype, iacls->roleid);
1179 else
1180 def_acl = make_empty_acl();
1181
1182 /*
1183 * Convert ACL object type to pg_default_acl object type and handle
1184 * all_privs option
1185 */
1186 switch (iacls->objtype)
1187 {
1188 case OBJECT_TABLE:
1189 objtype = DEFACLOBJ_RELATION;
1190 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1191 this_privileges = ACL_ALL_RIGHTS_RELATION;
1192 break;
1193
1194 case OBJECT_SEQUENCE:
1195 objtype = DEFACLOBJ_SEQUENCE;
1196 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1197 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1198 break;
1199
1200 case OBJECT_FUNCTION:
1201 objtype = DEFACLOBJ_FUNCTION;
1202 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1203 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
1204 break;
1205
1206 case OBJECT_TYPE:
1207 objtype = DEFACLOBJ_TYPE;
1208 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1209 this_privileges = ACL_ALL_RIGHTS_TYPE;
1210 break;
1211
1212 case OBJECT_SCHEMA:
1213 if (OidIsValid(iacls->nspid))
1214 ereport(ERROR,
1215 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1216 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1217 objtype = DEFACLOBJ_NAMESPACE;
1218 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1219 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1220 break;
1221
1222 default:
1223 elog(ERROR, "unrecognized objtype: %d",
1224 (int) iacls->objtype);
1225 objtype = 0; /* keep compiler quiet */
1226 break;
1227 }
1228
1229 /* Search for existing row for this object type in catalog */
1230 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1231 ObjectIdGetDatum(iacls->roleid),
1232 ObjectIdGetDatum(iacls->nspid),
1233 CharGetDatum(objtype));
1234
1235 if (HeapTupleIsValid(tuple))
1236 {
1237 Datum aclDatum;
1238 bool isNull;
1239
1240 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1241 Anum_pg_default_acl_defaclacl,
1242 &isNull);
1243 if (!isNull)
1244 old_acl = DatumGetAclPCopy(aclDatum);
1245 else
1246 old_acl = NULL; /* this case shouldn't happen, probably */
1247 isNew = false;
1248 }
1249 else
1250 {
1251 old_acl = NULL;
1252 isNew = true;
1253 }
1254
1255 if (old_acl != NULL)
1256 {
1257 /*
1258 * We need the members of both old and new ACLs so we can correct the
1259 * shared dependency information. Collect data before
1260 * merge_acl_with_grant throws away old_acl.
1261 */
1262 noldmembers = aclmembers(old_acl, &oldmembers);
1263 }
1264 else
1265 {
1266 /* If no or null entry, start with the default ACL value */
1267 old_acl = aclcopy(def_acl);
1268 /* There are no old member roles according to the catalogs */
1269 noldmembers = 0;
1270 oldmembers = NULL;
1271 }
1272
1273 /*
1274 * Generate new ACL. Grantor of rights is always the same as the target
1275 * role.
1276 */
1277 new_acl = merge_acl_with_grant(old_acl,
1278 iacls->is_grant,
1279 iacls->grant_option,
1280 iacls->behavior,
1281 iacls->grantees,
1282 this_privileges,
1283 iacls->roleid,
1284 iacls->roleid);
1285
1286 /*
1287 * If the result is the same as the default value, we do not need an
1288 * explicit pg_default_acl entry, and should in fact remove the entry if
1289 * it exists. Must sort both arrays to compare properly.
1290 */
1291 aclitemsort(new_acl);
1292 aclitemsort(def_acl);
1293 if (aclequal(new_acl, def_acl))
1294 {
1295 /* delete old entry, if indeed there is one */
1296 if (!isNew)
1297 {
1298 ObjectAddress myself;
1299
1300 /*
1301 * The dependency machinery will take care of removing all
1302 * associated dependency entries. We use DROP_RESTRICT since
1303 * there shouldn't be anything depending on this entry.
1304 */
1305 myself.classId = DefaultAclRelationId;
1306 myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1307 myself.objectSubId = 0;
1308
1309 performDeletion(&myself, DROP_RESTRICT, 0);
1310 }
1311 }
1312 else
1313 {
1314 Oid defAclOid;
1315
1316 /* Prepare to insert or update pg_default_acl entry */
1317 MemSet(values, 0, sizeof(values));
1318 MemSet(nulls, false, sizeof(nulls));
1319 MemSet(replaces, false, sizeof(replaces));
1320
1321 if (isNew)
1322 {
1323 /* insert new entry */
1324 defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1325 Anum_pg_default_acl_oid);
1326 values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1327 values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1328 values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1329 values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1330 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1331
1332 newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1333 CatalogTupleInsert(rel, newtuple);
1334 }
1335 else
1336 {
1337 defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1338
1339 /* update existing entry */
1340 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1341 replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1342
1343 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1344 values, nulls, replaces);
1345 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1346 }
1347
1348 /* these dependencies don't change in an update */
1349 if (isNew)
1350 {
1351 /* dependency on role */
1352 recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1353 iacls->roleid);
1354
1355 /* dependency on namespace */
1356 if (OidIsValid(iacls->nspid))
1357 {
1358 ObjectAddress myself,
1359 referenced;
1360
1361 myself.classId = DefaultAclRelationId;
1362 myself.objectId = defAclOid;
1363 myself.objectSubId = 0;
1364
1365 referenced.classId = NamespaceRelationId;
1366 referenced.objectId = iacls->nspid;
1367 referenced.objectSubId = 0;
1368
1369 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1370 }
1371 }
1372
1373 /*
1374 * Update the shared dependency ACL info
1375 */
1376 nnewmembers = aclmembers(new_acl, &newmembers);
1377
1378 updateAclDependencies(DefaultAclRelationId,
1379 defAclOid, 0,
1380 iacls->roleid,
1381 noldmembers, oldmembers,
1382 nnewmembers, newmembers);
1383
1384 if (isNew)
1385 InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1386 else
1387 InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1388 }
1389
1390 if (HeapTupleIsValid(tuple))
1391 ReleaseSysCache(tuple);
1392
1393 table_close(rel, RowExclusiveLock);
1394}
1395
1396
1397/*
1398 * RemoveRoleFromObjectACL
1399 *
1400 * Used by shdepDropOwned to remove mentions of a role in ACLs
1401 */
1402void
1403RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1404{
1405 if (classid == DefaultAclRelationId)
1406 {
1407 InternalDefaultACL iacls;
1408 Form_pg_default_acl pg_default_acl_tuple;
1409 Relation rel;
1410 ScanKeyData skey[1];
1411 SysScanDesc scan;
1412 HeapTuple tuple;
1413
1414 /* first fetch info needed by SetDefaultACL */
1415 rel = table_open(DefaultAclRelationId, AccessShareLock);
1416
1417 ScanKeyInit(&skey[0],
1418 Anum_pg_default_acl_oid,
1419 BTEqualStrategyNumber, F_OIDEQ,
1420 ObjectIdGetDatum(objid));
1421
1422 scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1423 NULL, 1, skey);
1424
1425 tuple = systable_getnext(scan);
1426
1427 if (!HeapTupleIsValid(tuple))
1428 elog(ERROR, "could not find tuple for default ACL %u", objid);
1429
1430 pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1431
1432 iacls.roleid = pg_default_acl_tuple->defaclrole;
1433 iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1434
1435 switch (pg_default_acl_tuple->defaclobjtype)
1436 {
1437 case DEFACLOBJ_RELATION:
1438 iacls.objtype = OBJECT_TABLE;
1439 break;
1440 case DEFACLOBJ_SEQUENCE:
1441 iacls.objtype = OBJECT_SEQUENCE;
1442 break;
1443 case DEFACLOBJ_FUNCTION:
1444 iacls.objtype = OBJECT_FUNCTION;
1445 break;
1446 case DEFACLOBJ_TYPE:
1447 iacls.objtype = OBJECT_TYPE;
1448 break;
1449 case DEFACLOBJ_NAMESPACE:
1450 iacls.objtype = OBJECT_SCHEMA;
1451 break;
1452 default:
1453 /* Shouldn't get here */
1454 elog(ERROR, "unexpected default ACL type: %d",
1455 (int) pg_default_acl_tuple->defaclobjtype);
1456 break;
1457 }
1458
1459 systable_endscan(scan);
1460 table_close(rel, AccessShareLock);
1461
1462 iacls.is_grant = false;
1463 iacls.all_privs = true;
1464 iacls.privileges = ACL_NO_RIGHTS;
1465 iacls.grantees = list_make1_oid(roleid);
1466 iacls.grant_option = false;
1467 iacls.behavior = DROP_CASCADE;
1468
1469 /* Do it */
1470 SetDefaultACL(&iacls);
1471 }
1472 else
1473 {
1474 InternalGrant istmt;
1475
1476 switch (classid)
1477 {
1478 case RelationRelationId:
1479 /* it's OK to use TABLE for a sequence */
1480 istmt.objtype = OBJECT_TABLE;
1481 break;
1482 case DatabaseRelationId:
1483 istmt.objtype = OBJECT_DATABASE;
1484 break;
1485 case TypeRelationId:
1486 istmt.objtype = OBJECT_TYPE;
1487 break;
1488 case ProcedureRelationId:
1489 istmt.objtype = OBJECT_ROUTINE;
1490 break;
1491 case LanguageRelationId:
1492 istmt.objtype = OBJECT_LANGUAGE;
1493 break;
1494 case LargeObjectRelationId:
1495 istmt.objtype = OBJECT_LARGEOBJECT;
1496 break;
1497 case NamespaceRelationId:
1498 istmt.objtype = OBJECT_SCHEMA;
1499 break;
1500 case TableSpaceRelationId:
1501 istmt.objtype = OBJECT_TABLESPACE;
1502 break;
1503 case ForeignServerRelationId:
1504 istmt.objtype = OBJECT_FOREIGN_SERVER;
1505 break;
1506 case ForeignDataWrapperRelationId:
1507 istmt.objtype = OBJECT_FDW;
1508 break;
1509 default:
1510 elog(ERROR, "unexpected object class %u", classid);
1511 break;
1512 }
1513 istmt.is_grant = false;
1514 istmt.objects = list_make1_oid(objid);
1515 istmt.all_privs = true;
1516 istmt.privileges = ACL_NO_RIGHTS;
1517 istmt.col_privs = NIL;
1518 istmt.grantees = list_make1_oid(roleid);
1519 istmt.grant_option = false;
1520 istmt.behavior = DROP_CASCADE;
1521
1522 ExecGrantStmt_oids(&istmt);
1523 }
1524}
1525
1526
1527/*
1528 * Remove a pg_default_acl entry
1529 */
1530void
1531RemoveDefaultACLById(Oid defaclOid)
1532{
1533 Relation rel;
1534 ScanKeyData skey[1];
1535 SysScanDesc scan;
1536 HeapTuple tuple;
1537
1538 rel = table_open(DefaultAclRelationId, RowExclusiveLock);
1539
1540 ScanKeyInit(&skey[0],
1541 Anum_pg_default_acl_oid,
1542 BTEqualStrategyNumber, F_OIDEQ,
1543 ObjectIdGetDatum(defaclOid));
1544
1545 scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1546 NULL, 1, skey);
1547
1548 tuple = systable_getnext(scan);
1549
1550 if (!HeapTupleIsValid(tuple))
1551 elog(ERROR, "could not find tuple for default ACL %u", defaclOid);
1552
1553 CatalogTupleDelete(rel, &tuple->t_self);
1554
1555 systable_endscan(scan);
1556 table_close(rel, RowExclusiveLock);
1557}
1558
1559
1560/*
1561 * expand_col_privileges
1562 *
1563 * OR the specified privilege(s) into per-column array entries for each
1564 * specified attribute. The per-column array is indexed starting at
1565 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1566 */
1567static void
1568expand_col_privileges(List *colnames, Oid table_oid,
1569 AclMode this_privileges,
1570 AclMode *col_privileges,
1571 int num_col_privileges)
1572{
1573 ListCell *cell;
1574
1575 foreach(cell, colnames)
1576 {
1577 char *colname = strVal(lfirst(cell));
1578 AttrNumber attnum;
1579
1580 attnum = get_attnum(table_oid, colname);
1581 if (attnum == InvalidAttrNumber)
1582 ereport(ERROR,
1583 (errcode(ERRCODE_UNDEFINED_COLUMN),
1584 errmsg("column \"%s\" of relation \"%s\" does not exist",
1585 colname, get_rel_name(table_oid))));
1586 attnum -= FirstLowInvalidHeapAttributeNumber;
1587 if (attnum <= 0 || attnum >= num_col_privileges)
1588 elog(ERROR, "column number out of range"); /* safety check */
1589 col_privileges[attnum] |= this_privileges;
1590 }
1591}
1592
1593/*
1594 * expand_all_col_privileges
1595 *
1596 * OR the specified privilege(s) into per-column array entries for each valid
1597 * attribute of a relation. The per-column array is indexed starting at
1598 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1599 */
1600static void
1601expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
1602 AclMode this_privileges,
1603 AclMode *col_privileges,
1604 int num_col_privileges)
1605{
1606 AttrNumber curr_att;
1607
1608 Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1609 for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1610 curr_att <= classForm->relnatts;
1611 curr_att++)
1612 {
1613 HeapTuple attTuple;
1614 bool isdropped;
1615
1616 if (curr_att == InvalidAttrNumber)
1617 continue;
1618
1619 /* Views don't have any system columns at all */
1620 if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1621 continue;
1622
1623 attTuple = SearchSysCache2(ATTNUM,
1624 ObjectIdGetDatum(table_oid),
1625 Int16GetDatum(curr_att));
1626 if (!HeapTupleIsValid(attTuple))
1627 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1628 curr_att, table_oid);
1629
1630 isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1631
1632 ReleaseSysCache(attTuple);
1633
1634 /* ignore dropped columns */
1635 if (isdropped)
1636 continue;
1637
1638 col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1639 }
1640}
1641
1642/*
1643 * This processes attributes, but expects to be called from
1644 * ExecGrant_Relation, not directly from ExecGrantStmt.
1645 */
1646static void
1647ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1648 AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1649 Relation attRelation, const Acl *old_rel_acl)
1650{
1651 HeapTuple attr_tuple;
1652 Form_pg_attribute pg_attribute_tuple;
1653 Acl *old_acl;
1654 Acl *new_acl;
1655 Acl *merged_acl;
1656 Datum aclDatum;
1657 bool isNull;
1658 Oid grantorId;
1659 AclMode avail_goptions;
1660 bool need_update;
1661 HeapTuple newtuple;
1662 Datum values[Natts_pg_attribute];
1663 bool nulls[Natts_pg_attribute];
1664 bool replaces[Natts_pg_attribute];
1665 int noldmembers;
1666 int nnewmembers;
1667 Oid *oldmembers;
1668 Oid *newmembers;
1669
1670 attr_tuple = SearchSysCache2(ATTNUM,
1671 ObjectIdGetDatum(relOid),
1672 Int16GetDatum(attnum));
1673 if (!HeapTupleIsValid(attr_tuple))
1674 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1675 attnum, relOid);
1676 pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1677
1678 /*
1679 * Get working copy of existing ACL. If there's no ACL, substitute the
1680 * proper default.
1681 */
1682 aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1683 &isNull);
1684 if (isNull)
1685 {
1686 old_acl = acldefault(OBJECT_COLUMN, ownerId);
1687 /* There are no old member roles according to the catalogs */
1688 noldmembers = 0;
1689 oldmembers = NULL;
1690 }
1691 else
1692 {
1693 old_acl = DatumGetAclPCopy(aclDatum);
1694 /* Get the roles mentioned in the existing ACL */
1695 noldmembers = aclmembers(old_acl, &oldmembers);
1696 }
1697
1698 /*
1699 * In select_best_grantor we should consider existing table-level ACL bits
1700 * as well as the per-column ACL. Build a new ACL that is their
1701 * concatenation. (This is a bit cheap and dirty compared to merging them
1702 * properly with no duplications, but it's all we need here.)
1703 */
1704 merged_acl = aclconcat(old_rel_acl, old_acl);
1705
1706 /* Determine ID to do the grant as, and available grant options */
1707 select_best_grantor(GetUserId(), col_privileges,
1708 merged_acl, ownerId,
1709 &grantorId, &avail_goptions);
1710
1711 pfree(merged_acl);
1712
1713 /*
1714 * Restrict the privileges to what we can actually grant, and emit the
1715 * standards-mandated warning and error messages. Note: we don't track
1716 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1717 * each column; we just approximate it by whether all the possible
1718 * privileges are specified now. Since the all_privs flag only determines
1719 * whether a warning is issued, this seems close enough.
1720 */
1721 col_privileges =
1722 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1723 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1724 col_privileges,
1725 relOid, grantorId, OBJECT_COLUMN,
1726 relname, attnum,
1727 NameStr(pg_attribute_tuple->attname));
1728
1729 /*
1730 * Generate new ACL.
1731 */
1732 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1733 istmt->grant_option,
1734 istmt->behavior, istmt->grantees,
1735 col_privileges, grantorId,
1736 ownerId);
1737
1738 /*
1739 * We need the members of both old and new ACLs so we can correct the
1740 * shared dependency information.
1741 */
1742 nnewmembers = aclmembers(new_acl, &newmembers);
1743
1744 /* finished building new ACL value, now insert it */
1745 MemSet(values, 0, sizeof(values));
1746 MemSet(nulls, false, sizeof(nulls));
1747 MemSet(replaces, false, sizeof(replaces));
1748
1749 /*
1750 * If the updated ACL is empty, we can set attacl to null, and maybe even
1751 * avoid an update of the pg_attribute row. This is worth testing because
1752 * we'll come through here multiple times for any relation-level REVOKE,
1753 * even if there were never any column GRANTs. Note we are assuming that
1754 * the "default" ACL state for columns is empty.
1755 */
1756 if (ACL_NUM(new_acl) > 0)
1757 {
1758 values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1759 need_update = true;
1760 }
1761 else
1762 {
1763 nulls[Anum_pg_attribute_attacl - 1] = true;
1764 need_update = !isNull;
1765 }
1766 replaces[Anum_pg_attribute_attacl - 1] = true;
1767
1768 if (need_update)
1769 {
1770 newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1771 values, nulls, replaces);
1772
1773 CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1774
1775 /* Update initial privileges for extensions */
1776 recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1777 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1778
1779 /* Update the shared dependency ACL info */
1780 updateAclDependencies(RelationRelationId, relOid, attnum,
1781 ownerId,
1782 noldmembers, oldmembers,
1783 nnewmembers, newmembers);
1784 }
1785
1786 pfree(new_acl);
1787
1788 ReleaseSysCache(attr_tuple);
1789}
1790
1791/*
1792 * This processes both sequences and non-sequences.
1793 */
1794static void
1795ExecGrant_Relation(InternalGrant *istmt)
1796{
1797 Relation relation;
1798 Relation attRelation;
1799 ListCell *cell;
1800
1801 relation = table_open(RelationRelationId, RowExclusiveLock);
1802 attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1803
1804 foreach(cell, istmt->objects)
1805 {
1806 Oid relOid = lfirst_oid(cell);
1807 Datum aclDatum;
1808 Form_pg_class pg_class_tuple;
1809 bool isNull;
1810 AclMode this_privileges;
1811 AclMode *col_privileges;
1812 int num_col_privileges;
1813 bool have_col_privileges;
1814 Acl *old_acl;
1815 Acl *old_rel_acl;
1816 int noldmembers;
1817 Oid *oldmembers;
1818 Oid ownerId;
1819 HeapTuple tuple;
1820 ListCell *cell_colprivs;
1821
1822 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1823 if (!HeapTupleIsValid(tuple))
1824 elog(ERROR, "cache lookup failed for relation %u", relOid);
1825 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1826
1827 /* Not sensible to grant on an index */
1828 if (pg_class_tuple->relkind == RELKIND_INDEX ||
1829 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1830 ereport(ERROR,
1831 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1832 errmsg("\"%s\" is an index",
1833 NameStr(pg_class_tuple->relname))));
1834
1835 /* Composite types aren't tables either */
1836 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1837 ereport(ERROR,
1838 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1839 errmsg("\"%s\" is a composite type",
1840 NameStr(pg_class_tuple->relname))));
1841
1842 /* Used GRANT SEQUENCE on a non-sequence? */
1843 if (istmt->objtype == OBJECT_SEQUENCE &&
1844 pg_class_tuple->relkind != RELKIND_SEQUENCE)
1845 ereport(ERROR,
1846 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1847 errmsg("\"%s\" is not a sequence",
1848 NameStr(pg_class_tuple->relname))));
1849
1850 /* Adjust the default permissions based on object type */
1851 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1852 {
1853 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1854 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1855 else
1856 this_privileges = ACL_ALL_RIGHTS_RELATION;
1857 }
1858 else
1859 this_privileges = istmt->privileges;
1860
1861 /*
1862 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1863 * so we have to look at the relkind to determine the supported
1864 * permissions. The OR of table and sequence permissions were already
1865 * checked.
1866 */
1867 if (istmt->objtype == OBJECT_TABLE)
1868 {
1869 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1870 {
1871 /*
1872 * For backward compatibility, just throw a warning for
1873 * invalid sequence permissions when using the non-sequence
1874 * GRANT syntax.
1875 */
1876 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1877 {
1878 /*
1879 * Mention the object name because the user needs to know
1880 * which operations succeeded. This is required because
1881 * WARNING allows the command to continue.
1882 */
1883 ereport(WARNING,
1884 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1885 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1886 NameStr(pg_class_tuple->relname))));
1887 this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1888 }
1889 }
1890 else
1891 {
1892 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1893 {
1894 /*
1895 * USAGE is the only permission supported by sequences but
1896 * not by non-sequences. Don't mention the object name
1897 * because we didn't in the combined TABLE | SEQUENCE
1898 * check.
1899 */
1900 ereport(ERROR,
1901 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1902 errmsg("invalid privilege type %s for table",
1903 "USAGE")));
1904 }
1905 }
1906 }
1907
1908 /*
1909 * Set up array in which we'll accumulate any column privilege bits
1910 * that need modification. The array is indexed such that entry [0]
1911 * corresponds to FirstLowInvalidHeapAttributeNumber.
1912 */
1913 num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1914 col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1915 have_col_privileges = false;
1916
1917 /*
1918 * If we are revoking relation privileges that are also column
1919 * privileges, we must implicitly revoke them from each column too,
1920 * per SQL spec. (We don't need to implicitly add column privileges
1921 * during GRANT because the permissions-checking code always checks
1922 * both relation and per-column privileges.)
1923 */
1924 if (!istmt->is_grant &&
1925 (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1926 {
1927 expand_all_col_privileges(relOid, pg_class_tuple,
1928 this_privileges & ACL_ALL_RIGHTS_COLUMN,
1929 col_privileges,
1930 num_col_privileges);
1931 have_col_privileges = true;
1932 }
1933
1934 /*
1935 * Get owner ID and working copy of existing ACL. If there's no ACL,
1936 * substitute the proper default.
1937 */
1938 ownerId = pg_class_tuple->relowner;
1939 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1940 &isNull);
1941 if (isNull)
1942 {
1943 switch (pg_class_tuple->relkind)
1944 {
1945 case RELKIND_SEQUENCE:
1946 old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1947 break;
1948 default:
1949 old_acl = acldefault(OBJECT_TABLE, ownerId);
1950 break;
1951 }
1952 /* There are no old member roles according to the catalogs */
1953 noldmembers = 0;
1954 oldmembers = NULL;
1955 }
1956 else
1957 {
1958 old_acl = DatumGetAclPCopy(aclDatum);
1959 /* Get the roles mentioned in the existing ACL */
1960 noldmembers = aclmembers(old_acl, &oldmembers);
1961 }
1962
1963 /* Need an extra copy of original rel ACL for column handling */
1964 old_rel_acl = aclcopy(old_acl);
1965
1966 /*
1967 * Handle relation-level privileges, if any were specified
1968 */
1969 if (this_privileges != ACL_NO_RIGHTS)
1970 {
1971 AclMode avail_goptions;
1972 Acl *new_acl;
1973 Oid grantorId;
1974 HeapTuple newtuple;
1975 Datum values[Natts_pg_class];
1976 bool nulls[Natts_pg_class];
1977 bool replaces[Natts_pg_class];
1978 int nnewmembers;
1979 Oid *newmembers;
1980 ObjectType objtype;
1981
1982 /* Determine ID to do the grant as, and available grant options */
1983 select_best_grantor(GetUserId(), this_privileges,
1984 old_acl, ownerId,
1985 &grantorId, &avail_goptions);
1986
1987 switch (pg_class_tuple->relkind)
1988 {
1989 case RELKIND_SEQUENCE:
1990 objtype = OBJECT_SEQUENCE;
1991 break;
1992 default:
1993 objtype = OBJECT_TABLE;
1994 break;
1995 }
1996
1997 /*
1998 * Restrict the privileges to what we can actually grant, and emit
1999 * the standards-mandated warning and error messages.
2000 */
2001 this_privileges =
2002 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2003 istmt->all_privs, this_privileges,
2004 relOid, grantorId, objtype,
2005 NameStr(pg_class_tuple->relname),
2006 0, NULL);
2007
2008 /*
2009 * Generate new ACL.
2010 */
2011 new_acl = merge_acl_with_grant(old_acl,
2012 istmt->is_grant,
2013 istmt->grant_option,
2014 istmt->behavior,
2015 istmt->grantees,
2016 this_privileges,
2017 grantorId,
2018 ownerId);
2019
2020 /*
2021 * We need the members of both old and new ACLs so we can correct
2022 * the shared dependency information.
2023 */
2024 nnewmembers = aclmembers(new_acl, &newmembers);
2025
2026 /* finished building new ACL value, now insert it */
2027 MemSet(values, 0, sizeof(values));
2028 MemSet(nulls, false, sizeof(nulls));
2029 MemSet(replaces, false, sizeof(replaces));
2030
2031 replaces[Anum_pg_class_relacl - 1] = true;
2032 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
2033
2034 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2035 values, nulls, replaces);
2036
2037 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2038
2039 /* Update initial privileges for extensions */
2040 recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2041
2042 /* Update the shared dependency ACL info */
2043 updateAclDependencies(RelationRelationId, relOid, 0,
2044 ownerId,
2045 noldmembers, oldmembers,
2046 nnewmembers, newmembers);
2047
2048 pfree(new_acl);
2049 }
2050
2051 /*
2052 * Handle column-level privileges, if any were specified or implied.
2053 * We first expand the user-specified column privileges into the
2054 * array, and then iterate over all nonempty array entries.
2055 */
2056 foreach(cell_colprivs, istmt->col_privs)
2057 {
2058 AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2059
2060 if (col_privs->priv_name == NULL)
2061 this_privileges = ACL_ALL_RIGHTS_COLUMN;
2062 else
2063 this_privileges = string_to_privilege(col_privs->priv_name);
2064
2065 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2066 ereport(ERROR,
2067 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2068 errmsg("invalid privilege type %s for column",
2069 privilege_to_string(this_privileges))));
2070
2071 if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2072 this_privileges & ~((AclMode) ACL_SELECT))
2073 {
2074 /*
2075 * The only column privilege allowed on sequences is SELECT.
2076 * This is a warning not error because we do it that way for
2077 * relation-level privileges.
2078 */
2079 ereport(WARNING,
2080 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2081 errmsg("sequence \"%s\" only supports SELECT column privileges",
2082 NameStr(pg_class_tuple->relname))));
2083
2084 this_privileges &= (AclMode) ACL_SELECT;
2085 }
2086
2087 expand_col_privileges(col_privs->cols, relOid,
2088 this_privileges,
2089 col_privileges,
2090 num_col_privileges);
2091 have_col_privileges = true;
2092 }
2093
2094 if (have_col_privileges)
2095 {
2096 AttrNumber i;
2097
2098 for (i = 0; i < num_col_privileges; i++)
2099 {
2100 if (col_privileges[i] == ACL_NO_RIGHTS)
2101 continue;
2102 ExecGrant_Attribute(istmt,
2103 relOid,
2104 NameStr(pg_class_tuple->relname),
2105 i + FirstLowInvalidHeapAttributeNumber,
2106 ownerId,
2107 col_privileges[i],
2108 attRelation,
2109 old_rel_acl);
2110 }
2111 }
2112
2113 pfree(old_rel_acl);
2114 pfree(col_privileges);
2115
2116 ReleaseSysCache(tuple);
2117
2118 /* prevent error when processing duplicate objects */
2119 CommandCounterIncrement();
2120 }
2121
2122 table_close(attRelation, RowExclusiveLock);
2123 table_close(relation, RowExclusiveLock);
2124}
2125
2126static void
2127ExecGrant_Database(InternalGrant *istmt)
2128{
2129 Relation relation;
2130 ListCell *cell;
2131
2132 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2133 istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
2134
2135 relation = table_open(DatabaseRelationId, RowExclusiveLock);
2136
2137 foreach(cell, istmt->objects)
2138 {
2139 Oid datId = lfirst_oid(cell);
2140 Form_pg_database pg_database_tuple;
2141 Datum aclDatum;
2142 bool isNull;
2143 AclMode avail_goptions;
2144 AclMode this_privileges;
2145 Acl *old_acl;
2146 Acl *new_acl;
2147 Oid grantorId;
2148 Oid ownerId;
2149 HeapTuple newtuple;
2150 Datum values[Natts_pg_database];
2151 bool nulls[Natts_pg_database];
2152 bool replaces[Natts_pg_database];
2153 int noldmembers;
2154 int nnewmembers;
2155 Oid *oldmembers;
2156 Oid *newmembers;
2157 HeapTuple tuple;
2158
2159 tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId));
2160 if (!HeapTupleIsValid(tuple))
2161 elog(ERROR, "cache lookup failed for database %u", datId);
2162
2163 pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
2164
2165 /*
2166 * Get owner ID and working copy of existing ACL. If there's no ACL,
2167 * substitute the proper default.
2168 */
2169 ownerId = pg_database_tuple->datdba;
2170 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
2171 RelationGetDescr(relation), &isNull);
2172 if (isNull)
2173 {
2174 old_acl = acldefault(OBJECT_DATABASE, ownerId);
2175 /* There are no old member roles according to the catalogs */
2176 noldmembers = 0;
2177 oldmembers = NULL;
2178 }
2179 else
2180 {
2181 old_acl = DatumGetAclPCopy(aclDatum);
2182 /* Get the roles mentioned in the existing ACL */
2183 noldmembers = aclmembers(old_acl, &oldmembers);
2184 }
2185
2186 /* Determine ID to do the grant as, and available grant options */
2187 select_best_grantor(GetUserId(), istmt->privileges,
2188 old_acl, ownerId,
2189 &grantorId, &avail_goptions);
2190
2191 /*
2192 * Restrict the privileges to what we can actually grant, and emit the
2193 * standards-mandated warning and error messages.
2194 */
2195 this_privileges =
2196 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2197 istmt->all_privs, istmt->privileges,
2198 datId, grantorId, OBJECT_DATABASE,
2199 NameStr(pg_database_tuple->datname),
2200 0, NULL);
2201
2202 /*
2203 * Generate new ACL.
2204 */
2205 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2206 istmt->grant_option, istmt->behavior,
2207 istmt->grantees, this_privileges,
2208 grantorId, ownerId);
2209
2210 /*
2211 * We need the members of both old and new ACLs so we can correct the
2212 * shared dependency information.
2213 */
2214 nnewmembers = aclmembers(new_acl, &newmembers);
2215
2216 /* finished building new ACL value, now insert it */
2217 MemSet(values, 0, sizeof(values));
2218 MemSet(nulls, false, sizeof(nulls));
2219 MemSet(replaces, false, sizeof(replaces));
2220
2221 replaces[Anum_pg_database_datacl - 1] = true;
2222 values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
2223
2224 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2225 nulls, replaces);
2226
2227 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2228
2229 /* Update the shared dependency ACL info */
2230 updateAclDependencies(DatabaseRelationId, pg_database_tuple->oid, 0,
2231 ownerId,
2232 noldmembers, oldmembers,
2233 nnewmembers, newmembers);
2234
2235 ReleaseSysCache(tuple);
2236
2237 pfree(new_acl);
2238
2239 /* prevent error when processing duplicate objects */
2240 CommandCounterIncrement();
2241 }
2242
2243 table_close(relation, RowExclusiveLock);
2244}
2245
2246static void
2247ExecGrant_Fdw(InternalGrant *istmt)
2248{
2249 Relation relation;
2250 ListCell *cell;
2251
2252 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2253 istmt->privileges = ACL_ALL_RIGHTS_FDW;
2254
2255 relation = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
2256
2257 foreach(cell, istmt->objects)
2258 {
2259 Oid fdwid = lfirst_oid(cell);
2260 Form_pg_foreign_data_wrapper pg_fdw_tuple;
2261 Datum aclDatum;
2262 bool isNull;
2263 AclMode avail_goptions;
2264 AclMode this_privileges;
2265 Acl *old_acl;
2266 Acl *new_acl;
2267 Oid grantorId;
2268 Oid ownerId;
2269 HeapTuple tuple;
2270 HeapTuple newtuple;
2271 Datum values[Natts_pg_foreign_data_wrapper];
2272 bool nulls[Natts_pg_foreign_data_wrapper];
2273 bool replaces[Natts_pg_foreign_data_wrapper];
2274 int noldmembers;
2275 int nnewmembers;
2276 Oid *oldmembers;
2277 Oid *newmembers;
2278
2279 tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
2280 ObjectIdGetDatum(fdwid));
2281 if (!HeapTupleIsValid(tuple))
2282 elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
2283
2284 pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
2285
2286 /*
2287 * Get owner ID and working copy of existing ACL. If there's no ACL,
2288 * substitute the proper default.
2289 */
2290 ownerId = pg_fdw_tuple->fdwowner;
2291 aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
2292 Anum_pg_foreign_data_wrapper_fdwacl,
2293 &isNull);
2294 if (isNull)
2295 {
2296 old_acl = acldefault(OBJECT_FDW, ownerId);
2297 /* There are no old member roles according to the catalogs */
2298 noldmembers = 0;
2299 oldmembers = NULL;
2300 }
2301 else
2302 {
2303 old_acl = DatumGetAclPCopy(aclDatum);
2304 /* Get the roles mentioned in the existing ACL */
2305 noldmembers = aclmembers(old_acl, &oldmembers);
2306 }
2307
2308 /* Determine ID to do the grant as, and available grant options */
2309 select_best_grantor(GetUserId(), istmt->privileges,
2310 old_acl, ownerId,
2311 &grantorId, &avail_goptions);
2312
2313 /*
2314 * Restrict the privileges to what we can actually grant, and emit the
2315 * standards-mandated warning and error messages.
2316 */
2317 this_privileges =
2318 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2319 istmt->all_privs, istmt->privileges,
2320 fdwid, grantorId, OBJECT_FDW,
2321 NameStr(pg_fdw_tuple->fdwname),
2322 0, NULL);
2323
2324 /*
2325 * Generate new ACL.
2326 */
2327 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2328 istmt->grant_option, istmt->behavior,
2329 istmt->grantees, this_privileges,
2330 grantorId, ownerId);
2331
2332 /*
2333 * We need the members of both old and new ACLs so we can correct the
2334 * shared dependency information.
2335 */
2336 nnewmembers = aclmembers(new_acl, &newmembers);
2337
2338 /* finished building new ACL value, now insert it */
2339 MemSet(values, 0, sizeof(values));
2340 MemSet(nulls, false, sizeof(nulls));
2341 MemSet(replaces, false, sizeof(replaces));
2342
2343 replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
2344 values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl);
2345
2346 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2347 nulls, replaces);
2348
2349 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2350
2351 /* Update initial privileges for extensions */
2352 recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
2353 new_acl);
2354
2355 /* Update the shared dependency ACL info */
2356 updateAclDependencies(ForeignDataWrapperRelationId,
2357 pg_fdw_tuple->oid, 0,
2358 ownerId,
2359 noldmembers, oldmembers,
2360 nnewmembers, newmembers);
2361
2362 ReleaseSysCache(tuple);
2363
2364 pfree(new_acl);
2365
2366 /* prevent error when processing duplicate objects */
2367 CommandCounterIncrement();
2368 }
2369
2370 table_close(relation, RowExclusiveLock);
2371}
2372
2373static void
2374ExecGrant_ForeignServer(InternalGrant *istmt)
2375{
2376 Relation relation;
2377 ListCell *cell;
2378
2379 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2380 istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
2381
2382 relation = table_open(ForeignServerRelationId, RowExclusiveLock);
2383
2384 foreach(cell, istmt->objects)
2385 {
2386 Oid srvid = lfirst_oid(cell);
2387 Form_pg_foreign_server pg_server_tuple;
2388 Datum aclDatum;
2389 bool isNull;
2390 AclMode avail_goptions;
2391 AclMode this_privileges;
2392 Acl *old_acl;
2393 Acl *new_acl;
2394 Oid grantorId;
2395 Oid ownerId;
2396 HeapTuple tuple;
2397 HeapTuple newtuple;
2398 Datum values[Natts_pg_foreign_server];
2399 bool nulls[Natts_pg_foreign_server];
2400 bool replaces[Natts_pg_foreign_server];
2401 int noldmembers;
2402 int nnewmembers;
2403 Oid *oldmembers;
2404 Oid *newmembers;
2405
2406 tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid));
2407 if (!HeapTupleIsValid(tuple))
2408 elog(ERROR, "cache lookup failed for foreign server %u", srvid);
2409
2410 pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple);
2411
2412 /*
2413 * Get owner ID and working copy of existing ACL. If there's no ACL,
2414 * substitute the proper default.
2415 */
2416 ownerId = pg_server_tuple->srvowner;
2417 aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
2418 Anum_pg_foreign_server_srvacl,
2419 &isNull);
2420 if (isNull)
2421 {
2422 old_acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
2423 /* There are no old member roles according to the catalogs */
2424 noldmembers = 0;
2425 oldmembers = NULL;
2426 }
2427 else
2428 {
2429 old_acl = DatumGetAclPCopy(aclDatum);
2430 /* Get the roles mentioned in the existing ACL */
2431 noldmembers = aclmembers(old_acl, &oldmembers);
2432 }
2433
2434 /* Determine ID to do the grant as, and available grant options */
2435 select_best_grantor(GetUserId(), istmt->privileges,
2436 old_acl, ownerId,
2437 &grantorId, &avail_goptions);
2438
2439 /*
2440 * Restrict the privileges to what we can actually grant, and emit the
2441 * standards-mandated warning and error messages.
2442 */
2443 this_privileges =
2444 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2445 istmt->all_privs, istmt->privileges,
2446 srvid, grantorId, OBJECT_FOREIGN_SERVER,
2447 NameStr(pg_server_tuple->srvname),
2448 0, NULL);
2449
2450 /*
2451 * Generate new ACL.
2452 */
2453 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2454 istmt->grant_option, istmt->behavior,
2455 istmt->grantees, this_privileges,
2456 grantorId, ownerId);
2457
2458 /*
2459 * We need the members of both old and new ACLs so we can correct the
2460 * shared dependency information.
2461 */
2462 nnewmembers = aclmembers(new_acl, &newmembers);
2463
2464 /* finished building new ACL value, now insert it */
2465 MemSet(values, 0, sizeof(values));
2466 MemSet(nulls, false, sizeof(nulls));
2467 MemSet(replaces, false, sizeof(replaces));
2468
2469 replaces[Anum_pg_foreign_server_srvacl - 1] = true;
2470 values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl);
2471
2472 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2473 nulls, replaces);
2474
2475 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2476
2477 /* Update initial privileges for extensions */
2478 recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
2479
2480 /* Update the shared dependency ACL info */
2481 updateAclDependencies(ForeignServerRelationId,
2482 pg_server_tuple->oid, 0,
2483 ownerId,
2484 noldmembers, oldmembers,
2485 nnewmembers, newmembers);
2486
2487 ReleaseSysCache(tuple);
2488
2489 pfree(new_acl);
2490
2491 /* prevent error when processing duplicate objects */
2492 CommandCounterIncrement();
2493 }
2494
2495 table_close(relation, RowExclusiveLock);
2496}
2497
2498static void
2499ExecGrant_Function(InternalGrant *istmt)
2500{
2501 Relation relation;
2502 ListCell *cell;
2503
2504 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2505 istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
2506
2507 relation = table_open(ProcedureRelationId, RowExclusiveLock);
2508
2509 foreach(cell, istmt->objects)
2510 {
2511 Oid funcId = lfirst_oid(cell);
2512 Form_pg_proc pg_proc_tuple;
2513 Datum aclDatum;
2514 bool isNull;
2515 AclMode avail_goptions;
2516 AclMode this_privileges;
2517 Acl *old_acl;
2518 Acl *new_acl;
2519 Oid grantorId;
2520 Oid ownerId;
2521 HeapTuple tuple;
2522 HeapTuple newtuple;
2523 Datum values[Natts_pg_proc];
2524 bool nulls[Natts_pg_proc];
2525 bool replaces[Natts_pg_proc];
2526 int noldmembers;
2527 int nnewmembers;
2528 Oid *oldmembers;
2529 Oid *newmembers;
2530
2531 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId));
2532 if (!HeapTupleIsValid(tuple))
2533 elog(ERROR, "cache lookup failed for function %u", funcId);
2534
2535 pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
2536
2537 /*
2538 * Get owner ID and working copy of existing ACL. If there's no ACL,
2539 * substitute the proper default.
2540 */
2541 ownerId = pg_proc_tuple->proowner;
2542 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
2543 &isNull);
2544 if (isNull)
2545 {
2546 old_acl = acldefault(OBJECT_FUNCTION, ownerId);
2547 /* There are no old member roles according to the catalogs */
2548 noldmembers = 0;
2549 oldmembers = NULL;
2550 }
2551 else
2552 {
2553 old_acl = DatumGetAclPCopy(aclDatum);
2554 /* Get the roles mentioned in the existing ACL */
2555 noldmembers = aclmembers(old_acl, &oldmembers);
2556 }
2557
2558 /* Determine ID to do the grant as, and available grant options */
2559 select_best_grantor(GetUserId(), istmt->privileges,
2560 old_acl, ownerId,
2561 &grantorId, &avail_goptions);
2562
2563 /*
2564 * Restrict the privileges to what we can actually grant, and emit the
2565 * standards-mandated warning and error messages.
2566 */
2567 this_privileges =
2568 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2569 istmt->all_privs, istmt->privileges,
2570 funcId, grantorId, OBJECT_FUNCTION,
2571 NameStr(pg_proc_tuple->proname),
2572 0, NULL);
2573
2574 /*
2575 * Generate new ACL.
2576 */
2577 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2578 istmt->grant_option, istmt->behavior,
2579 istmt->grantees, this_privileges,
2580 grantorId, ownerId);
2581
2582 /*
2583 * We need the members of both old and new ACLs so we can correct the
2584 * shared dependency information.
2585 */
2586 nnewmembers = aclmembers(new_acl, &newmembers);
2587
2588 /* finished building new ACL value, now insert it */
2589 MemSet(values, 0, sizeof(values));
2590 MemSet(nulls, false, sizeof(nulls));
2591 MemSet(replaces, false, sizeof(replaces));
2592
2593 replaces[Anum_pg_proc_proacl - 1] = true;
2594 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
2595
2596 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2597 nulls, replaces);
2598
2599 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2600
2601 /* Update initial privileges for extensions */
2602 recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
2603
2604 /* Update the shared dependency ACL info */
2605 updateAclDependencies(ProcedureRelationId, funcId, 0,
2606 ownerId,
2607 noldmembers, oldmembers,
2608 nnewmembers, newmembers);
2609
2610 ReleaseSysCache(tuple);
2611
2612 pfree(new_acl);
2613
2614 /* prevent error when processing duplicate objects */
2615 CommandCounterIncrement();
2616 }
2617
2618 table_close(relation, RowExclusiveLock);
2619}
2620
2621static void
2622ExecGrant_Language(InternalGrant *istmt)
2623{
2624 Relation relation;
2625 ListCell *cell;
2626
2627 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2628 istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
2629
2630 relation = table_open(LanguageRelationId, RowExclusiveLock);
2631
2632 foreach(cell, istmt->objects)
2633 {
2634 Oid langId = lfirst_oid(cell);
2635 Form_pg_language pg_language_tuple;
2636 Datum aclDatum;
2637 bool isNull;
2638 AclMode avail_goptions;
2639 AclMode this_privileges;
2640 Acl *old_acl;
2641 Acl *new_acl;
2642 Oid grantorId;
2643 Oid ownerId;
2644 HeapTuple tuple;
2645 HeapTuple newtuple;
2646 Datum values[Natts_pg_language];
2647 bool nulls[Natts_pg_language];
2648 bool replaces[Natts_pg_language];
2649 int noldmembers;
2650 int nnewmembers;
2651 Oid *oldmembers;
2652 Oid *newmembers;
2653
2654 tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(langId));
2655 if (!HeapTupleIsValid(tuple))
2656 elog(ERROR, "cache lookup failed for language %u", langId);
2657
2658 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2659
2660 if (!pg_language_tuple->lanpltrusted)
2661 ereport(ERROR,
2662 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2663 errmsg("language \"%s\" is not trusted",
2664 NameStr(pg_language_tuple->lanname)),
2665 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2666 "because only superusers can use untrusted languages.")));
2667
2668 /*
2669 * Get owner ID and working copy of existing ACL. If there's no ACL,
2670 * substitute the proper default.
2671 */
2672 ownerId = pg_language_tuple->lanowner;
2673 aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
2674 &isNull);
2675 if (isNull)
2676 {
2677 old_acl = acldefault(OBJECT_LANGUAGE, ownerId);
2678 /* There are no old member roles according to the catalogs */
2679 noldmembers = 0;
2680 oldmembers = NULL;
2681 }
2682 else
2683 {
2684 old_acl = DatumGetAclPCopy(aclDatum);
2685 /* Get the roles mentioned in the existing ACL */
2686 noldmembers = aclmembers(old_acl, &oldmembers);
2687 }
2688
2689 /* Determine ID to do the grant as, and available grant options */
2690 select_best_grantor(GetUserId(), istmt->privileges,
2691 old_acl, ownerId,
2692 &grantorId, &avail_goptions);
2693
2694 /*
2695 * Restrict the privileges to what we can actually grant, and emit the
2696 * standards-mandated warning and error messages.
2697 */
2698 this_privileges =
2699 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2700 istmt->all_privs, istmt->privileges,
2701 langId, grantorId, OBJECT_LANGUAGE,
2702 NameStr(pg_language_tuple->lanname),
2703 0, NULL);
2704
2705 /*
2706 * Generate new ACL.
2707 */
2708 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2709 istmt->grant_option, istmt->behavior,
2710 istmt->grantees, this_privileges,
2711 grantorId, ownerId);
2712
2713 /*
2714 * We need the members of both old and new ACLs so we can correct the
2715 * shared dependency information.
2716 */
2717 nnewmembers = aclmembers(new_acl, &newmembers);
2718
2719 /* finished building new ACL value, now insert it */
2720 MemSet(values, 0, sizeof(values));
2721 MemSet(nulls, false, sizeof(nulls));
2722 MemSet(replaces, false, sizeof(replaces));
2723
2724 replaces[Anum_pg_language_lanacl - 1] = true;
2725 values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
2726
2727 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2728 nulls, replaces);
2729
2730 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2731
2732 /* Update initial privileges for extensions */
2733 recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
2734
2735 /* Update the shared dependency ACL info */
2736 updateAclDependencies(LanguageRelationId, pg_language_tuple->oid, 0,
2737 ownerId,
2738 noldmembers, oldmembers,
2739 nnewmembers, newmembers);
2740
2741 ReleaseSysCache(tuple);
2742
2743 pfree(new_acl);
2744
2745 /* prevent error when processing duplicate objects */
2746 CommandCounterIncrement();
2747 }
2748
2749 table_close(relation, RowExclusiveLock);
2750}
2751
2752static void
2753ExecGrant_Largeobject(InternalGrant *istmt)
2754{
2755 Relation relation;
2756 ListCell *cell;
2757
2758 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2759 istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
2760
2761 relation = table_open(LargeObjectMetadataRelationId,
2762 RowExclusiveLock);
2763
2764 foreach(cell, istmt->objects)
2765 {
2766 Oid loid = lfirst_oid(cell);
2767 Form_pg_largeobject_metadata form_lo_meta;
2768 char loname[NAMEDATALEN];
2769 Datum aclDatum;
2770 bool isNull;
2771 AclMode avail_goptions;
2772 AclMode this_privileges;
2773 Acl *old_acl;
2774 Acl *new_acl;
2775 Oid grantorId;
2776 Oid ownerId;
2777 HeapTuple newtuple;
2778 Datum values[Natts_pg_largeobject_metadata];
2779 bool nulls[Natts_pg_largeobject_metadata];
2780 bool replaces[Natts_pg_largeobject_metadata];
2781 int noldmembers;
2782 int nnewmembers;
2783 Oid *oldmembers;
2784 Oid *newmembers;
2785 ScanKeyData entry[1];
2786 SysScanDesc scan;
2787 HeapTuple tuple;
2788
2789 /* There's no syscache for pg_largeobject_metadata */
2790 ScanKeyInit(&entry[0],
2791 Anum_pg_largeobject_metadata_oid,
2792 BTEqualStrategyNumber, F_OIDEQ,
2793 ObjectIdGetDatum(loid));
2794
2795 scan = systable_beginscan(relation,
2796 LargeObjectMetadataOidIndexId, true,
2797 NULL, 1, entry);
2798
2799 tuple = systable_getnext(scan);
2800 if (!HeapTupleIsValid(tuple))
2801 elog(ERROR, "could not find tuple for large object %u", loid);
2802
2803 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2804
2805 /*
2806 * Get owner ID and working copy of existing ACL. If there's no ACL,
2807 * substitute the proper default.
2808 */
2809 ownerId = form_lo_meta->lomowner;
2810 aclDatum = heap_getattr(tuple,
2811 Anum_pg_largeobject_metadata_lomacl,
2812 RelationGetDescr(relation), &isNull);
2813 if (isNull)
2814 {
2815 old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2816 /* There are no old member roles according to the catalogs */
2817 noldmembers = 0;
2818 oldmembers = NULL;
2819 }
2820 else
2821 {
2822 old_acl = DatumGetAclPCopy(aclDatum);
2823 /* Get the roles mentioned in the existing ACL */
2824 noldmembers = aclmembers(old_acl, &oldmembers);
2825 }
2826
2827 /* Determine ID to do the grant as, and available grant options */
2828 select_best_grantor(GetUserId(), istmt->privileges,
2829 old_acl, ownerId,
2830 &grantorId, &avail_goptions);
2831
2832 /*
2833 * Restrict the privileges to what we can actually grant, and emit the
2834 * standards-mandated warning and error messages.
2835 */
2836 snprintf(loname, sizeof(loname), "large object %u", loid);
2837 this_privileges =
2838 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2839 istmt->all_privs, istmt->privileges,
2840 loid, grantorId, OBJECT_LARGEOBJECT,
2841 loname, 0, NULL);
2842
2843 /*
2844 * Generate new ACL.
2845 */
2846 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2847 istmt->grant_option, istmt->behavior,
2848 istmt->grantees, this_privileges,
2849 grantorId, ownerId);
2850
2851 /*
2852 * We need the members of both old and new ACLs so we can correct the
2853 * shared dependency information.
2854 */
2855 nnewmembers = aclmembers(new_acl, &newmembers);
2856
2857 /* finished building new ACL value, now insert it */
2858 MemSet(values, 0, sizeof(values));
2859 MemSet(nulls, false, sizeof(nulls));
2860 MemSet(replaces, false, sizeof(replaces));
2861
2862 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2863 values[Anum_pg_largeobject_metadata_lomacl - 1]
2864 = PointerGetDatum(new_acl);
2865
2866 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2867 values, nulls, replaces);
2868
2869 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2870
2871 /* Update initial privileges for extensions */
2872 recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2873
2874 /* Update the shared dependency ACL info */
2875 updateAclDependencies(LargeObjectRelationId,
2876 form_lo_meta->oid, 0,
2877 ownerId,
2878 noldmembers, oldmembers,
2879 nnewmembers, newmembers);
2880
2881 systable_endscan(scan);
2882
2883 pfree(new_acl);
2884
2885 /* prevent error when processing duplicate objects */
2886 CommandCounterIncrement();
2887 }
2888
2889 table_close(relation, RowExclusiveLock);
2890}
2891
2892static void
2893ExecGrant_Namespace(InternalGrant *istmt)
2894{
2895 Relation relation;
2896 ListCell *cell;
2897
2898 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2899 istmt->privileges = ACL_ALL_RIGHTS_SCHEMA;
2900
2901 relation = table_open(NamespaceRelationId, RowExclusiveLock);
2902
2903 foreach(cell, istmt->objects)
2904 {
2905 Oid nspid = lfirst_oid(cell);
2906 Form_pg_namespace pg_namespace_tuple;
2907 Datum aclDatum;
2908 bool isNull;
2909 AclMode avail_goptions;
2910 AclMode this_privileges;
2911 Acl *old_acl;
2912 Acl *new_acl;
2913 Oid grantorId;
2914 Oid ownerId;
2915 HeapTuple tuple;
2916 HeapTuple newtuple;
2917 Datum values[Natts_pg_namespace];
2918 bool nulls[Natts_pg_namespace];
2919 bool replaces[Natts_pg_namespace];
2920 int noldmembers;
2921 int nnewmembers;
2922 Oid *oldmembers;
2923 Oid *newmembers;
2924
2925 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
2926 if (!HeapTupleIsValid(tuple))
2927 elog(ERROR, "cache lookup failed for namespace %u", nspid);
2928
2929 pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
2930
2931 /*
2932 * Get owner ID and working copy of existing ACL. If there's no ACL,
2933 * substitute the proper default.
2934 */
2935 ownerId = pg_namespace_tuple->nspowner;
2936 aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
2937 Anum_pg_namespace_nspacl,
2938 &isNull);
2939 if (isNull)
2940 {
2941 old_acl = acldefault(OBJECT_SCHEMA, ownerId);
2942 /* There are no old member roles according to the catalogs */
2943 noldmembers = 0;
2944 oldmembers = NULL;
2945 }
2946 else
2947 {
2948 old_acl = DatumGetAclPCopy(aclDatum);
2949 /* Get the roles mentioned in the existing ACL */
2950 noldmembers = aclmembers(old_acl, &oldmembers);
2951 }
2952
2953 /* Determine ID to do the grant as, and available grant options */
2954 select_best_grantor(GetUserId(), istmt->privileges,
2955 old_acl, ownerId,
2956 &grantorId, &avail_goptions);
2957
2958 /*
2959 * Restrict the privileges to what we can actually grant, and emit the
2960 * standards-mandated warning and error messages.
2961 */
2962 this_privileges =
2963 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2964 istmt->all_privs, istmt->privileges,
2965 nspid, grantorId, OBJECT_SCHEMA,
2966 NameStr(pg_namespace_tuple->nspname),
2967 0, NULL);
2968
2969 /*
2970 * Generate new ACL.
2971 */
2972 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2973 istmt->grant_option, istmt->behavior,
2974 istmt->grantees, this_privileges,
2975 grantorId, ownerId);
2976
2977 /*
2978 * We need the members of both old and new ACLs so we can correct the
2979 * shared dependency information.
2980 */
2981 nnewmembers = aclmembers(new_acl, &newmembers);
2982
2983 /* finished building new ACL value, now insert it */
2984 MemSet(values, 0, sizeof(values));
2985 MemSet(nulls, false, sizeof(nulls));
2986 MemSet(replaces, false, sizeof(replaces));
2987
2988 replaces[Anum_pg_namespace_nspacl - 1] = true;
2989 values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
2990
2991 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2992 nulls, replaces);
2993
2994 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2995
2996 /* Update initial privileges for extensions */
2997 recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
2998
2999 /* Update the shared dependency ACL info */
3000 updateAclDependencies(NamespaceRelationId, pg_namespace_tuple->oid, 0,
3001 ownerId,
3002 noldmembers, oldmembers,
3003 nnewmembers, newmembers);
3004
3005 ReleaseSysCache(tuple);
3006
3007 pfree(new_acl);
3008
3009 /* prevent error when processing duplicate objects */
3010 CommandCounterIncrement();
3011 }
3012
3013 table_close(relation, RowExclusiveLock);
3014}
3015
3016static void
3017ExecGrant_Tablespace(InternalGrant *istmt)
3018{
3019 Relation relation;
3020 ListCell *cell;
3021
3022 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
3023 istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
3024
3025 relation = table_open(TableSpaceRelationId, RowExclusiveLock);
3026
3027 foreach(cell, istmt->objects)
3028 {
3029 Oid tblId = lfirst_oid(cell);
3030 Form_pg_tablespace pg_tablespace_tuple;
3031 Datum aclDatum;
3032 bool isNull;
3033 AclMode avail_goptions;
3034 AclMode this_privileges;
3035 Acl *old_acl;
3036 Acl *new_acl;
3037 Oid grantorId;
3038 Oid ownerId;
3039 HeapTuple newtuple;
3040 Datum values[Natts_pg_tablespace];
3041 bool nulls[Natts_pg_tablespace];
3042 bool replaces[Natts_pg_tablespace];
3043 int noldmembers;
3044 int nnewmembers;
3045 Oid *oldmembers;
3046 Oid *newmembers;
3047 HeapTuple tuple;
3048
3049 /* Search syscache for pg_tablespace */
3050 tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId));
3051 if (!HeapTupleIsValid(tuple))
3052 elog(ERROR, "cache lookup failed for tablespace %u", tblId);
3053
3054 pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
3055
3056 /*
3057 * Get owner ID and working copy of existing ACL. If there's no ACL,
3058 * substitute the proper default.
3059 */
3060 ownerId = pg_tablespace_tuple->spcowner;
3061 aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
3062 RelationGetDescr(relation), &isNull);
3063 if (isNull)
3064 {
3065 old_acl = acldefault(OBJECT_TABLESPACE, ownerId);
3066 /* There are no old member roles according to the catalogs */
3067 noldmembers = 0;
3068 oldmembers = NULL;
3069 }
3070 else
3071 {
3072 old_acl = DatumGetAclPCopy(aclDatum);
3073 /* Get the roles mentioned in the existing ACL */
3074 noldmembers = aclmembers(old_acl, &oldmembers);
3075 }
3076
3077 /* Determine ID to do the grant as, and available grant options */
3078 select_best_grantor(GetUserId(), istmt->privileges,
3079 old_acl, ownerId,
3080 &grantorId, &avail_goptions);
3081
3082 /*
3083 * Restrict the privileges to what we can actually grant, and emit the
3084 * standards-mandated warning and error messages.
3085 */
3086 this_privileges =
3087 restrict_and_check_grant(istmt->is_grant, avail_goptions,
3088 istmt->all_privs, istmt->privileges,
3089 tblId, grantorId, OBJECT_TABLESPACE,
3090 NameStr(pg_tablespace_tuple->spcname),
3091 0, NULL);
3092
3093 /*
3094 * Generate new ACL.
3095 */
3096 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
3097 istmt->grant_option, istmt->behavior,
3098 istmt->grantees, this_privileges,
3099 grantorId, ownerId);
3100
3101 /*
3102 * We need the members of both old and new ACLs so we can correct the
3103 * shared dependency information.
3104 */
3105 nnewmembers = aclmembers(new_acl, &newmembers);
3106
3107 /* finished building new ACL value, now insert it */
3108 MemSet(values, 0, sizeof(values));
3109 MemSet(nulls, false, sizeof(nulls));
3110 MemSet(replaces, false, sizeof(replaces));
3111
3112 replaces[Anum_pg_tablespace_spcacl - 1] = true;
3113 values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
3114
3115 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
3116 nulls, replaces);
3117
3118 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
3119
3120 /* Update the shared dependency ACL info */
3121 updateAclDependencies(TableSpaceRelationId, tblId, 0,
3122 ownerId,
3123 noldmembers, oldmembers,
3124 nnewmembers, newmembers);
3125
3126 ReleaseSysCache(tuple);
3127 pfree(new_acl);
3128
3129 /* prevent error when processing duplicate objects */
3130 CommandCounterIncrement();
3131 }
3132
3133 table_close(relation, RowExclusiveLock);
3134}
3135
3136static void
3137ExecGrant_Type(InternalGrant *istmt)
3138{
3139 Relation relation;
3140 ListCell *cell;
3141
3142 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
3143 istmt->privileges = ACL_ALL_RIGHTS_TYPE;
3144
3145 relation = table_open(TypeRelationId, RowExclusiveLock);
3146
3147 foreach(cell, istmt->objects)
3148 {
3149 Oid typId = lfirst_oid(cell);
3150 Form_pg_type pg_type_tuple;
3151 Datum aclDatum;
3152 bool isNull;
3153 AclMode avail_goptions;
3154 AclMode this_privileges;
3155 Acl *old_acl;
3156 Acl *new_acl;
3157 Oid grantorId;
3158 Oid ownerId;
3159 HeapTuple newtuple;
3160 Datum values[Natts_pg_type];
3161 bool nulls[Natts_pg_type];
3162 bool replaces[Natts_pg_type];
3163 int noldmembers;
3164 int nnewmembers;
3165 Oid *oldmembers;
3166 Oid *newmembers;
3167 HeapTuple tuple;
3168
3169 /* Search syscache for pg_type */
3170 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typId));
3171 if (!HeapTupleIsValid(tuple))
3172 elog(ERROR, "cache lookup failed for type %u", typId);
3173
3174 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
3175
3176 if (pg_type_tuple->typelem != 0 && pg_type_tuple->typlen == -1)
3177 ereport(ERROR,
3178 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
3179 errmsg("cannot set privileges of array types"),
3180 errhint("Set the privileges of the element type instead.")));
3181
3182 /* Used GRANT DOMAIN on a non-domain? */
3183 if (istmt->objtype == OBJECT_DOMAIN &&
3184 pg_type_tuple->typtype != TYPTYPE_DOMAIN)
3185 ereport(ERROR,
3186 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3187 errmsg("\"%s\" is not a domain",
3188 NameStr(pg_type_tuple->typname))));
3189
3190 /*
3191 * Get owner ID and working copy of existing ACL. If there's no ACL,
3192 * substitute the proper default.
3193 */
3194 ownerId = pg_type_tuple->typowner;
3195 aclDatum = heap_getattr(tuple, Anum_pg_type_typacl,
3196 RelationGetDescr(relation), &isNull);
3197 if (isNull)
3198 {
3199 old_acl = acldefault(istmt->objtype, ownerId);
3200 /* There are no old member roles according to the catalogs */
3201 noldmembers = 0;
3202 oldmembers = NULL;
3203 }
3204 else
3205 {
3206 old_acl = DatumGetAclPCopy(aclDatum);
3207 /* Get the roles mentioned in the existing ACL */
3208 noldmembers = aclmembers(old_acl, &oldmembers);
3209 }
3210
3211 /* Determine ID to do the grant as, and available grant options */
3212 select_best_grantor(GetUserId(), istmt->privileges,
3213 old_acl, ownerId,
3214 &grantorId, &avail_goptions);
3215
3216 /*
3217 * Restrict the privileges to what we can actually grant, and emit the
3218 * standards-mandated warning and error messages.
3219 */
3220 this_privileges =
3221 restrict_and_check_grant(istmt->is_grant, avail_goptions,
3222 istmt->all_privs, istmt->privileges,
3223 typId, grantorId, OBJECT_TYPE,
3224 NameStr(pg_type_tuple->typname),
3225 0, NULL);
3226
3227 /*
3228 * Generate new ACL.
3229 */
3230 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
3231 istmt->grant_option, istmt->behavior,
3232 istmt->grantees, this_privileges,
3233 grantorId, ownerId);
3234
3235 /*
3236 * We need the members of both old and new ACLs so we can correct the
3237 * shared dependency information.
3238 */
3239 nnewmembers = aclmembers(new_acl, &newmembers);
3240
3241 /* finished building new ACL value, now insert it */
3242 MemSet(values, 0, sizeof(values));
3243 MemSet(nulls, false, sizeof(nulls));
3244 MemSet(replaces, false, sizeof(replaces));
3245
3246 replaces[Anum_pg_type_typacl - 1] = true;
3247 values[Anum_pg_type_typacl - 1] = PointerGetDatum(new_acl);
3248
3249 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
3250 nulls, replaces);
3251
3252 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
3253
3254 /* Update initial privileges for extensions */
3255 recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
3256
3257 /* Update the shared dependency ACL info */
3258 updateAclDependencies(TypeRelationId, typId, 0,
3259 ownerId,
3260 noldmembers, oldmembers,
3261 nnewmembers, newmembers);
3262
3263 ReleaseSysCache(tuple);
3264 pfree(new_acl);
3265
3266 /* prevent error when processing duplicate objects */
3267 CommandCounterIncrement();
3268 }
3269
3270 table_close(relation, RowExclusiveLock);
3271}
3272
3273
3274static AclMode
3275string_to_privilege(const char *privname)
3276{
3277 if (strcmp(privname, "insert") == 0)
3278 return ACL_INSERT;
3279 if (strcmp(privname, "select") == 0)
3280 return ACL_SELECT;
3281 if (strcmp(privname, "update") == 0)
3282 return ACL_UPDATE;
3283 if (strcmp(privname, "delete") == 0)
3284 return ACL_DELETE;
3285 if (strcmp(privname, "truncate") == 0)
3286 return ACL_TRUNCATE;
3287 if (strcmp(privname, "references") == 0)
3288 return ACL_REFERENCES;
3289 if (strcmp(privname, "trigger") == 0)
3290 return ACL_TRIGGER;
3291 if (strcmp(privname, "execute") == 0)
3292 return ACL_EXECUTE;
3293 if (strcmp(privname, "usage") == 0)
3294 return ACL_USAGE;
3295 if (strcmp(privname, "create") == 0)
3296 return ACL_CREATE;
3297 if (strcmp(privname, "temporary") == 0)
3298 return ACL_CREATE_TEMP;
3299 if (strcmp(privname, "temp") == 0)
3300 return ACL_CREATE_TEMP;
3301 if (strcmp(privname, "connect") == 0)
3302 return ACL_CONNECT;
3303 if (strcmp(privname, "rule") == 0)
3304 return 0; /* ignore old RULE privileges */
3305 ereport(ERROR,
3306 (errcode(ERRCODE_SYNTAX_ERROR),
3307 errmsg("unrecognized privilege type \"%s\"", privname)));
3308 return 0; /* appease compiler */
3309}
3310
3311static const char *
3312privilege_to_string(AclMode privilege)
3313{
3314 switch (privilege)
3315 {
3316 case ACL_INSERT:
3317 return "INSERT";
3318 case ACL_SELECT:
3319 return "SELECT";
3320 case ACL_UPDATE:
3321 return "UPDATE";
3322 case ACL_DELETE:
3323 return "DELETE";
3324 case ACL_TRUNCATE:
3325 return "TRUNCATE";
3326 case ACL_REFERENCES:
3327 return "REFERENCES";
3328 case ACL_TRIGGER:
3329 return "TRIGGER";
3330 case ACL_EXECUTE:
3331 return "EXECUTE";
3332 case ACL_USAGE:
3333 return "USAGE";
3334 case ACL_CREATE:
3335 return "CREATE";
3336 case ACL_CREATE_TEMP:
3337 return "TEMP";
3338 case ACL_CONNECT:
3339 return "CONNECT";
3340 default:
3341 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
3342 }
3343 return NULL; /* appease compiler */
3344}
3345
3346/*
3347 * Standardized reporting of aclcheck permissions failures.
3348 *
3349 * Note: we do not double-quote the %s's below, because many callers
3350 * supply strings that might be already quoted.
3351 */
3352void
3353aclcheck_error(AclResult aclerr, ObjectType objtype,
3354 const char *objectname)
3355{
3356 switch (aclerr)
3357 {
3358 case ACLCHECK_OK:
3359 /* no error, so return to caller */
3360 break;
3361 case ACLCHECK_NO_PRIV:
3362 {
3363 const char *msg = "???";
3364
3365 switch (objtype)
3366 {
3367 case OBJECT_AGGREGATE:
3368 msg = gettext_noop("permission denied for aggregate %s");
3369 break;
3370 case OBJECT_COLLATION:
3371 msg = gettext_noop("permission denied for collation %s");
3372 break;
3373 case OBJECT_COLUMN:
3374 msg = gettext_noop("permission denied for column %s");
3375 break;
3376 case OBJECT_CONVERSION:
3377 msg = gettext_noop("permission denied for conversion %s");
3378 break;
3379 case OBJECT_DATABASE:
3380 msg = gettext_noop("permission denied for database %s");
3381 break;
3382 case OBJECT_DOMAIN:
3383 msg = gettext_noop("permission denied for domain %s");
3384 break;
3385 case OBJECT_EVENT_TRIGGER:
3386 msg = gettext_noop("permission denied for event trigger %s");
3387 break;
3388 case OBJECT_EXTENSION:
3389 msg = gettext_noop("permission denied for extension %s");
3390 break;
3391 case OBJECT_FDW:
3392 msg = gettext_noop("permission denied for foreign-data wrapper %s");
3393 break;
3394 case OBJECT_FOREIGN_SERVER:
3395 msg = gettext_noop("permission denied for foreign server %s");
3396 break;
3397 case OBJECT_FOREIGN_TABLE:
3398 msg = gettext_noop("permission denied for foreign table %s");
3399 break;
3400 case OBJECT_FUNCTION:
3401 msg = gettext_noop("permission denied for function %s");
3402 break;
3403 case OBJECT_INDEX:
3404 msg = gettext_noop("permission denied for index %s");
3405 break;
3406 case OBJECT_LANGUAGE:
3407 msg = gettext_noop("permission denied for language %s");
3408 break;
3409 case OBJECT_LARGEOBJECT:
3410 msg = gettext_noop("permission denied for large object %s");
3411 break;
3412 case OBJECT_MATVIEW:
3413 msg = gettext_noop("permission denied for materialized view %s");
3414 break;
3415 case OBJECT_OPCLASS:
3416 msg = gettext_noop("permission denied for operator class %s");
3417 break;
3418 case OBJECT_OPERATOR:
3419 msg = gettext_noop("permission denied for operator %s");
3420 break;
3421 case OBJECT_OPFAMILY:
3422 msg = gettext_noop("permission denied for operator family %s");
3423 break;
3424 case OBJECT_POLICY:
3425 msg = gettext_noop("permission denied for policy %s");
3426 break;
3427 case OBJECT_PROCEDURE:
3428 msg = gettext_noop("permission denied for procedure %s");
3429 break;
3430 case OBJECT_PUBLICATION:
3431 msg = gettext_noop("permission denied for publication %s");
3432 break;
3433 case OBJECT_ROUTINE:
3434 msg = gettext_noop("permission denied for routine %s");
3435 break;
3436 case OBJECT_SCHEMA:
3437 msg = gettext_noop("permission denied for schema %s");
3438 break;
3439 case OBJECT_SEQUENCE:
3440 msg = gettext_noop("permission denied for sequence %s");
3441 break;
3442 case OBJECT_STATISTIC_EXT:
3443 msg = gettext_noop("permission denied for statistics object %s");
3444 break;
3445 case OBJECT_SUBSCRIPTION:
3446 msg = gettext_noop("permission denied for subscription %s");
3447 break;
3448 case OBJECT_TABLE:
3449 msg = gettext_noop("permission denied for table %s");
3450 break;
3451 case OBJECT_TABLESPACE:
3452 msg = gettext_noop("permission denied for tablespace %s");
3453 break;
3454 case OBJECT_TSCONFIGURATION:
3455 msg = gettext_noop("permission denied for text search configuration %s");
3456 break;
3457 case OBJECT_TSDICTIONARY:
3458 msg = gettext_noop("permission denied for text search dictionary %s");
3459 break;
3460 case OBJECT_TYPE:
3461 msg = gettext_noop("permission denied for type %s");
3462 break;
3463 case OBJECT_VIEW:
3464 msg = gettext_noop("permission denied for view %s");
3465 break;
3466 /* these currently aren't used */
3467 case OBJECT_ACCESS_METHOD:
3468 case OBJECT_AMOP:
3469 case OBJECT_AMPROC:
3470 case OBJECT_ATTRIBUTE:
3471 case OBJECT_CAST:
3472 case OBJECT_DEFAULT:
3473 case OBJECT_DEFACL:
3474 case OBJECT_DOMCONSTRAINT:
3475 case OBJECT_PUBLICATION_REL:
3476 case OBJECT_ROLE:
3477 case OBJECT_RULE:
3478 case OBJECT_TABCONSTRAINT:
3479 case OBJECT_TRANSFORM:
3480 case OBJECT_TRIGGER:
3481 case OBJECT_TSPARSER:
3482 case OBJECT_TSTEMPLATE:
3483 case OBJECT_USER_MAPPING:
3484 elog(ERROR, "unsupported object type %d", objtype);
3485 }
3486
3487 ereport(ERROR,
3488 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3489 errmsg(msg, objectname)));
3490 break;
3491 }
3492 case ACLCHECK_NOT_OWNER:
3493 {
3494 const char *msg = "???";
3495
3496 switch (objtype)
3497 {
3498 case OBJECT_AGGREGATE:
3499 msg = gettext_noop("must be owner of aggregate %s");
3500 break;
3501 case OBJECT_COLLATION:
3502 msg = gettext_noop("must be owner of collation %s");
3503 break;
3504 case OBJECT_CONVERSION:
3505 msg = gettext_noop("must be owner of conversion %s");
3506 break;
3507 case OBJECT_DATABASE:
3508 msg = gettext_noop("must be owner of database %s");
3509 break;
3510 case OBJECT_DOMAIN:
3511 msg = gettext_noop("must be owner of domain %s");
3512 break;
3513 case OBJECT_EVENT_TRIGGER:
3514 msg = gettext_noop("must be owner of event trigger %s");
3515 break;
3516 case OBJECT_EXTENSION:
3517 msg = gettext_noop("must be owner of extension %s");
3518 break;
3519 case OBJECT_FDW:
3520 msg = gettext_noop("must be owner of foreign-data wrapper %s");
3521 break;
3522 case OBJECT_FOREIGN_SERVER:
3523 msg = gettext_noop("must be owner of foreign server %s");
3524 break;
3525 case OBJECT_FOREIGN_TABLE:
3526 msg = gettext_noop("must be owner of foreign table %s");
3527 break;
3528 case OBJECT_FUNCTION:
3529 msg = gettext_noop("must be owner of function %s");
3530 break;
3531 case OBJECT_INDEX:
3532 msg = gettext_noop("must be owner of index %s");
3533 break;
3534 case OBJECT_LANGUAGE:
3535 msg = gettext_noop("must be owner of language %s");
3536 break;
3537 case OBJECT_LARGEOBJECT:
3538 msg = gettext_noop("must be owner of large object %s");
3539 break;
3540 case OBJECT_MATVIEW:
3541 msg = gettext_noop("must be owner of materialized view %s");
3542 break;
3543 case OBJECT_OPCLASS:
3544 msg = gettext_noop("must be owner of operator class %s");
3545 break;
3546 case OBJECT_OPERATOR:
3547 msg = gettext_noop("must be owner of operator %s");
3548 break;
3549 case OBJECT_OPFAMILY:
3550 msg = gettext_noop("must be owner of operator family %s");
3551 break;
3552 case OBJECT_PROCEDURE:
3553 msg = gettext_noop("must be owner of procedure %s");
3554 break;
3555 case OBJECT_PUBLICATION:
3556 msg = gettext_noop("must be owner of publication %s");
3557 break;
3558 case OBJECT_ROUTINE:
3559 msg = gettext_noop("must be owner of routine %s");
3560 break;
3561 case OBJECT_SEQUENCE:
3562 msg = gettext_noop("must be owner of sequence %s");
3563 break;
3564 case OBJECT_SUBSCRIPTION:
3565 msg = gettext_noop("must be owner of subscription %s");
3566 break;
3567 case OBJECT_TABLE:
3568 msg = gettext_noop("must be owner of table %s");
3569 break;
3570 case OBJECT_TYPE:
3571 msg = gettext_noop("must be owner of type %s");
3572 break;
3573 case OBJECT_VIEW:
3574 msg = gettext_noop("must be owner of view %s");
3575 break;
3576 case OBJECT_SCHEMA:
3577 msg = gettext_noop("must be owner of schema %s");
3578 break;
3579 case OBJECT_STATISTIC_EXT:
3580 msg = gettext_noop("must be owner of statistics object %s");
3581 break;
3582 case OBJECT_TABLESPACE:
3583 msg = gettext_noop("must be owner of tablespace %s");
3584 break;
3585 case OBJECT_TSCONFIGURATION:
3586 msg = gettext_noop("must be owner of text search configuration %s");
3587 break;
3588 case OBJECT_TSDICTIONARY:
3589 msg = gettext_noop("must be owner of text search dictionary %s");
3590 break;
3591
3592 /*
3593 * Special cases: For these, the error message talks
3594 * about "relation", because that's where the
3595 * ownership is attached. See also
3596 * check_object_ownership().
3597 */
3598 case OBJECT_COLUMN:
3599 case OBJECT_POLICY:
3600 case OBJECT_RULE:
3601 case OBJECT_TABCONSTRAINT:
3602 case OBJECT_TRIGGER:
3603 msg = gettext_noop("must be owner of relation %s");
3604 break;
3605 /* these currently aren't used */
3606 case OBJECT_ACCESS_METHOD:
3607 case OBJECT_AMOP:
3608 case OBJECT_AMPROC:
3609 case OBJECT_ATTRIBUTE:
3610 case OBJECT_CAST:
3611 case OBJECT_DEFAULT:
3612 case OBJECT_DEFACL:
3613 case OBJECT_DOMCONSTRAINT:
3614 case OBJECT_PUBLICATION_REL:
3615 case OBJECT_ROLE:
3616 case OBJECT_TRANSFORM:
3617 case OBJECT_TSPARSER:
3618 case OBJECT_TSTEMPLATE:
3619 case OBJECT_USER_MAPPING:
3620 elog(ERROR, "unsupported object type %d", objtype);
3621 }
3622
3623 ereport(ERROR,
3624 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3625 errmsg(msg, objectname)));
3626 break;
3627 }
3628 default:
3629 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3630 break;
3631 }
3632}
3633
3634
3635void
3636aclcheck_error_col(AclResult aclerr, ObjectType objtype,
3637 const char *objectname, const char *colname)
3638{
3639 switch (aclerr)
3640 {
3641 case ACLCHECK_OK:
3642 /* no error, so return to caller */
3643 break;
3644 case ACLCHECK_NO_PRIV:
3645 ereport(ERROR,
3646 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3647 errmsg("permission denied for column \"%s\" of relation \"%s\"",
3648 colname, objectname)));
3649 break;
3650 case ACLCHECK_NOT_OWNER:
3651 /* relation msg is OK since columns don't have separate owners */
3652 aclcheck_error(aclerr, objtype, objectname);
3653 break;
3654 default:
3655 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3656 break;
3657 }
3658}
3659
3660
3661/*
3662 * Special common handling for types: use element type instead of array type,
3663 * and format nicely
3664 */
3665void
3666aclcheck_error_type(AclResult aclerr, Oid typeOid)
3667{
3668 Oid element_type = get_element_type(typeOid);
3669
3670 aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
3671}
3672
3673
3674/*
3675 * Relay for the various pg_*_mask routines depending on object kind
3676 */
3677static AclMode
3678pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid,
3679 AclMode mask, AclMaskHow how)
3680{
3681 switch (objtype)
3682 {
3683 case OBJECT_COLUMN:
3684 return
3685 pg_class_aclmask(table_oid, roleid, mask, how) |
3686 pg_attribute_aclmask(table_oid, attnum, roleid, mask, how);
3687 case OBJECT_TABLE:
3688 case OBJECT_SEQUENCE:
3689 return pg_class_aclmask(table_oid, roleid, mask, how);
3690 case OBJECT_DATABASE:
3691 return pg_database_aclmask(table_oid, roleid, mask, how);
3692 case OBJECT_FUNCTION:
3693 return pg_proc_aclmask(table_oid, roleid, mask, how);
3694 case OBJECT_LANGUAGE:
3695 return pg_language_aclmask(table_oid, roleid, mask, how);
3696 case OBJECT_LARGEOBJECT:
3697 return pg_largeobject_aclmask_snapshot(table_oid, roleid,
3698 mask, how, NULL);
3699 case OBJECT_SCHEMA:
3700 return pg_namespace_aclmask(table_oid, roleid, mask, how);
3701 case OBJECT_STATISTIC_EXT:
3702 elog(ERROR, "grantable rights not supported for statistics objects");
3703 /* not reached, but keep compiler quiet */
3704 return ACL_NO_RIGHTS;
3705 case OBJECT_TABLESPACE:
3706 return pg_tablespace_aclmask(table_oid, roleid, mask, how);
3707 case OBJECT_FDW:
3708 return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
3709 case OBJECT_FOREIGN_SERVER:
3710 return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
3711 case OBJECT_EVENT_TRIGGER:
3712 elog(ERROR, "grantable rights not supported for event triggers");
3713 /* not reached, but keep compiler quiet */
3714 return ACL_NO_RIGHTS;
3715 case OBJECT_TYPE:
3716 return pg_type_aclmask(table_oid, roleid, mask, how);
3717 default:
3718 elog(ERROR, "unrecognized objtype: %d",
3719 (int) objtype);
3720 /* not reached, but keep compiler quiet */
3721 return ACL_NO_RIGHTS;
3722 }
3723}
3724
3725
3726/* ****************************************************************
3727 * Exported routines for examining a user's privileges for various objects
3728 *
3729 * See aclmask() for a description of the common API for these functions.
3730 *
3731 * Note: we give lookup failure the full ereport treatment because the
3732 * has_xxx_privilege() family of functions allow users to pass any random
3733 * OID to these functions.
3734 * ****************************************************************
3735 */
3736
3737/*
3738 * Exported routine for examining a user's privileges for a column
3739 *
3740 * Note: this considers only privileges granted specifically on the column.
3741 * It is caller's responsibility to take relation-level privileges into account
3742 * as appropriate. (For the same reason, we have no special case for
3743 * superuser-ness here.)
3744 */
3745AclMode
3746pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
3747 AclMode mask, AclMaskHow how)
3748{
3749 AclMode result;
3750 HeapTuple classTuple;
3751 HeapTuple attTuple;
3752 Form_pg_class classForm;
3753 Form_pg_attribute attributeForm;
3754 Datum aclDatum;
3755 bool isNull;
3756 Acl *acl;
3757 Oid ownerId;
3758
3759 /*
3760 * First, get the column's ACL from its pg_attribute entry
3761 */
3762 attTuple = SearchSysCache2(ATTNUM,
3763 ObjectIdGetDatum(table_oid),
3764 Int16GetDatum(attnum));
3765 if (!HeapTupleIsValid(attTuple))
3766 ereport(ERROR,
3767 (errcode(ERRCODE_UNDEFINED_COLUMN),
3768 errmsg("attribute %d of relation with OID %u does not exist",
3769 attnum, table_oid)));
3770 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3771
3772 /* Throw error on dropped columns, too */
3773 if (attributeForm->attisdropped)
3774 ereport(ERROR,
3775 (errcode(ERRCODE_UNDEFINED_COLUMN),
3776 errmsg("attribute %d of relation with OID %u does not exist",
3777 attnum, table_oid)));
3778
3779 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3780 &isNull);
3781
3782 /*
3783 * Here we hard-wire knowledge that the default ACL for a column grants no
3784 * privileges, so that we can fall out quickly in the very common case
3785 * where attacl is null.
3786 */
3787 if (isNull)
3788 {
3789 ReleaseSysCache(attTuple);
3790 return 0;
3791 }
3792
3793 /*
3794 * Must get the relation's ownerId from pg_class. Since we already found
3795 * a pg_attribute entry, the only likely reason for this to fail is that a
3796 * concurrent DROP of the relation committed since then (which could only
3797 * happen if we don't have lock on the relation). We prefer to report "no
3798 * privileges" rather than failing in such a case, so as to avoid unwanted
3799 * failures in has_column_privilege() tests.
3800 */
3801 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3802 if (!HeapTupleIsValid(classTuple))
3803 {
3804 ReleaseSysCache(attTuple);
3805 return 0;
3806 }
3807 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3808
3809 ownerId = classForm->relowner;
3810
3811 ReleaseSysCache(classTuple);
3812
3813 /* detoast column's ACL if necessary */
3814 acl = DatumGetAclP(aclDatum);
3815
3816 result = aclmask(acl, roleid, ownerId, mask, how);
3817
3818 /* if we have a detoasted copy, free it */
3819 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3820 pfree(acl);
3821
3822 ReleaseSysCache(attTuple);
3823
3824 return result;
3825}
3826
3827/*
3828 * Exported routine for examining a user's privileges for a table
3829 */
3830AclMode
3831pg_class_aclmask(Oid table_oid, Oid roleid,
3832 AclMode mask, AclMaskHow how)
3833{
3834 AclMode result;
3835 HeapTuple tuple;
3836 Form_pg_class classForm;
3837 Datum aclDatum;
3838 bool isNull;
3839 Acl *acl;
3840 Oid ownerId;
3841
3842 /*
3843 * Must get the relation's tuple from pg_class
3844 */
3845 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3846 if (!HeapTupleIsValid(tuple))
3847 ereport(ERROR,
3848 (errcode(ERRCODE_UNDEFINED_TABLE),
3849 errmsg("relation with OID %u does not exist",
3850 table_oid)));
3851 classForm = (Form_pg_class) GETSTRUCT(tuple);
3852
3853 /*
3854 * Deny anyone permission to update a system catalog unless
3855 * pg_authid.rolsuper is set. Also allow it if allowSystemTableMods.
3856 *
3857 * As of 7.4 we have some updatable system views; those shouldn't be
3858 * protected in this way. Assume the view rules can take care of
3859 * themselves. ACL_USAGE is if we ever have system sequences.
3860 */
3861 if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3862 IsSystemClass(table_oid, classForm) &&
3863 classForm->relkind != RELKIND_VIEW &&
3864 !superuser_arg(roleid) &&
3865 !allowSystemTableMods)
3866 {
3867#ifdef ACLDEBUG
3868 elog(DEBUG2, "permission denied for system catalog update");
3869#endif
3870 mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
3871 }
3872
3873 /*
3874 * Otherwise, superusers bypass all permission-checking.
3875 */
3876 if (superuser_arg(roleid))
3877 {
3878#ifdef ACLDEBUG
3879 elog(DEBUG2, "OID %u is superuser, home free", roleid);
3880#endif
3881 ReleaseSysCache(tuple);
3882 return mask;
3883 }
3884
3885 /*
3886 * Normal case: get the relation's ACL from pg_class
3887 */
3888 ownerId = classForm->relowner;
3889
3890 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3891 &isNull);
3892 if (isNull)
3893 {
3894 /* No ACL, so build default ACL */
3895 switch (classForm->relkind)
3896 {
3897 case RELKIND_SEQUENCE:
3898 acl = acldefault(OBJECT_SEQUENCE, ownerId);
3899 break;
3900 default:
3901 acl = acldefault(OBJECT_TABLE, ownerId);
3902 break;
3903 }
3904 aclDatum = (Datum) 0;
3905 }
3906 else
3907 {
3908 /* detoast rel's ACL if necessary */
3909 acl = DatumGetAclP(aclDatum);
3910 }
3911
3912 result = aclmask(acl, roleid, ownerId, mask, how);
3913
3914 /* if we have a detoasted copy, free it */
3915 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3916 pfree(acl);
3917
3918 ReleaseSysCache(tuple);
3919
3920 return result;
3921}
3922
3923/*
3924 * Exported routine for examining a user's privileges for a database
3925 */
3926AclMode
3927pg_database_aclmask(Oid db_oid, Oid roleid,
3928 AclMode mask, AclMaskHow how)
3929{
3930 AclMode result;
3931 HeapTuple tuple;
3932 Datum aclDatum;
3933 bool isNull;
3934 Acl *acl;
3935 Oid ownerId;
3936
3937 /* Superusers bypass all permission checking. */
3938 if (superuser_arg(roleid))
3939 return mask;
3940
3941 /*
3942 * Get the database's ACL from pg_database
3943 */
3944 tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
3945 if (!HeapTupleIsValid(tuple))
3946 ereport(ERROR,
3947 (errcode(ERRCODE_UNDEFINED_DATABASE),
3948 errmsg("database with OID %u does not exist", db_oid)));
3949
3950 ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
3951
3952 aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
3953 &isNull);
3954 if (isNull)
3955 {
3956 /* No ACL, so build default ACL */
3957 acl = acldefault(OBJECT_DATABASE, ownerId);
3958 aclDatum = (Datum) 0;
3959 }
3960 else
3961 {
3962 /* detoast ACL if necessary */
3963 acl = DatumGetAclP(aclDatum);
3964 }
3965
3966 result = aclmask(acl, roleid, ownerId, mask, how);
3967
3968 /* if we have a detoasted copy, free it */
3969 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3970 pfree(acl);
3971
3972 ReleaseSysCache(tuple);
3973
3974 return result;
3975}
3976
3977/*
3978 * Exported routine for examining a user's privileges for a function
3979 */
3980AclMode
3981pg_proc_aclmask(Oid proc_oid, Oid roleid,
3982 AclMode mask, AclMaskHow how)
3983{
3984 AclMode result;
3985 HeapTuple tuple;
3986 Datum aclDatum;
3987 bool isNull;
3988 Acl *acl;
3989 Oid ownerId;
3990
3991 /* Superusers bypass all permission checking. */
3992 if (superuser_arg(roleid))
3993 return mask;
3994
3995 /*
3996 * Get the function's ACL from pg_proc
3997 */
3998 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
3999 if (!HeapTupleIsValid(tuple))
4000 ereport(ERROR,
4001 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4002 errmsg("function with OID %u does not exist", proc_oid)));
4003
4004 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
4005
4006 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
4007 &isNull);
4008 if (isNull)
4009 {
4010 /* No ACL, so build default ACL */
4011 acl = acldefault(OBJECT_FUNCTION, ownerId);
4012 aclDatum = (Datum) 0;
4013 }
4014 else
4015 {
4016 /* detoast ACL if necessary */
4017 acl = DatumGetAclP(aclDatum);
4018 }
4019
4020 result = aclmask(acl, roleid, ownerId, mask, how);
4021
4022 /* if we have a detoasted copy, free it */
4023 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4024 pfree(acl);
4025
4026 ReleaseSysCache(tuple);
4027
4028 return result;
4029}
4030
4031/*
4032 * Exported routine for examining a user's privileges for a language
4033 */
4034AclMode
4035pg_language_aclmask(Oid lang_oid, Oid roleid,
4036 AclMode mask, AclMaskHow how)
4037{
4038 AclMode result;
4039 HeapTuple tuple;
4040 Datum aclDatum;
4041 bool isNull;
4042 Acl *acl;
4043 Oid ownerId;
4044
4045 /* Superusers bypass all permission checking. */
4046 if (superuser_arg(roleid))
4047 return mask;
4048
4049 /*
4050 * Get the language's ACL from pg_language
4051 */
4052 tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid));
4053 if (!HeapTupleIsValid(tuple))
4054 ereport(ERROR,
4055 (errcode(ERRCODE_UNDEFINED_OBJECT),
4056 errmsg("language with OID %u does not exist", lang_oid)));
4057
4058 ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
4059
4060 aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
4061 &isNull);
4062 if (isNull)
4063 {
4064 /* No ACL, so build default ACL */
4065 acl = acldefault(OBJECT_LANGUAGE, ownerId);
4066 aclDatum = (Datum) 0;
4067 }
4068 else
4069 {
4070 /* detoast ACL if necessary */
4071 acl = DatumGetAclP(aclDatum);
4072 }
4073
4074 result = aclmask(acl, roleid, ownerId, mask, how);
4075
4076 /* if we have a detoasted copy, free it */
4077 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4078 pfree(acl);
4079
4080 ReleaseSysCache(tuple);
4081
4082 return result;
4083}
4084
4085/*
4086 * Exported routine for examining a user's privileges for a largeobject
4087 *
4088 * When a large object is opened for reading, it is opened relative to the
4089 * caller's snapshot, but when it is opened for writing, a current
4090 * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
4091 * takes a snapshot argument so that the permissions check can be made
4092 * relative to the same snapshot that will be used to read the underlying
4093 * data. The caller will actually pass NULL for an instantaneous MVCC
4094 * snapshot, since all we do with the snapshot argument is pass it through
4095 * to systable_beginscan().
4096 */
4097AclMode
4098pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
4099 AclMode mask, AclMaskHow how,
4100 Snapshot snapshot)
4101{
4102 AclMode result;
4103 Relation pg_lo_meta;
4104 ScanKeyData entry[1];
4105 SysScanDesc scan;
4106 HeapTuple tuple;
4107 Datum aclDatum;
4108 bool isNull;
4109 Acl *acl;
4110 Oid ownerId;
4111
4112 /* Superusers bypass all permission checking. */
4113 if (superuser_arg(roleid))
4114 return mask;
4115
4116 /*
4117 * Get the largeobject's ACL from pg_language_metadata
4118 */
4119 pg_lo_meta = table_open(LargeObjectMetadataRelationId,
4120 AccessShareLock);
4121
4122 ScanKeyInit(&entry[0],
4123 Anum_pg_largeobject_metadata_oid,
4124 BTEqualStrategyNumber, F_OIDEQ,
4125 ObjectIdGetDatum(lobj_oid));
4126
4127 scan = systable_beginscan(pg_lo_meta,
4128 LargeObjectMetadataOidIndexId, true,
4129 snapshot, 1, entry);
4130
4131 tuple = systable_getnext(scan);
4132 if (!HeapTupleIsValid(tuple))
4133 ereport(ERROR,
4134 (errcode(ERRCODE_UNDEFINED_OBJECT),
4135 errmsg("large object %u does not exist", lobj_oid)));
4136
4137 ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
4138
4139 aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
4140 RelationGetDescr(pg_lo_meta), &isNull);
4141
4142 if (isNull)
4143 {
4144 /* No ACL, so build default ACL */
4145 acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
4146 aclDatum = (Datum) 0;
4147 }
4148 else
4149 {
4150 /* detoast ACL if necessary */
4151 acl = DatumGetAclP(aclDatum);
4152 }
4153
4154 result = aclmask(acl, roleid, ownerId, mask, how);
4155
4156 /* if we have a detoasted copy, free it */
4157 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4158 pfree(acl);
4159
4160 systable_endscan(scan);
4161
4162 table_close(pg_lo_meta, AccessShareLock);
4163
4164 return result;
4165}
4166
4167/*
4168 * Exported routine for examining a user's privileges for a namespace
4169 */
4170AclMode
4171pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
4172 AclMode mask, AclMaskHow how)
4173{
4174 AclMode result;
4175 HeapTuple tuple;
4176 Datum aclDatum;
4177 bool isNull;
4178 Acl *acl;
4179 Oid ownerId;
4180
4181 /* Superusers bypass all permission checking. */
4182 if (superuser_arg(roleid))
4183 return mask;
4184
4185 /*
4186 * If we have been assigned this namespace as a temp namespace, check to
4187 * make sure we have CREATE TEMP permission on the database, and if so act
4188 * as though we have all standard (but not GRANT OPTION) permissions on
4189 * the namespace. If we don't have CREATE TEMP, act as though we have
4190 * only USAGE (and not CREATE) rights.
4191 *
4192 * This may seem redundant given the check in InitTempTableNamespace, but
4193 * it really isn't since current user ID may have changed since then. The
4194 * upshot of this behavior is that a SECURITY DEFINER function can create
4195 * temp tables that can then be accessed (if permission is granted) by
4196 * code in the same session that doesn't have permissions to create temp
4197 * tables.
4198 *
4199 * XXX Would it be safe to ereport a special error message as
4200 * InitTempTableNamespace does? Returning zero here means we'll get a
4201 * generic "permission denied for schema pg_temp_N" message, which is not
4202 * remarkably user-friendly.
4203 */
4204 if (isTempNamespace(nsp_oid))
4205 {
4206 if (pg_database_aclcheck(MyDatabaseId, roleid,
4207 ACL_CREATE_TEMP) == ACLCHECK_OK)
4208 return mask & ACL_ALL_RIGHTS_SCHEMA;
4209 else
4210 return mask & ACL_USAGE;
4211 }
4212
4213 /*
4214 * Get the schema's ACL from pg_namespace
4215 */
4216 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
4217 if (!HeapTupleIsValid(tuple))
4218 ereport(ERROR,
4219 (errcode(ERRCODE_UNDEFINED_SCHEMA),
4220 errmsg("schema with OID %u does not exist", nsp_oid)));
4221
4222 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
4223
4224 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
4225 &isNull);
4226 if (isNull)
4227 {
4228 /* No ACL, so build default ACL */
4229 acl = acldefault(OBJECT_SCHEMA, ownerId);
4230 aclDatum = (Datum) 0;
4231 }
4232 else
4233 {
4234 /* detoast ACL if necessary */
4235 acl = DatumGetAclP(aclDatum);
4236 }
4237
4238 result = aclmask(acl, roleid, ownerId, mask, how);
4239
4240 /* if we have a detoasted copy, free it */
4241 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4242 pfree(acl);
4243
4244 ReleaseSysCache(tuple);
4245
4246 return result;
4247}
4248
4249/*
4250 * Exported routine for examining a user's privileges for a tablespace
4251 */
4252AclMode
4253pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
4254 AclMode mask, AclMaskHow how)
4255{
4256 AclMode result;
4257 HeapTuple tuple;
4258 Datum aclDatum;
4259 bool isNull;
4260 Acl *acl;
4261 Oid ownerId;
4262
4263 /* Superusers bypass all permission checking. */
4264 if (superuser_arg(roleid))
4265 return mask;
4266
4267 /*
4268 * Get the tablespace's ACL from pg_tablespace
4269 */
4270 tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
4271 if (!HeapTupleIsValid(tuple))
4272 ereport(ERROR,
4273 (errcode(ERRCODE_UNDEFINED_OBJECT),
4274 errmsg("tablespace with OID %u does not exist", spc_oid)));
4275
4276 ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
4277
4278 aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple,
4279 Anum_pg_tablespace_spcacl,
4280 &isNull);
4281
4282 if (isNull)
4283 {
4284 /* No ACL, so build default ACL */
4285 acl = acldefault(OBJECT_TABLESPACE, ownerId);
4286 aclDatum = (Datum) 0;
4287 }
4288 else
4289 {
4290 /* detoast ACL if necessary */
4291 acl = DatumGetAclP(aclDatum);
4292 }
4293
4294 result = aclmask(acl, roleid, ownerId, mask, how);
4295
4296 /* if we have a detoasted copy, free it */
4297 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4298 pfree(acl);
4299
4300 ReleaseSysCache(tuple);
4301
4302 return result;
4303}
4304
4305/*
4306 * Exported routine for examining a user's privileges for a foreign
4307 * data wrapper
4308 */
4309AclMode
4310pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
4311 AclMode mask, AclMaskHow how)
4312{
4313 AclMode result;
4314 HeapTuple tuple;
4315 Datum aclDatum;
4316 bool isNull;
4317 Acl *acl;
4318 Oid ownerId;
4319
4320 Form_pg_foreign_data_wrapper fdwForm;
4321
4322 /* Bypass permission checks for superusers */
4323 if (superuser_arg(roleid))
4324 return mask;
4325
4326 /*
4327 * Must get the FDW's tuple from pg_foreign_data_wrapper
4328 */
4329 tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdw_oid));
4330 if (!HeapTupleIsValid(tuple))
4331 ereport(ERROR,
4332 (errcode(ERRCODE_UNDEFINED_OBJECT),
4333 errmsg("foreign-data wrapper with OID %u does not exist",
4334 fdw_oid)));
4335 fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
4336
4337 /*
4338 * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
4339 */
4340 ownerId = fdwForm->fdwowner;
4341
4342 aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
4343 Anum_pg_foreign_data_wrapper_fdwacl, &isNull);
4344 if (isNull)
4345 {
4346 /* No ACL, so build default ACL */
4347 acl = acldefault(OBJECT_FDW, ownerId);
4348 aclDatum = (Datum) 0;
4349 }
4350 else
4351 {
4352 /* detoast rel's ACL if necessary */
4353 acl = DatumGetAclP(aclDatum);
4354 }
4355
4356 result = aclmask(acl, roleid, ownerId, mask, how);
4357
4358 /* if we have a detoasted copy, free it */
4359 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4360 pfree(acl);
4361
4362 ReleaseSysCache(tuple);
4363
4364 return result;
4365}
4366
4367/*
4368 * Exported routine for examining a user's privileges for a foreign
4369 * server.
4370 */
4371AclMode
4372pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
4373 AclMode mask, AclMaskHow how)
4374{
4375 AclMode result;
4376 HeapTuple tuple;
4377 Datum aclDatum;
4378 bool isNull;
4379 Acl *acl;
4380 Oid ownerId;
4381
4382 Form_pg_foreign_server srvForm;
4383
4384 /* Bypass permission checks for superusers */
4385 if (superuser_arg(roleid))
4386 return mask;
4387
4388 /*
4389 * Must get the FDW's tuple from pg_foreign_data_wrapper
4390 */
4391 tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
4392 if (!HeapTupleIsValid(tuple))
4393 ereport(ERROR,
4394 (errcode(ERRCODE_UNDEFINED_OBJECT),
4395 errmsg("foreign server with OID %u does not exist",
4396 srv_oid)));
4397 srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
4398
4399 /*
4400 * Normal case: get the foreign server's ACL from pg_foreign_server
4401 */
4402 ownerId = srvForm->srvowner;
4403
4404 aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
4405 Anum_pg_foreign_server_srvacl, &isNull);
4406 if (isNull)
4407 {
4408 /* No ACL, so build default ACL */
4409 acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
4410 aclDatum = (Datum) 0;
4411 }
4412 else
4413 {
4414 /* detoast rel's ACL if necessary */
4415 acl = DatumGetAclP(aclDatum);
4416 }
4417
4418 result = aclmask(acl, roleid, ownerId, mask, how);
4419
4420 /* if we have a detoasted copy, free it */
4421 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4422 pfree(acl);
4423
4424 ReleaseSysCache(tuple);
4425
4426 return result;
4427}
4428
4429/*
4430 * Exported routine for examining a user's privileges for a type.
4431 */
4432AclMode
4433pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
4434{
4435 AclMode result;
4436 HeapTuple tuple;
4437 Datum aclDatum;
4438 bool isNull;
4439 Acl *acl;
4440 Oid ownerId;
4441
4442 Form_pg_type typeForm;
4443
4444 /* Bypass permission checks for superusers */
4445 if (superuser_arg(roleid))
4446 return mask;
4447
4448 /*
4449 * Must get the type's tuple from pg_type
4450 */
4451 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
4452 if (!HeapTupleIsValid(tuple))
4453 ereport(ERROR,
4454 (errcode(ERRCODE_UNDEFINED_OBJECT),
4455 errmsg("type with OID %u does not exist",
4456 type_oid)));
4457 typeForm = (Form_pg_type) GETSTRUCT(tuple);
4458
4459 /*
4460 * "True" array types don't manage permissions of their own; consult the
4461 * element type instead.
4462 */
4463 if (OidIsValid(typeForm->typelem) && typeForm->typlen == -1)
4464 {
4465 Oid elttype_oid = typeForm->typelem;
4466
4467 ReleaseSysCache(tuple);
4468
4469 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
4470 /* this case is not a user-facing error, so elog not ereport */
4471 if (!HeapTupleIsValid(tuple))
4472 elog(ERROR, "cache lookup failed for type %u", elttype_oid);
4473 typeForm = (Form_pg_type) GETSTRUCT(tuple);
4474 }
4475
4476 /*
4477 * Now get the type's owner and ACL from the tuple
4478 */
4479 ownerId = typeForm->typowner;
4480
4481 aclDatum = SysCacheGetAttr(TYPEOID, tuple,
4482 Anum_pg_type_typacl, &isNull);
4483 if (isNull)
4484 {
4485 /* No ACL, so build default ACL */
4486 acl = acldefault(OBJECT_TYPE, ownerId);
4487 aclDatum = (Datum) 0;
4488 }
4489 else
4490 {
4491 /* detoast rel's ACL if necessary */
4492 acl = DatumGetAclP(aclDatum);
4493 }
4494
4495 result = aclmask(acl, roleid, ownerId, mask, how);
4496
4497 /* if we have a detoasted copy, free it */
4498 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4499 pfree(acl);
4500
4501 ReleaseSysCache(tuple);
4502
4503 return result;
4504}
4505
4506/*
4507 * Exported routine for checking a user's access privileges to a column
4508 *
4509 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4510 * 'mode'; otherwise returns a suitable error code (in practice, always
4511 * ACLCHECK_NO_PRIV).
4512 *
4513 * As with pg_attribute_aclmask, only privileges granted directly on the
4514 * column are considered here.
4515 */
4516AclResult
4517pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
4518 Oid roleid, AclMode mode)
4519{
4520 if (pg_attribute_aclmask(table_oid, attnum, roleid, mode, ACLMASK_ANY) != 0)
4521 return ACLCHECK_OK;
4522 else
4523 return ACLCHECK_NO_PRIV;
4524}
4525
4526/*
4527 * Exported routine for checking a user's access privileges to any/all columns
4528 *
4529 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
4530 * privileges identified by 'mode' on any non-dropped column in the relation;
4531 * otherwise returns a suitable error code (in practice, always
4532 * ACLCHECK_NO_PRIV).
4533 *
4534 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
4535 * privileges identified by 'mode' on each non-dropped column in the relation
4536 * (and there must be at least one such column); otherwise returns a suitable
4537 * error code (in practice, always ACLCHECK_NO_PRIV).
4538 *
4539 * As with pg_attribute_aclmask, only privileges granted directly on the
4540 * column(s) are considered here.
4541 *
4542 * Note: system columns are not considered here; there are cases where that
4543 * might be appropriate but there are also cases where it wouldn't.
4544 */
4545AclResult
4546pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
4547 AclMaskHow how)
4548{
4549 AclResult result;
4550 HeapTuple classTuple;
4551 Form_pg_class classForm;
4552 AttrNumber nattrs;
4553 AttrNumber curr_att;
4554
4555 /*
4556 * Must fetch pg_class row to check number of attributes. As in
4557 * pg_attribute_aclmask, we prefer to return "no privileges" instead of
4558 * throwing an error if we get any unexpected lookup errors.
4559 */
4560 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
4561 if (!HeapTupleIsValid(classTuple))
4562 return ACLCHECK_NO_PRIV;
4563 classForm = (Form_pg_class) GETSTRUCT(classTuple);
4564
4565 nattrs = classForm->relnatts;
4566
4567 ReleaseSysCache(classTuple);
4568
4569 /*
4570 * Initialize result in case there are no non-dropped columns. We want to
4571 * report failure in such cases for either value of 'how'.
4572 */
4573 result = ACLCHECK_NO_PRIV;
4574
4575 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4576 {
4577 HeapTuple attTuple;
4578 AclMode attmask;
4579
4580 attTuple = SearchSysCache2(ATTNUM,
4581 ObjectIdGetDatum(table_oid),
4582 Int16GetDatum(curr_att));
4583 if (!HeapTupleIsValid(attTuple))
4584 continue;
4585
4586 /* ignore dropped columns */
4587 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4588 {
4589 ReleaseSysCache(attTuple);
4590 continue;
4591 }
4592
4593 /*
4594 * Here we hard-wire knowledge that the default ACL for a column
4595 * grants no privileges, so that we can fall out quickly in the very
4596 * common case where attacl is null.
4597 */
4598 if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
4599 attmask = 0;
4600 else
4601 attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
4602 mode, ACLMASK_ANY);
4603
4604 ReleaseSysCache(attTuple);
4605
4606 if (attmask != 0)
4607 {
4608 result = ACLCHECK_OK;
4609 if (how == ACLMASK_ANY)
4610 break; /* succeed on any success */
4611 }
4612 else
4613 {
4614 result = ACLCHECK_NO_PRIV;
4615 if (how == ACLMASK_ALL)
4616 break; /* fail on any failure */
4617 }
4618 }
4619
4620 return result;
4621}
4622
4623/*
4624 * Exported routine for checking a user's access privileges to a table
4625 *
4626 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4627 * 'mode'; otherwise returns a suitable error code (in practice, always
4628 * ACLCHECK_NO_PRIV).
4629 */
4630AclResult
4631pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
4632{
4633 if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
4634 return ACLCHECK_OK;
4635 else
4636 return ACLCHECK_NO_PRIV;
4637}
4638
4639/*
4640 * Exported routine for checking a user's access privileges to a database
4641 */
4642AclResult
4643pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
4644{
4645 if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
4646 return ACLCHECK_OK;
4647 else
4648 return ACLCHECK_NO_PRIV;
4649}
4650
4651/*
4652 * Exported routine for checking a user's access privileges to a function
4653 */
4654AclResult
4655pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
4656{
4657 if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
4658 return ACLCHECK_OK;
4659 else
4660 return ACLCHECK_NO_PRIV;
4661}
4662
4663/*
4664 * Exported routine for checking a user's access privileges to a language
4665 */
4666AclResult
4667pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
4668{
4669 if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
4670 return ACLCHECK_OK;
4671 else
4672 return ACLCHECK_NO_PRIV;
4673}
4674
4675/*
4676 * Exported routine for checking a user's access privileges to a largeobject
4677 */
4678AclResult
4679pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
4680 Snapshot snapshot)
4681{
4682 if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4683 ACLMASK_ANY, snapshot) != 0)
4684 return ACLCHECK_OK;
4685 else
4686 return ACLCHECK_NO_PRIV;
4687}
4688
4689/*
4690 * Exported routine for checking a user's access privileges to a namespace
4691 */
4692AclResult
4693pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
4694{
4695 if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
4696 return ACLCHECK_OK;
4697 else
4698 return ACLCHECK_NO_PRIV;
4699}
4700
4701/*
4702 * Exported routine for checking a user's access privileges to a tablespace
4703 */
4704AclResult
4705pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
4706{
4707 if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
4708 return ACLCHECK_OK;
4709 else
4710 return ACLCHECK_NO_PRIV;
4711}
4712
4713/*
4714 * Exported routine for checking a user's access privileges to a foreign
4715 * data wrapper
4716 */
4717AclResult
4718pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode)
4719{
4720 if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0)
4721 return ACLCHECK_OK;
4722 else
4723 return ACLCHECK_NO_PRIV;
4724}
4725
4726/*
4727 * Exported routine for checking a user's access privileges to a foreign
4728 * server
4729 */
4730AclResult
4731pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
4732{
4733 if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0)
4734 return ACLCHECK_OK;
4735 else
4736 return ACLCHECK_NO_PRIV;
4737}
4738
4739/*
4740 * Exported routine for checking a user's access privileges to a type
4741 */
4742AclResult
4743pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
4744{
4745 if (pg_type_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0)
4746 return ACLCHECK_OK;
4747 else
4748 return ACLCHECK_NO_PRIV;
4749}
4750
4751/*
4752 * Ownership check for a relation (specified by OID).
4753 */
4754bool
4755pg_class_ownercheck(Oid class_oid, Oid roleid)
4756{
4757 HeapTuple tuple;
4758 Oid ownerId;
4759
4760 /* Superusers bypass all permission checking. */
4761 if (superuser_arg(roleid))
4762 return true;
4763
4764 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid));
4765 if (!HeapTupleIsValid(tuple))
4766 ereport(ERROR,
4767 (errcode(ERRCODE_UNDEFINED_TABLE),
4768 errmsg("relation with OID %u does not exist", class_oid)));
4769
4770 ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
4771
4772 ReleaseSysCache(tuple);
4773
4774 return has_privs_of_role(roleid, ownerId);
4775}
4776
4777/*
4778 * Ownership check for a type (specified by OID).
4779 */
4780bool
4781pg_type_ownercheck(Oid type_oid, Oid roleid)
4782{
4783 HeapTuple tuple;
4784 Oid ownerId;
4785
4786 /* Superusers bypass all permission checking. */
4787 if (superuser_arg(roleid))
4788 return true;
4789
4790 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
4791 if (!HeapTupleIsValid(tuple))
4792 ereport(ERROR,
4793 (errcode(ERRCODE_UNDEFINED_OBJECT),
4794 errmsg("type with OID %u does not exist", type_oid)));
4795
4796 ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
4797
4798 ReleaseSysCache(tuple);
4799
4800 return has_privs_of_role(roleid, ownerId);
4801}
4802
4803/*
4804 * Ownership check for an operator (specified by OID).
4805 */
4806bool
4807pg_oper_ownercheck(Oid oper_oid, Oid roleid)
4808{
4809 HeapTuple tuple;
4810 Oid ownerId;
4811
4812 /* Superusers bypass all permission checking. */
4813 if (superuser_arg(roleid))
4814 return true;
4815
4816 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(oper_oid));
4817 if (!HeapTupleIsValid(tuple))
4818 ereport(ERROR,
4819 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4820 errmsg("operator with OID %u does not exist", oper_oid)));
4821
4822 ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
4823
4824 ReleaseSysCache(tuple);
4825
4826 return has_privs_of_role(roleid, ownerId);
4827}
4828
4829/*
4830 * Ownership check for a function (specified by OID).
4831 */
4832bool
4833pg_proc_ownercheck(Oid proc_oid, Oid roleid)
4834{
4835 HeapTuple tuple;
4836 Oid ownerId;
4837
4838 /* Superusers bypass all permission checking. */
4839 if (superuser_arg(roleid))
4840 return true;
4841
4842 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
4843 if (!HeapTupleIsValid(tuple))
4844 ereport(ERROR,
4845 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4846 errmsg("function with OID %u does not exist", proc_oid)));
4847
4848 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
4849
4850 ReleaseSysCache(tuple);
4851
4852 return has_privs_of_role(roleid, ownerId);
4853}
4854
4855/*
4856 * Ownership check for a procedural language (specified by OID)
4857 */
4858bool
4859pg_language_ownercheck(Oid lan_oid, Oid roleid)
4860{
4861 HeapTuple tuple;
4862 Oid ownerId;
4863
4864 /* Superusers bypass all permission checking. */
4865 if (superuser_arg(roleid))
4866 return true;
4867
4868 tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lan_oid));
4869 if (!HeapTupleIsValid(tuple))
4870 ereport(ERROR,
4871 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4872 errmsg("language with OID %u does not exist", lan_oid)));
4873
4874 ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
4875
4876 ReleaseSysCache(tuple);
4877
4878 return has_privs_of_role(roleid, ownerId);
4879}
4880
4881/*
4882 * Ownership check for a largeobject (specified by OID)
4883 *
4884 * This is only used for operations like ALTER LARGE OBJECT that are always
4885 * relative to an up-to-date snapshot.
4886 */
4887bool
4888pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
4889{
4890 Relation pg_lo_meta;
4891 ScanKeyData entry[1];
4892 SysScanDesc scan;
4893 HeapTuple tuple;
4894 Oid ownerId;
4895
4896 /* Superusers bypass all permission checking. */
4897 if (superuser_arg(roleid))
4898 return true;
4899
4900 /* There's no syscache for pg_largeobject_metadata */
4901 pg_lo_meta = table_open(LargeObjectMetadataRelationId,
4902 AccessShareLock);
4903
4904 ScanKeyInit(&entry[0],
4905 Anum_pg_largeobject_metadata_oid,
4906 BTEqualStrategyNumber, F_OIDEQ,
4907 ObjectIdGetDatum(lobj_oid));
4908
4909 scan = systable_beginscan(pg_lo_meta,
4910 LargeObjectMetadataOidIndexId, true,
4911 NULL, 1, entry);
4912
4913 tuple = systable_getnext(scan);
4914 if (!HeapTupleIsValid(tuple))
4915 ereport(ERROR,
4916 (errcode(ERRCODE_UNDEFINED_OBJECT),
4917 errmsg("large object %u does not exist", lobj_oid)));
4918
4919 ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
4920
4921 systable_endscan(scan);
4922 table_close(pg_lo_meta, AccessShareLock);
4923
4924 return has_privs_of_role(roleid, ownerId);
4925}
4926
4927/*
4928 * Ownership check for a namespace (specified by OID).
4929 */
4930bool
4931pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
4932{
4933 HeapTuple tuple;
4934 Oid ownerId;
4935
4936 /* Superusers bypass all permission checking. */
4937 if (superuser_arg(roleid))
4938 return true;
4939
4940 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
4941 if (!HeapTupleIsValid(tuple))
4942 ereport(ERROR,
4943 (errcode(ERRCODE_UNDEFINED_SCHEMA),
4944 errmsg("schema with OID %u does not exist", nsp_oid)));
4945
4946 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
4947
4948 ReleaseSysCache(tuple);
4949
4950 return has_privs_of_role(roleid, ownerId);
4951}
4952
4953/*
4954 * Ownership check for a tablespace (specified by OID).
4955 */
4956bool
4957pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
4958{
4959 HeapTuple spctuple;
4960 Oid spcowner;
4961
4962 /* Superusers bypass all permission checking. */
4963 if (superuser_arg(roleid))
4964 return true;
4965
4966 /* Search syscache for pg_tablespace */
4967 spctuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
4968 if (!HeapTupleIsValid(spctuple))
4969 ereport(ERROR,
4970 (errcode(ERRCODE_UNDEFINED_OBJECT),
4971 errmsg("tablespace with OID %u does not exist", spc_oid)));
4972
4973 spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
4974
4975 ReleaseSysCache(spctuple);
4976
4977 return has_privs_of_role(roleid, spcowner);
4978}
4979
4980/*
4981 * Ownership check for an operator class (specified by OID).
4982 */
4983bool
4984pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
4985{
4986 HeapTuple tuple;
4987 Oid ownerId;
4988
4989 /* Superusers bypass all permission checking. */
4990 if (superuser_arg(roleid))
4991 return true;
4992
4993 tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opc_oid));
4994 if (!HeapTupleIsValid(tuple))
4995 ereport(ERROR,
4996 (errcode(ERRCODE_UNDEFINED_OBJECT),
4997 errmsg("operator class with OID %u does not exist",
4998 opc_oid)));
4999
5000 ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
5001
5002 ReleaseSysCache(tuple);
5003
5004 return has_privs_of_role(roleid, ownerId);
5005}
5006
5007/*
5008 * Ownership check for an operator family (specified by OID).
5009 */
5010bool
5011pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
5012{
5013 HeapTuple tuple;
5014 Oid ownerId;
5015
5016 /* Superusers bypass all permission checking. */
5017 if (superuser_arg(roleid))
5018 return true;
5019
5020 tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opf_oid));
5021 if (!HeapTupleIsValid(tuple))
5022 ereport(ERROR,
5023 (errcode(ERRCODE_UNDEFINED_OBJECT),
5024 errmsg("operator family with OID %u does not exist",
5025 opf_oid)));
5026
5027 ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
5028
5029 ReleaseSysCache(tuple);
5030
5031 return has_privs_of_role(roleid, ownerId);
5032}
5033
5034/*
5035 * Ownership check for a text search dictionary (specified by OID).
5036 */
5037bool
5038pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid)
5039{
5040 HeapTuple tuple;
5041 Oid ownerId;
5042
5043 /* Superusers bypass all permission checking. */
5044 if (superuser_arg(roleid))
5045 return true;
5046
5047 tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dict_oid));
5048 if (!HeapTupleIsValid(tuple))
5049 ereport(ERROR,
5050 (errcode(ERRCODE_UNDEFINED_OBJECT),
5051 errmsg("text search dictionary with OID %u does not exist",
5052 dict_oid)));
5053
5054 ownerId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictowner;
5055
5056 ReleaseSysCache(tuple);
5057
5058 return has_privs_of_role(roleid, ownerId);
5059}
5060
5061/*
5062 * Ownership check for a text search configuration (specified by OID).
5063 */
5064bool
5065pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid)
5066{
5067 HeapTuple tuple;
5068 Oid ownerId;
5069
5070 /* Superusers bypass all permission checking. */
5071 if (superuser_arg(roleid))
5072 return true;
5073
5074 tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfg_oid));
5075 if (!HeapTupleIsValid(tuple))
5076 ereport(ERROR,
5077 (errcode(ERRCODE_UNDEFINED_OBJECT),
5078 errmsg("text search configuration with OID %u does not exist",
5079 cfg_oid)));
5080
5081 ownerId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgowner;
5082
5083 ReleaseSysCache(tuple);
5084
5085 return has_privs_of_role(roleid, ownerId);
5086}
5087
5088/*
5089 * Ownership check for a foreign-data wrapper (specified by OID).
5090 */
5091bool
5092pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid)
5093{
5094 HeapTuple tuple;
5095 Oid ownerId;
5096
5097 /* Superusers bypass all permission checking. */
5098 if (superuser_arg(roleid))
5099 return true;
5100
5101 tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(srv_oid));
5102 if (!HeapTupleIsValid(tuple))
5103 ereport(ERROR,
5104 (errcode(ERRCODE_UNDEFINED_OBJECT),
5105 errmsg("foreign-data wrapper with OID %u does not exist",
5106 srv_oid)));
5107
5108 ownerId = ((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwowner;
5109
5110 ReleaseSysCache(tuple);
5111
5112 return has_privs_of_role(roleid, ownerId);
5113}
5114
5115/*
5116 * Ownership check for a foreign server (specified by OID).
5117 */
5118bool
5119pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
5120{
5121 HeapTuple tuple;
5122 Oid ownerId;
5123
5124 /* Superusers bypass all permission checking. */
5125 if (superuser_arg(roleid))
5126 return true;
5127
5128 tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
5129 if (!HeapTupleIsValid(tuple))
5130 ereport(ERROR,
5131 (errcode(ERRCODE_UNDEFINED_OBJECT),
5132 errmsg("foreign server with OID %u does not exist",
5133 srv_oid)));
5134
5135 ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner;
5136
5137 ReleaseSysCache(tuple);
5138
5139 return has_privs_of_role(roleid, ownerId);
5140}
5141
5142/*
5143 * Ownership check for an event trigger (specified by OID).
5144 */
5145bool
5146pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
5147{
5148 HeapTuple tuple;
5149 Oid ownerId;
5150
5151 /* Superusers bypass all permission checking. */
5152 if (superuser_arg(roleid))
5153 return true;
5154
5155 tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid));
5156 if (!HeapTupleIsValid(tuple))
5157 ereport(ERROR,
5158 (errcode(ERRCODE_UNDEFINED_OBJECT),
5159 errmsg("event trigger with OID %u does not exist",
5160 et_oid)));
5161
5162 ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
5163
5164 ReleaseSysCache(tuple);
5165
5166 return has_privs_of_role(roleid, ownerId);
5167}
5168
5169/*
5170 * Ownership check for a database (specified by OID).
5171 */
5172bool
5173pg_database_ownercheck(Oid db_oid, Oid roleid)
5174{
5175 HeapTuple tuple;
5176 Oid dba;
5177
5178 /* Superusers bypass all permission checking. */
5179 if (superuser_arg(roleid))
5180 return true;
5181
5182 tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
5183 if (!HeapTupleIsValid(tuple))
5184 ereport(ERROR,
5185 (errcode(ERRCODE_UNDEFINED_DATABASE),
5186 errmsg("database with OID %u does not exist", db_oid)));
5187
5188 dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
5189
5190 ReleaseSysCache(tuple);
5191
5192 return has_privs_of_role(roleid, dba);
5193}
5194
5195/*
5196 * Ownership check for a collation (specified by OID).
5197 */
5198bool
5199pg_collation_ownercheck(Oid coll_oid, Oid roleid)
5200{
5201 HeapTuple tuple;
5202 Oid ownerId;
5203
5204 /* Superusers bypass all permission checking. */
5205 if (superuser_arg(roleid))
5206 return true;
5207
5208 tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(coll_oid));
5209 if (!HeapTupleIsValid(tuple))
5210 ereport(ERROR,
5211 (errcode(ERRCODE_UNDEFINED_OBJECT),
5212 errmsg("collation with OID %u does not exist", coll_oid)));
5213
5214 ownerId = ((Form_pg_collation) GETSTRUCT(tuple))->collowner;
5215
5216 ReleaseSysCache(tuple);
5217
5218 return has_privs_of_role(roleid, ownerId);
5219}
5220
5221/*
5222 * Ownership check for a conversion (specified by OID).
5223 */
5224bool
5225pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
5226{
5227 HeapTuple tuple;
5228 Oid ownerId;
5229
5230 /* Superusers bypass all permission checking. */
5231 if (superuser_arg(roleid))
5232 return true;
5233
5234 tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conv_oid));
5235 if (!HeapTupleIsValid(tuple))
5236 ereport(ERROR,
5237 (errcode(ERRCODE_UNDEFINED_OBJECT),
5238 errmsg("conversion with OID %u does not exist", conv_oid)));
5239
5240 ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
5241
5242 ReleaseSysCache(tuple);
5243
5244 return has_privs_of_role(roleid, ownerId);
5245}
5246
5247/*
5248 * Ownership check for an extension (specified by OID).
5249 */
5250bool
5251pg_extension_ownercheck(Oid ext_oid, Oid roleid)
5252{
5253 Relation pg_extension;
5254 ScanKeyData entry[1];
5255 SysScanDesc scan;
5256 HeapTuple tuple;
5257 Oid ownerId;
5258
5259 /* Superusers bypass all permission checking. */
5260 if (superuser_arg(roleid))
5261 return true;
5262
5263 /* There's no syscache for pg_extension, so do it the hard way */
5264 pg_extension = table_open(ExtensionRelationId, AccessShareLock);
5265
5266 ScanKeyInit(&entry[0],
5267 Anum_pg_extension_oid,
5268 BTEqualStrategyNumber, F_OIDEQ,
5269 ObjectIdGetDatum(ext_oid));
5270
5271 scan = systable_beginscan(pg_extension,
5272 ExtensionOidIndexId, true,
5273 NULL, 1, entry);
5274
5275 tuple = systable_getnext(scan);
5276 if (!HeapTupleIsValid(tuple))
5277 ereport(ERROR,
5278 (errcode(ERRCODE_UNDEFINED_OBJECT),
5279 errmsg("extension with OID %u does not exist", ext_oid)));
5280
5281 ownerId = ((Form_pg_extension) GETSTRUCT(tuple))->extowner;
5282
5283 systable_endscan(scan);
5284 table_close(pg_extension, AccessShareLock);
5285
5286 return has_privs_of_role(roleid, ownerId);
5287}
5288
5289/*
5290 * Ownership check for a publication (specified by OID).
5291 */
5292bool
5293pg_publication_ownercheck(Oid pub_oid, Oid roleid)
5294{
5295 HeapTuple tuple;
5296 Oid ownerId;
5297
5298 /* Superusers bypass all permission checking. */
5299 if (superuser_arg(roleid))
5300 return true;
5301
5302 tuple = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pub_oid));
5303 if (!HeapTupleIsValid(tuple))
5304 ereport(ERROR,
5305 (errcode(ERRCODE_UNDEFINED_OBJECT),
5306 errmsg("publication with OID %u does not exist", pub_oid)));
5307
5308 ownerId = ((Form_pg_publication) GETSTRUCT(tuple))->pubowner;
5309
5310 ReleaseSysCache(tuple);
5311
5312 return has_privs_of_role(roleid, ownerId);
5313}
5314
5315/*
5316 * Ownership check for a subscription (specified by OID).
5317 */
5318bool
5319pg_subscription_ownercheck(Oid sub_oid, Oid roleid)
5320{
5321 HeapTuple tuple;
5322 Oid ownerId;
5323
5324 /* Superusers bypass all permission checking. */
5325 if (superuser_arg(roleid))
5326 return true;
5327
5328 tuple = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(sub_oid));
5329 if (!HeapTupleIsValid(tuple))
5330 ereport(ERROR,
5331 (errcode(ERRCODE_UNDEFINED_OBJECT),
5332 errmsg("subscription with OID %u does not exist", sub_oid)));
5333
5334 ownerId = ((Form_pg_subscription) GETSTRUCT(tuple))->subowner;
5335
5336 ReleaseSysCache(tuple);
5337
5338 return has_privs_of_role(roleid, ownerId);
5339}
5340
5341/*
5342 * Ownership check for a statistics object (specified by OID).
5343 */
5344bool
5345pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
5346{
5347 HeapTuple tuple;
5348 Oid ownerId;
5349
5350 /* Superusers bypass all permission checking. */
5351 if (superuser_arg(roleid))
5352 return true;
5353
5354 tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stat_oid));
5355 if (!HeapTupleIsValid(tuple))
5356 ereport(ERROR,
5357 (errcode(ERRCODE_UNDEFINED_OBJECT),
5358 errmsg("statistics object with OID %u does not exist",
5359 stat_oid)));
5360
5361 ownerId = ((Form_pg_statistic_ext) GETSTRUCT(tuple))->stxowner;
5362
5363 ReleaseSysCache(tuple);
5364
5365 return has_privs_of_role(roleid, ownerId);
5366}
5367
5368/*
5369 * Check whether specified role has CREATEROLE privilege (or is a superuser)
5370 *
5371 * Note: roles do not have owners per se; instead we use this test in
5372 * places where an ownership-like permissions test is needed for a role.
5373 * Be sure to apply it to the role trying to do the operation, not the
5374 * role being operated on! Also note that this generally should not be
5375 * considered enough privilege if the target role is a superuser.
5376 * (We don't handle that consideration here because we want to give a
5377 * separate error message for such cases, so the caller has to deal with it.)
5378 */
5379bool
5380has_createrole_privilege(Oid roleid)
5381{
5382 bool result = false;
5383 HeapTuple utup;
5384
5385 /* Superusers bypass all permission checking. */
5386 if (superuser_arg(roleid))
5387 return true;
5388
5389 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
5390 if (HeapTupleIsValid(utup))
5391 {
5392 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
5393 ReleaseSysCache(utup);
5394 }
5395 return result;
5396}
5397
5398bool
5399has_bypassrls_privilege(Oid roleid)
5400{
5401 bool result = false;
5402 HeapTuple utup;
5403
5404 /* Superusers bypass all permission checking. */
5405 if (superuser_arg(roleid))
5406 return true;
5407
5408 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
5409 if (HeapTupleIsValid(utup))
5410 {
5411 result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
5412 ReleaseSysCache(utup);
5413 }
5414 return result;
5415}
5416
5417/*
5418 * Fetch pg_default_acl entry for given role, namespace and object type
5419 * (object type must be given in pg_default_acl's encoding).
5420 * Returns NULL if no such entry.
5421 */
5422static Acl *
5423get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
5424{
5425 Acl *result = NULL;
5426 HeapTuple tuple;
5427
5428 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
5429 ObjectIdGetDatum(roleId),
5430 ObjectIdGetDatum(nsp_oid),
5431 CharGetDatum(objtype));
5432
5433 if (HeapTupleIsValid(tuple))
5434 {
5435 Datum aclDatum;
5436 bool isNull;
5437
5438 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
5439 Anum_pg_default_acl_defaclacl,
5440 &isNull);
5441 if (!isNull)
5442 result = DatumGetAclPCopy(aclDatum);
5443 ReleaseSysCache(tuple);
5444 }
5445
5446 return result;
5447}
5448
5449/*
5450 * Get default permissions for newly created object within given schema
5451 *
5452 * Returns NULL if built-in system defaults should be used.
5453 *
5454 * If the result is not NULL, caller must call recordDependencyOnNewAcl
5455 * once the OID of the new object is known.
5456 */
5457Acl *
5458get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
5459{
5460 Acl *result;
5461 Acl *glob_acl;
5462 Acl *schema_acl;
5463 Acl *def_acl;
5464 char defaclobjtype;
5465
5466 /*
5467 * Use NULL during bootstrap, since pg_default_acl probably isn't there
5468 * yet.
5469 */
5470 if (IsBootstrapProcessingMode())
5471 return NULL;
5472
5473 /* Check if object type is supported in pg_default_acl */
5474 switch (objtype)
5475 {
5476 case OBJECT_TABLE:
5477 defaclobjtype = DEFACLOBJ_RELATION;
5478 break;
5479
5480 case OBJECT_SEQUENCE:
5481 defaclobjtype = DEFACLOBJ_SEQUENCE;
5482 break;
5483
5484 case OBJECT_FUNCTION:
5485 defaclobjtype = DEFACLOBJ_FUNCTION;
5486 break;
5487
5488 case OBJECT_TYPE:
5489 defaclobjtype = DEFACLOBJ_TYPE;
5490 break;
5491
5492 case OBJECT_SCHEMA:
5493 defaclobjtype = DEFACLOBJ_NAMESPACE;
5494 break;
5495
5496 default:
5497 return NULL;
5498 }
5499
5500 /* Look up the relevant pg_default_acl entries */
5501 glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
5502 schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
5503
5504 /* Quick out if neither entry exists */
5505 if (glob_acl == NULL && schema_acl == NULL)
5506 return NULL;
5507
5508 /* We need to know the hard-wired default value, too */
5509 def_acl = acldefault(objtype, ownerId);
5510
5511 /* If there's no global entry, substitute the hard-wired default */
5512 if (glob_acl == NULL)
5513 glob_acl = def_acl;
5514
5515 /* Merge in any per-schema privileges */
5516 result = aclmerge(glob_acl, schema_acl, ownerId);
5517
5518 /*
5519 * For efficiency, we want to return NULL if the result equals default.
5520 * This requires sorting both arrays to get an accurate comparison.
5521 */
5522 aclitemsort(result);
5523 aclitemsort(def_acl);
5524 if (aclequal(result, def_acl))
5525 result = NULL;
5526
5527 return result;
5528}
5529
5530/*
5531 * Record dependencies on roles mentioned in a new object's ACL.
5532 */
5533void
5534recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
5535 Oid ownerId, Acl *acl)
5536{
5537 int nmembers;
5538 Oid *members;
5539
5540 /* Nothing to do if ACL is defaulted */
5541 if (acl == NULL)
5542 return;
5543
5544 /* Extract roles mentioned in ACL */
5545 nmembers = aclmembers(acl, &members);
5546
5547 /* Update the shared dependency ACL info */
5548 updateAclDependencies(classId, objectId, objsubId,
5549 ownerId,
5550 0, NULL,
5551 nmembers, members);
5552}
5553
5554/*
5555 * Record initial privileges for the top-level object passed in.
5556 *
5557 * For the object passed in, this will record its ACL (if any) and the ACLs of
5558 * any sub-objects (eg: columns) into pg_init_privs.
5559 *
5560 * Any new kinds of objects which have ACLs associated with them and can be
5561 * added to an extension should be added to the if-else tree below.
5562 */
5563void
5564recordExtObjInitPriv(Oid objoid, Oid classoid)
5565{
5566 /*
5567 * pg_class / pg_attribute
5568 *
5569 * If this is a relation then we need to see if there are any sub-objects
5570 * (eg: columns) for it and, if so, be sure to call
5571 * recordExtensionInitPrivWorker() for each one.
5572 */
5573 if (classoid == RelationRelationId)
5574 {
5575 Form_pg_class pg_class_tuple;
5576 Datum aclDatum;
5577 bool isNull;
5578 HeapTuple tuple;
5579
5580 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
5581 if (!HeapTupleIsValid(tuple))
5582 elog(ERROR, "cache lookup failed for relation %u", objoid);
5583 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
5584
5585 /* Indexes don't have permissions */
5586 if (pg_class_tuple->relkind == RELKIND_INDEX ||
5587 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
5588 return;
5589
5590 /* Composite types don't have permissions either */
5591 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
5592 return;
5593
5594 /*
5595 * If this isn't a sequence, index, or composite type then it's
5596 * possibly going to have columns associated with it that might have
5597 * ACLs.
5598 */
5599 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
5600 {
5601 AttrNumber curr_att;
5602 AttrNumber nattrs = pg_class_tuple->relnatts;
5603
5604 for (curr_att = 1; curr_att <= nattrs; curr_att++)
5605 {
5606 HeapTuple attTuple;
5607 Datum attaclDatum;
5608
5609 attTuple = SearchSysCache2(ATTNUM,
5610 ObjectIdGetDatum(objoid),
5611 Int16GetDatum(curr_att));
5612
5613 if (!HeapTupleIsValid(attTuple))
5614 continue;
5615
5616 /* ignore dropped columns */
5617 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
5618 {
5619 ReleaseSysCache(attTuple);
5620 continue;
5621 }
5622
5623 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
5624 Anum_pg_attribute_attacl,
5625 &isNull);
5626
5627 /* no need to do anything for a NULL ACL */
5628 if (isNull)
5629 {
5630 ReleaseSysCache(attTuple);
5631 continue;
5632 }
5633
5634 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
5635 DatumGetAclP(attaclDatum));
5636
5637 ReleaseSysCache(attTuple);
5638 }
5639 }
5640
5641 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
5642 &isNull);
5643
5644 /* Add the record, if any, for the top-level object */
5645 if (!isNull)
5646 recordExtensionInitPrivWorker(objoid, classoid, 0,
5647 DatumGetAclP(aclDatum));
5648
5649 ReleaseSysCache(tuple);
5650 }
5651 /* pg_foreign_data_wrapper */
5652 else if (classoid == ForeignDataWrapperRelationId)
5653 {
5654 Datum aclDatum;
5655 bool isNull;
5656 HeapTuple tuple;
5657
5658 tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
5659 ObjectIdGetDatum(objoid));
5660 if (!HeapTupleIsValid(tuple))
5661 elog(ERROR, "cache lookup failed for foreign data wrapper %u",
5662 objoid);
5663
5664 aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
5665 Anum_pg_foreign_data_wrapper_fdwacl,
5666 &isNull);
5667
5668 /* Add the record, if any, for the top-level object */
5669 if (!isNull)
5670 recordExtensionInitPrivWorker(objoid, classoid, 0,
5671 DatumGetAclP(aclDatum));
5672
5673 ReleaseSysCache(tuple);
5674 }
5675 /* pg_foreign_server */
5676 else if (classoid == ForeignServerRelationId)
5677 {
5678 Datum aclDatum;
5679 bool isNull;
5680 HeapTuple tuple;
5681
5682 tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(objoid));
5683 if (!HeapTupleIsValid(tuple))
5684 elog(ERROR, "cache lookup failed for foreign data wrapper %u",
5685 objoid);
5686
5687 aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
5688 Anum_pg_foreign_server_srvacl,
5689 &isNull);
5690
5691 /* Add the record, if any, for the top-level object */
5692 if (!isNull)
5693 recordExtensionInitPrivWorker(objoid, classoid, 0,
5694 DatumGetAclP(aclDatum));
5695
5696 ReleaseSysCache(tuple);
5697 }
5698 /* pg_language */
5699 else if (classoid == LanguageRelationId)
5700 {
5701 Datum aclDatum;
5702 bool isNull;
5703 HeapTuple tuple;
5704
5705 tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(objoid));
5706 if (!HeapTupleIsValid(tuple))
5707 elog(ERROR, "cache lookup failed for language %u", objoid);
5708
5709 aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
5710 &isNull);
5711
5712 /* Add the record, if any, for the top-level object */
5713 if (!isNull)
5714 recordExtensionInitPrivWorker(objoid, classoid, 0,
5715 DatumGetAclP(aclDatum));
5716
5717 ReleaseSysCache(tuple);
5718 }
5719 /* pg_largeobject_metadata */
5720 else if (classoid == LargeObjectMetadataRelationId)
5721 {
5722 Datum aclDatum;
5723 bool isNull;
5724 HeapTuple tuple;
5725 ScanKeyData entry[1];
5726 SysScanDesc scan;
5727 Relation relation;
5728
5729 relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
5730
5731 /* There's no syscache for pg_largeobject_metadata */
5732 ScanKeyInit(&entry[0],
5733 Anum_pg_largeobject_metadata_oid,
5734 BTEqualStrategyNumber, F_OIDEQ,
5735 ObjectIdGetDatum(objoid));
5736
5737 scan = systable_beginscan(relation,
5738 LargeObjectMetadataOidIndexId, true,
5739 NULL, 1, entry);
5740
5741 tuple = systable_getnext(scan);
5742 if (!HeapTupleIsValid(tuple))
5743 elog(ERROR, "could not find tuple for large object %u", objoid);
5744
5745 aclDatum = heap_getattr(tuple,
5746 Anum_pg_largeobject_metadata_lomacl,
5747 RelationGetDescr(relation), &isNull);
5748
5749 /* Add the record, if any, for the top-level object */
5750 if (!isNull)
5751 recordExtensionInitPrivWorker(objoid, classoid, 0,
5752 DatumGetAclP(aclDatum));
5753
5754 systable_endscan(scan);
5755 }
5756 /* pg_namespace */
5757 else if (classoid == NamespaceRelationId)
5758 {
5759 Datum aclDatum;
5760 bool isNull;
5761 HeapTuple tuple;
5762
5763 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(objoid));
5764 if (!HeapTupleIsValid(tuple))
5765 elog(ERROR, "cache lookup failed for function %u", objoid);
5766
5767 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple,
5768 Anum_pg_namespace_nspacl, &isNull);
5769
5770 /* Add the record, if any, for the top-level object */
5771 if (!isNull)
5772 recordExtensionInitPrivWorker(objoid, classoid, 0,
5773 DatumGetAclP(aclDatum));
5774
5775 ReleaseSysCache(tuple);
5776 }
5777 /* pg_proc */
5778 else if (classoid == ProcedureRelationId)
5779 {
5780 Datum aclDatum;
5781 bool isNull;
5782 HeapTuple tuple;
5783
5784 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(objoid));
5785 if (!HeapTupleIsValid(tuple))
5786 elog(ERROR, "cache lookup failed for function %u", objoid);
5787
5788 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
5789 &isNull);
5790
5791 /* Add the record, if any, for the top-level object */
5792 if (!isNull)
5793 recordExtensionInitPrivWorker(objoid, classoid, 0,
5794 DatumGetAclP(aclDatum));
5795
5796 ReleaseSysCache(tuple);
5797 }
5798 /* pg_type */
5799 else if (classoid == TypeRelationId)
5800 {
5801 Datum aclDatum;
5802 bool isNull;
5803 HeapTuple tuple;
5804
5805 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(objoid));
5806 if (!HeapTupleIsValid(tuple))
5807 elog(ERROR, "cache lookup failed for function %u", objoid);
5808
5809 aclDatum = SysCacheGetAttr(TYPEOID, tuple, Anum_pg_type_typacl,
5810 &isNull);
5811
5812 /* Add the record, if any, for the top-level object */
5813 if (!isNull)
5814 recordExtensionInitPrivWorker(objoid, classoid, 0,
5815 DatumGetAclP(aclDatum));
5816
5817 ReleaseSysCache(tuple);
5818 }
5819 else if (classoid == AccessMethodRelationId ||
5820 classoid == AggregateRelationId ||
5821 classoid == CastRelationId ||
5822 classoid == CollationRelationId ||
5823 classoid == ConversionRelationId ||
5824 classoid == EventTriggerRelationId ||
5825 classoid == OperatorRelationId ||
5826 classoid == OperatorClassRelationId ||
5827 classoid == OperatorFamilyRelationId ||
5828 classoid == NamespaceRelationId ||
5829 classoid == TSConfigRelationId ||
5830 classoid == TSDictionaryRelationId ||
5831 classoid == TSParserRelationId ||
5832 classoid == TSTemplateRelationId ||
5833 classoid == TransformRelationId
5834 )
5835 {
5836 /* no ACL for these object types, so do nothing. */
5837 }
5838
5839 /*
5840 * complain if we are given a class OID for a class that extensions don't
5841 * support or that we don't recognize.
5842 */
5843 else
5844 {
5845 elog(ERROR, "unrecognized or unsupported class OID: %u", classoid);
5846 }
5847}
5848
5849/*
5850 * For the object passed in, remove its ACL and the ACLs of any object subIds
5851 * from pg_init_privs (via recordExtensionInitPrivWorker()).
5852 */
5853void
5854removeExtObjInitPriv(Oid objoid, Oid classoid)
5855{
5856 /*
5857 * If this is a relation then we need to see if there are any sub-objects
5858 * (eg: columns) for it and, if so, be sure to call
5859 * recordExtensionInitPrivWorker() for each one.
5860 */
5861 if (classoid == RelationRelationId)
5862 {
5863 Form_pg_class pg_class_tuple;
5864 HeapTuple tuple;
5865
5866 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
5867 if (!HeapTupleIsValid(tuple))
5868 elog(ERROR, "cache lookup failed for relation %u", objoid);
5869 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
5870
5871 /* Indexes don't have permissions */
5872 if (pg_class_tuple->relkind == RELKIND_INDEX ||
5873 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
5874 return;
5875
5876 /* Composite types don't have permissions either */
5877 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
5878 return;
5879
5880 /*
5881 * If this isn't a sequence, index, or composite type then it's
5882 * possibly going to have columns associated with it that might have
5883 * ACLs.
5884 */
5885 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
5886 {
5887 AttrNumber curr_att;
5888 AttrNumber nattrs = pg_class_tuple->relnatts;
5889
5890 for (curr_att = 1; curr_att <= nattrs; curr_att++)
5891 {
5892 HeapTuple attTuple;
5893
5894 attTuple = SearchSysCache2(ATTNUM,
5895 ObjectIdGetDatum(objoid),
5896 Int16GetDatum(curr_att));
5897
5898 if (!HeapTupleIsValid(attTuple))
5899 continue;
5900
5901 /* when removing, remove all entries, even dropped columns */
5902
5903 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
5904
5905 ReleaseSysCache(attTuple);
5906 }
5907 }
5908
5909 ReleaseSysCache(tuple);
5910 }
5911
5912 /* Remove the record, if any, for the top-level object */
5913 recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
5914}
5915
5916/*
5917 * Record initial ACL for an extension object
5918 *
5919 * Can be called at any time, we check if 'creating_extension' is set and, if
5920 * not, exit immediately.
5921 *
5922 * Pass in the object OID, the OID of the class (the OID of the table which
5923 * the object is defined in) and the 'sub' id of the object (objsubid), if
5924 * any. If there is no 'sub' id (they are currently only used for columns of
5925 * tables) then pass in '0'. Finally, pass in the complete ACL to store.
5926 *
5927 * If an ACL already exists for this object/sub-object then we will replace
5928 * it with what is passed in.
5929 *
5930 * Passing in NULL for 'new_acl' will result in the entry for the object being
5931 * removed, if one is found.
5932 */
5933static void
5934recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
5935{
5936 /*
5937 * Generally, we only record the initial privileges when an extension is
5938 * being created, but because we don't actually use CREATE EXTENSION
5939 * during binary upgrades with pg_upgrade, there is a variable to let us
5940 * know that the GRANT and REVOKE statements being issued, while this
5941 * variable is true, are for the initial privileges of the extension
5942 * object and therefore we need to record them.
5943 */
5944 if (!creating_extension && !binary_upgrade_record_init_privs)
5945 return;
5946
5947 recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
5948}
5949
5950/*
5951 * Record initial ACL for an extension object, worker.
5952 *
5953 * This will perform a wholesale replacement of the entire ACL for the object
5954 * passed in, therefore be sure to pass in the complete new ACL to use.
5955 *
5956 * Generally speaking, do *not* use this function directly but instead use
5957 * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
5958 * This function does *not* check if 'creating_extension' is set as it is also
5959 * used when an object is added to or removed from an extension via ALTER
5960 * EXTENSION ... ADD/DROP.
5961 */
5962static void
5963recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
5964{
5965 Relation relation;
5966 ScanKeyData key[3];
5967 SysScanDesc scan;
5968 HeapTuple tuple;
5969 HeapTuple oldtuple;
5970
5971 relation = table_open(InitPrivsRelationId, RowExclusiveLock);
5972
5973 ScanKeyInit(&key[0],
5974 Anum_pg_init_privs_objoid,
5975 BTEqualStrategyNumber, F_OIDEQ,
5976 ObjectIdGetDatum(objoid));
5977 ScanKeyInit(&key[1],
5978 Anum_pg_init_privs_classoid,
5979 BTEqualStrategyNumber, F_OIDEQ,
5980 ObjectIdGetDatum(classoid));
5981 ScanKeyInit(&key[2],
5982 Anum_pg_init_privs_objsubid,
5983 BTEqualStrategyNumber, F_INT4EQ,
5984 Int32GetDatum(objsubid));
5985
5986 scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
5987 NULL, 3, key);
5988
5989 /* There should exist only one entry or none. */
5990 oldtuple = systable_getnext(scan);
5991
5992 /* If we find an entry, update it with the latest ACL. */
5993 if (HeapTupleIsValid(oldtuple))
5994 {
5995 Datum values[Natts_pg_init_privs];
5996 bool nulls[Natts_pg_init_privs];
5997 bool replace[Natts_pg_init_privs];
5998
5999 /* If we have a new ACL to set, then update the row with it. */
6000 if (new_acl)
6001 {
6002 MemSet(values, 0, sizeof(values));
6003 MemSet(nulls, false, sizeof(nulls));
6004 MemSet(replace, false, sizeof(replace));
6005
6006 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
6007 replace[Anum_pg_init_privs_initprivs - 1] = true;
6008
6009 oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
6010 values, nulls, replace);
6011
6012 CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
6013 }
6014 else
6015 {
6016 /* new_acl is NULL, so delete the entry we found. */
6017 CatalogTupleDelete(relation, &oldtuple->t_self);
6018 }
6019 }
6020 else
6021 {
6022 Datum values[Natts_pg_init_privs];
6023 bool nulls[Natts_pg_init_privs];
6024
6025 /*
6026 * Only add a new entry if the new ACL is non-NULL.
6027 *
6028 * If we are passed in a NULL ACL and no entry exists, we can just
6029 * fall through and do nothing.
6030 */
6031 if (new_acl)
6032 {
6033 /* No entry found, so add it. */
6034 MemSet(nulls, false, sizeof(nulls));
6035
6036 values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
6037 values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
6038 values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
6039
6040 /* This function only handles initial privileges of extensions */
6041 values[Anum_pg_init_privs_privtype - 1] =
6042 CharGetDatum(INITPRIVS_EXTENSION);
6043
6044 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
6045
6046 tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
6047
6048 CatalogTupleInsert(relation, tuple);
6049 }
6050 }
6051
6052 systable_endscan(scan);
6053
6054 /* prevent error when processing objects multiple times */
6055 CommandCounterIncrement();
6056
6057 table_close(relation, RowExclusiveLock);
6058}
6059