Fix multiranges to behave more like dependent types.
[pgsql.git] / src / backend / catalog / aclchk.c
blob1e44a71f61c5007611e2457dd06f1e91e9da4fc9
1 /*-------------------------------------------------------------------------
3 * aclchk.c
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/catalog/aclchk.c
13 * NOTES
14 * See acl.h.
16 * The xxx_aclmask() functions in this file are wrappers around
17 * acl.c's aclmask() function; see that for basic usage information.
18 * The wrapper functions add object-type-specific lookup capability.
19 * Generally, they will throw error if the object doesn't exist.
21 * The xxx_aclmask_ext() functions add the ability to not throw
22 * error if the object doesn't exist. If their "is_missing" argument
23 * isn't NULL, then when the object isn't found they will set
24 * *is_missing = true and return zero (no privileges) instead of
25 * throwing an error. Caller must initialize *is_missing = false.
27 * The xxx_aclcheck() functions are simplified wrappers around the
28 * corresponding xxx_aclmask() functions, simply returning ACLCHECK_OK
29 * if any of the privileges specified in "mode" are held, and otherwise
30 * a suitable error code (in practice, always ACLCHECK_NO_PRIV).
31 * Again, they will throw error if the object doesn't exist.
33 * The xxx_aclcheck_ext() functions add the ability to not throw
34 * error if the object doesn't exist. Their "is_missing" argument
35 * works similarly to the xxx_aclmask_ext() functions.
37 *-------------------------------------------------------------------------
39 #include "postgres.h"
41 #include "access/genam.h"
42 #include "access/heapam.h"
43 #include "access/htup_details.h"
44 #include "access/sysattr.h"
45 #include "access/tableam.h"
46 #include "access/xact.h"
47 #include "catalog/binary_upgrade.h"
48 #include "catalog/catalog.h"
49 #include "catalog/dependency.h"
50 #include "catalog/indexing.h"
51 #include "catalog/objectaccess.h"
52 #include "catalog/pg_aggregate.h"
53 #include "catalog/pg_am.h"
54 #include "catalog/pg_authid.h"
55 #include "catalog/pg_cast.h"
56 #include "catalog/pg_class.h"
57 #include "catalog/pg_collation.h"
58 #include "catalog/pg_conversion.h"
59 #include "catalog/pg_database.h"
60 #include "catalog/pg_default_acl.h"
61 #include "catalog/pg_event_trigger.h"
62 #include "catalog/pg_extension.h"
63 #include "catalog/pg_foreign_data_wrapper.h"
64 #include "catalog/pg_foreign_server.h"
65 #include "catalog/pg_init_privs.h"
66 #include "catalog/pg_language.h"
67 #include "catalog/pg_largeobject.h"
68 #include "catalog/pg_largeobject_metadata.h"
69 #include "catalog/pg_namespace.h"
70 #include "catalog/pg_opclass.h"
71 #include "catalog/pg_operator.h"
72 #include "catalog/pg_opfamily.h"
73 #include "catalog/pg_parameter_acl.h"
74 #include "catalog/pg_proc.h"
75 #include "catalog/pg_statistic_ext.h"
76 #include "catalog/pg_subscription.h"
77 #include "catalog/pg_tablespace.h"
78 #include "catalog/pg_transform.h"
79 #include "catalog/pg_ts_config.h"
80 #include "catalog/pg_ts_dict.h"
81 #include "catalog/pg_ts_parser.h"
82 #include "catalog/pg_ts_template.h"
83 #include "catalog/pg_type.h"
84 #include "commands/dbcommands.h"
85 #include "commands/defrem.h"
86 #include "commands/event_trigger.h"
87 #include "commands/extension.h"
88 #include "commands/proclang.h"
89 #include "commands/tablespace.h"
90 #include "foreign/foreign.h"
91 #include "miscadmin.h"
92 #include "nodes/makefuncs.h"
93 #include "parser/parse_func.h"
94 #include "parser/parse_type.h"
95 #include "utils/acl.h"
96 #include "utils/aclchk_internal.h"
97 #include "utils/builtins.h"
98 #include "utils/fmgroids.h"
99 #include "utils/guc.h"
100 #include "utils/lsyscache.h"
101 #include "utils/rel.h"
102 #include "utils/syscache.h"
105 * Internal format used by ALTER DEFAULT PRIVILEGES.
107 typedef struct
109 Oid roleid; /* owning role */
110 Oid nspid; /* namespace, or InvalidOid if none */
111 /* remaining fields are same as in InternalGrant: */
112 bool is_grant;
113 ObjectType objtype;
114 bool all_privs;
115 AclMode privileges;
116 List *grantees;
117 bool grant_option;
118 DropBehavior behavior;
119 } InternalDefaultACL;
122 * When performing a binary-upgrade, pg_dump will call a function to set
123 * this variable to let us know that we need to populate the pg_init_privs
124 * table for the GRANT/REVOKE commands while this variable is set to true.
126 bool binary_upgrade_record_init_privs = false;
128 static void ExecGrantStmt_oids(InternalGrant *istmt);
129 static void ExecGrant_Relation(InternalGrant *istmt);
130 static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
131 void (*object_check) (InternalGrant *istmt, HeapTuple tuple));
132 static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple);
133 static void ExecGrant_Largeobject(InternalGrant *istmt);
134 static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple);
135 static void ExecGrant_Parameter(InternalGrant *istmt);
137 static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
138 static void SetDefaultACL(InternalDefaultACL *iacls);
140 static List *objectNamesToOids(ObjectType objtype, List *objnames,
141 bool is_grant);
142 static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
143 static List *getRelationsInNamespace(Oid namespaceId, char relkind);
144 static void expand_col_privileges(List *colnames, Oid table_oid,
145 AclMode this_privileges,
146 AclMode *col_privileges,
147 int num_col_privileges);
148 static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
149 AclMode this_privileges,
150 AclMode *col_privileges,
151 int num_col_privileges);
152 static AclMode string_to_privilege(const char *privname);
153 static const char *privilege_to_string(AclMode privilege);
154 static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
155 bool all_privs, AclMode privileges,
156 Oid objectId, Oid grantorId,
157 ObjectType objtype, const char *objname,
158 AttrNumber att_number, const char *colname);
159 static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum,
160 Oid roleid, AclMode mask, AclMaskHow how);
161 static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid,
162 AclMode mask, AclMaskHow how);
163 static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
164 AclMode mask, AclMaskHow how,
165 bool *is_missing);
166 static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum,
167 Oid roleid, AclMode mask, AclMaskHow how);
168 static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum,
169 Oid roleid, AclMode mask,
170 AclMaskHow how, bool *is_missing);
171 static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid,
172 AclMode mask, AclMaskHow how,
173 bool *is_missing);
174 static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
175 AclMode mask, AclMaskHow how);
176 static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
177 AclMode mask, AclMaskHow how, Snapshot snapshot);
178 static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
179 AclMode mask, AclMaskHow how,
180 bool *is_missing);
181 static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid,
182 AclMode mask, AclMaskHow how,
183 bool *is_missing);
184 static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
185 Acl *new_acl);
186 static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
187 Acl *new_acl);
191 * If is_grant is true, adds the given privileges for the list of
192 * grantees to the existing old_acl. If is_grant is false, the
193 * privileges for the given grantees are removed from old_acl.
195 * NB: the original old_acl is pfree'd.
197 static Acl *
198 merge_acl_with_grant(Acl *old_acl, bool is_grant,
199 bool grant_option, DropBehavior behavior,
200 List *grantees, AclMode privileges,
201 Oid grantorId, Oid ownerId)
203 unsigned modechg;
204 ListCell *j;
205 Acl *new_acl;
207 modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
209 new_acl = old_acl;
211 foreach(j, grantees)
213 AclItem aclitem;
214 Acl *newer_acl;
216 aclitem.ai_grantee = lfirst_oid(j);
219 * Grant options can only be granted to individual roles, not PUBLIC.
220 * The reason is that if a user would re-grant a privilege that he
221 * held through PUBLIC, and later the user is removed, the situation
222 * is impossible to clean up.
224 if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
225 ereport(ERROR,
226 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
227 errmsg("grant options can only be granted to roles")));
229 aclitem.ai_grantor = grantorId;
232 * The asymmetry in the conditions here comes from the spec. In
233 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
234 * to grant both the basic privilege and its grant option. But in
235 * REVOKE, plain revoke revokes both the basic privilege and its grant
236 * option, while REVOKE GRANT OPTION revokes only the option.
238 ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
239 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
240 (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
242 newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
244 /* avoid memory leak when there are many grantees */
245 pfree(new_acl);
246 new_acl = newer_acl;
249 return new_acl;
253 * Restrict the privileges to what we can actually grant, and emit
254 * the standards-mandated warning and error messages.
256 static AclMode
257 restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
258 AclMode privileges, Oid objectId, Oid grantorId,
259 ObjectType objtype, const char *objname,
260 AttrNumber att_number, const char *colname)
262 AclMode this_privileges;
263 AclMode whole_mask;
265 switch (objtype)
267 case OBJECT_COLUMN:
268 whole_mask = ACL_ALL_RIGHTS_COLUMN;
269 break;
270 case OBJECT_TABLE:
271 whole_mask = ACL_ALL_RIGHTS_RELATION;
272 break;
273 case OBJECT_SEQUENCE:
274 whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
275 break;
276 case OBJECT_DATABASE:
277 whole_mask = ACL_ALL_RIGHTS_DATABASE;
278 break;
279 case OBJECT_FUNCTION:
280 whole_mask = ACL_ALL_RIGHTS_FUNCTION;
281 break;
282 case OBJECT_LANGUAGE:
283 whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
284 break;
285 case OBJECT_LARGEOBJECT:
286 whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
287 break;
288 case OBJECT_SCHEMA:
289 whole_mask = ACL_ALL_RIGHTS_SCHEMA;
290 break;
291 case OBJECT_TABLESPACE:
292 whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
293 break;
294 case OBJECT_FDW:
295 whole_mask = ACL_ALL_RIGHTS_FDW;
296 break;
297 case OBJECT_FOREIGN_SERVER:
298 whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
299 break;
300 case OBJECT_EVENT_TRIGGER:
301 elog(ERROR, "grantable rights not supported for event triggers");
302 /* not reached, but keep compiler quiet */
303 return ACL_NO_RIGHTS;
304 case OBJECT_TYPE:
305 whole_mask = ACL_ALL_RIGHTS_TYPE;
306 break;
307 case OBJECT_PARAMETER_ACL:
308 whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
309 break;
310 default:
311 elog(ERROR, "unrecognized object type: %d", objtype);
312 /* not reached, but keep compiler quiet */
313 return ACL_NO_RIGHTS;
317 * If we found no grant options, consider whether to issue a hard error.
318 * Per spec, having any privilege at all on the object will get you by
319 * here.
321 if (avail_goptions == ACL_NO_RIGHTS)
323 if (pg_aclmask(objtype, objectId, att_number, grantorId,
324 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
325 ACLMASK_ANY) == ACL_NO_RIGHTS)
327 if (objtype == OBJECT_COLUMN && colname)
328 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
329 else
330 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
335 * Restrict the operation to what we can actually grant or revoke, and
336 * issue a warning if appropriate. (For REVOKE this isn't quite what the
337 * spec says to do: the spec seems to want a warning only if no privilege
338 * bits actually change in the ACL. In practice that behavior seems much
339 * too noisy, as well as inconsistent with the GRANT case.)
341 this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
342 if (is_grant)
344 if (this_privileges == 0)
346 if (objtype == OBJECT_COLUMN && colname)
347 ereport(WARNING,
348 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
349 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
350 colname, objname)));
351 else
352 ereport(WARNING,
353 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
354 errmsg("no privileges were granted for \"%s\"",
355 objname)));
357 else if (!all_privs && this_privileges != privileges)
359 if (objtype == OBJECT_COLUMN && colname)
360 ereport(WARNING,
361 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
362 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
363 colname, objname)));
364 else
365 ereport(WARNING,
366 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
367 errmsg("not all privileges were granted for \"%s\"",
368 objname)));
371 else
373 if (this_privileges == 0)
375 if (objtype == OBJECT_COLUMN && colname)
376 ereport(WARNING,
377 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
378 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
379 colname, objname)));
380 else
381 ereport(WARNING,
382 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
383 errmsg("no privileges could be revoked for \"%s\"",
384 objname)));
386 else if (!all_privs && this_privileges != privileges)
388 if (objtype == OBJECT_COLUMN && colname)
389 ereport(WARNING,
390 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
391 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
392 colname, objname)));
393 else
394 ereport(WARNING,
395 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
396 errmsg("not all privileges could be revoked for \"%s\"",
397 objname)));
401 return this_privileges;
405 * Called to execute the utility commands GRANT and REVOKE
407 void
408 ExecuteGrantStmt(GrantStmt *stmt)
410 InternalGrant istmt;
411 ListCell *cell;
412 const char *errormsg;
413 AclMode all_privileges;
415 if (stmt->grantor)
417 Oid grantor;
419 grantor = get_rolespec_oid(stmt->grantor, false);
422 * Currently, this clause is only for SQL compatibility, not very
423 * interesting otherwise.
425 if (grantor != GetUserId())
426 ereport(ERROR,
427 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
428 errmsg("grantor must be current user")));
432 * Turn the regular GrantStmt into the InternalGrant form.
434 istmt.is_grant = stmt->is_grant;
435 istmt.objtype = stmt->objtype;
437 /* Collect the OIDs of the target objects */
438 switch (stmt->targtype)
440 case ACL_TARGET_OBJECT:
441 istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
442 stmt->is_grant);
443 break;
444 case ACL_TARGET_ALL_IN_SCHEMA:
445 istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
446 break;
447 /* ACL_TARGET_DEFAULTS should not be seen here */
448 default:
449 elog(ERROR, "unrecognized GrantStmt.targtype: %d",
450 (int) stmt->targtype);
453 /* all_privs to be filled below */
454 /* privileges to be filled below */
455 istmt.col_privs = NIL; /* may get filled below */
456 istmt.grantees = NIL; /* filled below */
457 istmt.grant_option = stmt->grant_option;
458 istmt.behavior = stmt->behavior;
461 * Convert the RoleSpec list into an Oid list. Note that at this point we
462 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
463 * there shouldn't be any additional work needed to support this case.
465 foreach(cell, stmt->grantees)
467 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
468 Oid grantee_uid;
470 switch (grantee->roletype)
472 case ROLESPEC_PUBLIC:
473 grantee_uid = ACL_ID_PUBLIC;
474 break;
475 default:
476 grantee_uid = get_rolespec_oid(grantee, false);
477 break;
479 istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
483 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
484 * bitmask. Note: objtype can't be OBJECT_COLUMN.
486 switch (stmt->objtype)
488 case OBJECT_TABLE:
491 * Because this might be a sequence, we test both relation and
492 * sequence bits, and later do a more limited test when we know
493 * the object type.
495 all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
496 errormsg = gettext_noop("invalid privilege type %s for relation");
497 break;
498 case OBJECT_SEQUENCE:
499 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
500 errormsg = gettext_noop("invalid privilege type %s for sequence");
501 break;
502 case OBJECT_DATABASE:
503 all_privileges = ACL_ALL_RIGHTS_DATABASE;
504 errormsg = gettext_noop("invalid privilege type %s for database");
505 break;
506 case OBJECT_DOMAIN:
507 all_privileges = ACL_ALL_RIGHTS_TYPE;
508 errormsg = gettext_noop("invalid privilege type %s for domain");
509 break;
510 case OBJECT_FUNCTION:
511 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
512 errormsg = gettext_noop("invalid privilege type %s for function");
513 break;
514 case OBJECT_LANGUAGE:
515 all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
516 errormsg = gettext_noop("invalid privilege type %s for language");
517 break;
518 case OBJECT_LARGEOBJECT:
519 all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
520 errormsg = gettext_noop("invalid privilege type %s for large object");
521 break;
522 case OBJECT_SCHEMA:
523 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
524 errormsg = gettext_noop("invalid privilege type %s for schema");
525 break;
526 case OBJECT_PROCEDURE:
527 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
528 errormsg = gettext_noop("invalid privilege type %s for procedure");
529 break;
530 case OBJECT_ROUTINE:
531 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
532 errormsg = gettext_noop("invalid privilege type %s for routine");
533 break;
534 case OBJECT_TABLESPACE:
535 all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
536 errormsg = gettext_noop("invalid privilege type %s for tablespace");
537 break;
538 case OBJECT_TYPE:
539 all_privileges = ACL_ALL_RIGHTS_TYPE;
540 errormsg = gettext_noop("invalid privilege type %s for type");
541 break;
542 case OBJECT_FDW:
543 all_privileges = ACL_ALL_RIGHTS_FDW;
544 errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
545 break;
546 case OBJECT_FOREIGN_SERVER:
547 all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
548 errormsg = gettext_noop("invalid privilege type %s for foreign server");
549 break;
550 case OBJECT_PARAMETER_ACL:
551 all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
552 errormsg = gettext_noop("invalid privilege type %s for parameter");
553 break;
554 default:
555 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
556 (int) stmt->objtype);
557 /* keep compiler quiet */
558 all_privileges = ACL_NO_RIGHTS;
559 errormsg = NULL;
562 if (stmt->privileges == NIL)
564 istmt.all_privs = true;
567 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
568 * depending on the object type
570 istmt.privileges = ACL_NO_RIGHTS;
572 else
574 istmt.all_privs = false;
575 istmt.privileges = ACL_NO_RIGHTS;
577 foreach(cell, stmt->privileges)
579 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
580 AclMode priv;
583 * If it's a column-level specification, we just set it aside in
584 * col_privs for the moment; but insist it's for a relation.
586 if (privnode->cols)
588 if (stmt->objtype != OBJECT_TABLE)
589 ereport(ERROR,
590 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
591 errmsg("column privileges are only valid for relations")));
592 istmt.col_privs = lappend(istmt.col_privs, privnode);
593 continue;
596 if (privnode->priv_name == NULL) /* parser mistake? */
597 elog(ERROR, "AccessPriv node must specify privilege or columns");
598 priv = string_to_privilege(privnode->priv_name);
600 if (priv & ~((AclMode) all_privileges))
601 ereport(ERROR,
602 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
603 errmsg(errormsg, privilege_to_string(priv))));
605 istmt.privileges |= priv;
609 ExecGrantStmt_oids(&istmt);
613 * ExecGrantStmt_oids
615 * Internal entry point for granting and revoking privileges.
617 static void
618 ExecGrantStmt_oids(InternalGrant *istmt)
620 switch (istmt->objtype)
622 case OBJECT_TABLE:
623 case OBJECT_SEQUENCE:
624 ExecGrant_Relation(istmt);
625 break;
626 case OBJECT_DATABASE:
627 ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
628 break;
629 case OBJECT_DOMAIN:
630 case OBJECT_TYPE:
631 ExecGrant_common(istmt, TypeRelationId, ACL_ALL_RIGHTS_TYPE, ExecGrant_Type_check);
632 break;
633 case OBJECT_FDW:
634 ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
635 break;
636 case OBJECT_FOREIGN_SERVER:
637 ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
638 break;
639 case OBJECT_FUNCTION:
640 case OBJECT_PROCEDURE:
641 case OBJECT_ROUTINE:
642 ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
643 break;
644 case OBJECT_LANGUAGE:
645 ExecGrant_common(istmt, LanguageRelationId, ACL_ALL_RIGHTS_LANGUAGE, ExecGrant_Language_check);
646 break;
647 case OBJECT_LARGEOBJECT:
648 ExecGrant_Largeobject(istmt);
649 break;
650 case OBJECT_SCHEMA:
651 ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
652 break;
653 case OBJECT_TABLESPACE:
654 ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
655 break;
656 case OBJECT_PARAMETER_ACL:
657 ExecGrant_Parameter(istmt);
658 break;
659 default:
660 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
661 (int) istmt->objtype);
665 * Pass the info to event triggers about the just-executed GRANT. Note
666 * that we prefer to do it after actually executing it, because that gives
667 * the functions a chance to adjust the istmt with privileges actually
668 * granted.
670 if (EventTriggerSupportsObjectType(istmt->objtype))
671 EventTriggerCollectGrant(istmt);
675 * objectNamesToOids
677 * Turn a list of object names of a given type into an Oid list.
679 * XXX: This function doesn't take any sort of locks on the objects whose
680 * names it looks up. In the face of concurrent DDL, we might easily latch
681 * onto an old version of an object, causing the GRANT or REVOKE statement
682 * to fail.
684 static List *
685 objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
687 List *objects = NIL;
688 ListCell *cell;
690 Assert(objnames != NIL);
692 switch (objtype)
694 case OBJECT_TABLE:
695 case OBJECT_SEQUENCE:
696 foreach(cell, objnames)
698 RangeVar *relvar = (RangeVar *) lfirst(cell);
699 Oid relOid;
701 relOid = RangeVarGetRelid(relvar, NoLock, false);
702 objects = lappend_oid(objects, relOid);
704 break;
705 case OBJECT_DATABASE:
706 foreach(cell, objnames)
708 char *dbname = strVal(lfirst(cell));
709 Oid dbid;
711 dbid = get_database_oid(dbname, false);
712 objects = lappend_oid(objects, dbid);
714 break;
715 case OBJECT_DOMAIN:
716 case OBJECT_TYPE:
717 foreach(cell, objnames)
719 List *typname = (List *) lfirst(cell);
720 Oid oid;
722 oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
723 objects = lappend_oid(objects, oid);
725 break;
726 case OBJECT_FUNCTION:
727 foreach(cell, objnames)
729 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
730 Oid funcid;
732 funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
733 objects = lappend_oid(objects, funcid);
735 break;
736 case OBJECT_LANGUAGE:
737 foreach(cell, objnames)
739 char *langname = strVal(lfirst(cell));
740 Oid oid;
742 oid = get_language_oid(langname, false);
743 objects = lappend_oid(objects, oid);
745 break;
746 case OBJECT_LARGEOBJECT:
747 foreach(cell, objnames)
749 Oid lobjOid = oidparse(lfirst(cell));
751 if (!LargeObjectExists(lobjOid))
752 ereport(ERROR,
753 (errcode(ERRCODE_UNDEFINED_OBJECT),
754 errmsg("large object %u does not exist",
755 lobjOid)));
757 objects = lappend_oid(objects, lobjOid);
759 break;
760 case OBJECT_SCHEMA:
761 foreach(cell, objnames)
763 char *nspname = strVal(lfirst(cell));
764 Oid oid;
766 oid = get_namespace_oid(nspname, false);
767 objects = lappend_oid(objects, oid);
769 break;
770 case OBJECT_PROCEDURE:
771 foreach(cell, objnames)
773 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
774 Oid procid;
776 procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
777 objects = lappend_oid(objects, procid);
779 break;
780 case OBJECT_ROUTINE:
781 foreach(cell, objnames)
783 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
784 Oid routid;
786 routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
787 objects = lappend_oid(objects, routid);
789 break;
790 case OBJECT_TABLESPACE:
791 foreach(cell, objnames)
793 char *spcname = strVal(lfirst(cell));
794 Oid spcoid;
796 spcoid = get_tablespace_oid(spcname, false);
797 objects = lappend_oid(objects, spcoid);
799 break;
800 case OBJECT_FDW:
801 foreach(cell, objnames)
803 char *fdwname = strVal(lfirst(cell));
804 Oid fdwid = get_foreign_data_wrapper_oid(fdwname, false);
806 objects = lappend_oid(objects, fdwid);
808 break;
809 case OBJECT_FOREIGN_SERVER:
810 foreach(cell, objnames)
812 char *srvname = strVal(lfirst(cell));
813 Oid srvid = get_foreign_server_oid(srvname, false);
815 objects = lappend_oid(objects, srvid);
817 break;
818 case OBJECT_PARAMETER_ACL:
819 foreach(cell, objnames)
822 * In this code we represent a GUC by the OID of its entry in
823 * pg_parameter_acl, which we have to manufacture here if it
824 * doesn't exist yet. (That's a hack for sure, but it avoids
825 * messing with all the GRANT/REVOKE infrastructure that
826 * expects to use OIDs for object identities.) However, if
827 * this is a REVOKE, we can instead just ignore any GUCs that
828 * don't have such an entry, as they must not have any
829 * privileges needing removal.
831 char *parameter = strVal(lfirst(cell));
832 Oid parameterId = ParameterAclLookup(parameter, true);
834 if (!OidIsValid(parameterId) && is_grant)
836 parameterId = ParameterAclCreate(parameter);
839 * Prevent error when processing duplicate objects, and
840 * make this new entry visible so that ExecGrant_Parameter
841 * can update it.
843 CommandCounterIncrement();
845 if (OidIsValid(parameterId))
846 objects = lappend_oid(objects, parameterId);
848 break;
849 default:
850 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
851 (int) objtype);
854 return objects;
858 * objectsInSchemaToOids
860 * Find all objects of a given type in specified schemas, and make a list
861 * of their Oids. We check USAGE privilege on the schemas, but there is
862 * no privilege checking on the individual objects here.
864 static List *
865 objectsInSchemaToOids(ObjectType objtype, List *nspnames)
867 List *objects = NIL;
868 ListCell *cell;
870 foreach(cell, nspnames)
872 char *nspname = strVal(lfirst(cell));
873 Oid namespaceId;
874 List *objs;
876 namespaceId = LookupExplicitNamespace(nspname, false);
878 switch (objtype)
880 case OBJECT_TABLE:
881 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
882 objects = list_concat(objects, objs);
883 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
884 objects = list_concat(objects, objs);
885 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
886 objects = list_concat(objects, objs);
887 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
888 objects = list_concat(objects, objs);
889 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
890 objects = list_concat(objects, objs);
891 break;
892 case OBJECT_SEQUENCE:
893 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
894 objects = list_concat(objects, objs);
895 break;
896 case OBJECT_FUNCTION:
897 case OBJECT_PROCEDURE:
898 case OBJECT_ROUTINE:
900 ScanKeyData key[2];
901 int keycount;
902 Relation rel;
903 TableScanDesc scan;
904 HeapTuple tuple;
906 keycount = 0;
907 ScanKeyInit(&key[keycount++],
908 Anum_pg_proc_pronamespace,
909 BTEqualStrategyNumber, F_OIDEQ,
910 ObjectIdGetDatum(namespaceId));
912 if (objtype == OBJECT_FUNCTION)
913 /* includes aggregates and window functions */
914 ScanKeyInit(&key[keycount++],
915 Anum_pg_proc_prokind,
916 BTEqualStrategyNumber, F_CHARNE,
917 CharGetDatum(PROKIND_PROCEDURE));
918 else if (objtype == OBJECT_PROCEDURE)
919 ScanKeyInit(&key[keycount++],
920 Anum_pg_proc_prokind,
921 BTEqualStrategyNumber, F_CHAREQ,
922 CharGetDatum(PROKIND_PROCEDURE));
924 rel = table_open(ProcedureRelationId, AccessShareLock);
925 scan = table_beginscan_catalog(rel, keycount, key);
927 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
929 Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
931 objects = lappend_oid(objects, oid);
934 table_endscan(scan);
935 table_close(rel, AccessShareLock);
937 break;
938 default:
939 /* should not happen */
940 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
941 (int) objtype);
945 return objects;
949 * getRelationsInNamespace
951 * Return Oid list of relations in given namespace filtered by relation kind
953 static List *
954 getRelationsInNamespace(Oid namespaceId, char relkind)
956 List *relations = NIL;
957 ScanKeyData key[2];
958 Relation rel;
959 TableScanDesc scan;
960 HeapTuple tuple;
962 ScanKeyInit(&key[0],
963 Anum_pg_class_relnamespace,
964 BTEqualStrategyNumber, F_OIDEQ,
965 ObjectIdGetDatum(namespaceId));
966 ScanKeyInit(&key[1],
967 Anum_pg_class_relkind,
968 BTEqualStrategyNumber, F_CHAREQ,
969 CharGetDatum(relkind));
971 rel = table_open(RelationRelationId, AccessShareLock);
972 scan = table_beginscan_catalog(rel, 2, key);
974 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
976 Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
978 relations = lappend_oid(relations, oid);
981 table_endscan(scan);
982 table_close(rel, AccessShareLock);
984 return relations;
989 * ALTER DEFAULT PRIVILEGES statement
991 void
992 ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
994 GrantStmt *action = stmt->action;
995 InternalDefaultACL iacls;
996 ListCell *cell;
997 List *rolespecs = NIL;
998 List *nspnames = NIL;
999 DefElem *drolespecs = NULL;
1000 DefElem *dnspnames = NULL;
1001 AclMode all_privileges;
1002 const char *errormsg;
1004 /* Deconstruct the "options" part of the statement */
1005 foreach(cell, stmt->options)
1007 DefElem *defel = (DefElem *) lfirst(cell);
1009 if (strcmp(defel->defname, "schemas") == 0)
1011 if (dnspnames)
1012 errorConflictingDefElem(defel, pstate);
1013 dnspnames = defel;
1015 else if (strcmp(defel->defname, "roles") == 0)
1017 if (drolespecs)
1018 errorConflictingDefElem(defel, pstate);
1019 drolespecs = defel;
1021 else
1022 elog(ERROR, "option \"%s\" not recognized", defel->defname);
1025 if (dnspnames)
1026 nspnames = (List *) dnspnames->arg;
1027 if (drolespecs)
1028 rolespecs = (List *) drolespecs->arg;
1030 /* Prepare the InternalDefaultACL representation of the statement */
1031 /* roleid to be filled below */
1032 /* nspid to be filled in SetDefaultACLsInSchemas */
1033 iacls.is_grant = action->is_grant;
1034 iacls.objtype = action->objtype;
1035 /* all_privs to be filled below */
1036 /* privileges to be filled below */
1037 iacls.grantees = NIL; /* filled below */
1038 iacls.grant_option = action->grant_option;
1039 iacls.behavior = action->behavior;
1042 * Convert the RoleSpec list into an Oid list. Note that at this point we
1043 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
1044 * there shouldn't be any additional work needed to support this case.
1046 foreach(cell, action->grantees)
1048 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
1049 Oid grantee_uid;
1051 switch (grantee->roletype)
1053 case ROLESPEC_PUBLIC:
1054 grantee_uid = ACL_ID_PUBLIC;
1055 break;
1056 default:
1057 grantee_uid = get_rolespec_oid(grantee, false);
1058 break;
1060 iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
1064 * Convert action->privileges, a list of privilege strings, into an
1065 * AclMode bitmask.
1067 switch (action->objtype)
1069 case OBJECT_TABLE:
1070 all_privileges = ACL_ALL_RIGHTS_RELATION;
1071 errormsg = gettext_noop("invalid privilege type %s for relation");
1072 break;
1073 case OBJECT_SEQUENCE:
1074 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1075 errormsg = gettext_noop("invalid privilege type %s for sequence");
1076 break;
1077 case OBJECT_FUNCTION:
1078 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1079 errormsg = gettext_noop("invalid privilege type %s for function");
1080 break;
1081 case OBJECT_PROCEDURE:
1082 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1083 errormsg = gettext_noop("invalid privilege type %s for procedure");
1084 break;
1085 case OBJECT_ROUTINE:
1086 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1087 errormsg = gettext_noop("invalid privilege type %s for routine");
1088 break;
1089 case OBJECT_TYPE:
1090 all_privileges = ACL_ALL_RIGHTS_TYPE;
1091 errormsg = gettext_noop("invalid privilege type %s for type");
1092 break;
1093 case OBJECT_SCHEMA:
1094 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
1095 errormsg = gettext_noop("invalid privilege type %s for schema");
1096 break;
1097 default:
1098 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1099 (int) action->objtype);
1100 /* keep compiler quiet */
1101 all_privileges = ACL_NO_RIGHTS;
1102 errormsg = NULL;
1105 if (action->privileges == NIL)
1107 iacls.all_privs = true;
1110 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1111 * depending on the object type
1113 iacls.privileges = ACL_NO_RIGHTS;
1115 else
1117 iacls.all_privs = false;
1118 iacls.privileges = ACL_NO_RIGHTS;
1120 foreach(cell, action->privileges)
1122 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1123 AclMode priv;
1125 if (privnode->cols)
1126 ereport(ERROR,
1127 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1128 errmsg("default privileges cannot be set for columns")));
1130 if (privnode->priv_name == NULL) /* parser mistake? */
1131 elog(ERROR, "AccessPriv node must specify privilege");
1132 priv = string_to_privilege(privnode->priv_name);
1134 if (priv & ~((AclMode) all_privileges))
1135 ereport(ERROR,
1136 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1137 errmsg(errormsg, privilege_to_string(priv))));
1139 iacls.privileges |= priv;
1143 if (rolespecs == NIL)
1145 /* Set permissions for myself */
1146 iacls.roleid = GetUserId();
1148 SetDefaultACLsInSchemas(&iacls, nspnames);
1150 else
1152 /* Look up the role OIDs and do permissions checks */
1153 ListCell *rolecell;
1155 foreach(rolecell, rolespecs)
1157 RoleSpec *rolespec = lfirst(rolecell);
1159 iacls.roleid = get_rolespec_oid(rolespec, false);
1161 if (!has_privs_of_role(GetUserId(), iacls.roleid))
1162 ereport(ERROR,
1163 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1164 errmsg("permission denied to change default privileges")));
1166 SetDefaultACLsInSchemas(&iacls, nspnames);
1172 * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1174 * All fields of *iacls except nspid were filled already
1176 static void
1177 SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
1179 if (nspnames == NIL)
1181 /* Set database-wide permissions if no schema was specified */
1182 iacls->nspid = InvalidOid;
1184 SetDefaultACL(iacls);
1186 else
1188 /* Look up the schema OIDs and set permissions for each one */
1189 ListCell *nspcell;
1191 foreach(nspcell, nspnames)
1193 char *nspname = strVal(lfirst(nspcell));
1195 iacls->nspid = get_namespace_oid(nspname, false);
1198 * We used to insist that the target role have CREATE privileges
1199 * on the schema, since without that it wouldn't be able to create
1200 * an object for which these default privileges would apply.
1201 * However, this check proved to be more confusing than helpful,
1202 * and it also caused certain database states to not be
1203 * dumpable/restorable, since revoking CREATE doesn't cause
1204 * default privileges for the schema to go away. So now, we just
1205 * allow the ALTER; if the user lacks CREATE he'll find out when
1206 * he tries to create an object.
1209 SetDefaultACL(iacls);
1216 * Create or update a pg_default_acl entry
1218 static void
1219 SetDefaultACL(InternalDefaultACL *iacls)
1221 AclMode this_privileges = iacls->privileges;
1222 char objtype;
1223 Relation rel;
1224 HeapTuple tuple;
1225 bool isNew;
1226 Acl *def_acl;
1227 Acl *old_acl;
1228 Acl *new_acl;
1229 HeapTuple newtuple;
1230 int noldmembers;
1231 int nnewmembers;
1232 Oid *oldmembers;
1233 Oid *newmembers;
1235 rel = table_open(DefaultAclRelationId, RowExclusiveLock);
1238 * The default for a global entry is the hard-wired default ACL for the
1239 * particular object type. The default for non-global entries is an empty
1240 * ACL. This must be so because global entries replace the hard-wired
1241 * defaults, while others are added on.
1243 if (!OidIsValid(iacls->nspid))
1244 def_acl = acldefault(iacls->objtype, iacls->roleid);
1245 else
1246 def_acl = make_empty_acl();
1249 * Convert ACL object type to pg_default_acl object type and handle
1250 * all_privs option
1252 switch (iacls->objtype)
1254 case OBJECT_TABLE:
1255 objtype = DEFACLOBJ_RELATION;
1256 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1257 this_privileges = ACL_ALL_RIGHTS_RELATION;
1258 break;
1260 case OBJECT_SEQUENCE:
1261 objtype = DEFACLOBJ_SEQUENCE;
1262 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1263 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1264 break;
1266 case OBJECT_FUNCTION:
1267 objtype = DEFACLOBJ_FUNCTION;
1268 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1269 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
1270 break;
1272 case OBJECT_TYPE:
1273 objtype = DEFACLOBJ_TYPE;
1274 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1275 this_privileges = ACL_ALL_RIGHTS_TYPE;
1276 break;
1278 case OBJECT_SCHEMA:
1279 if (OidIsValid(iacls->nspid))
1280 ereport(ERROR,
1281 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1282 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1283 objtype = DEFACLOBJ_NAMESPACE;
1284 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1285 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1286 break;
1288 default:
1289 elog(ERROR, "unrecognized object type: %d",
1290 (int) iacls->objtype);
1291 objtype = 0; /* keep compiler quiet */
1292 break;
1295 /* Search for existing row for this object type in catalog */
1296 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1297 ObjectIdGetDatum(iacls->roleid),
1298 ObjectIdGetDatum(iacls->nspid),
1299 CharGetDatum(objtype));
1301 if (HeapTupleIsValid(tuple))
1303 Datum aclDatum;
1304 bool isNull;
1306 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1307 Anum_pg_default_acl_defaclacl,
1308 &isNull);
1309 if (!isNull)
1310 old_acl = DatumGetAclPCopy(aclDatum);
1311 else
1312 old_acl = NULL; /* this case shouldn't happen, probably */
1313 isNew = false;
1315 else
1317 old_acl = NULL;
1318 isNew = true;
1321 if (old_acl != NULL)
1324 * We need the members of both old and new ACLs so we can correct the
1325 * shared dependency information. Collect data before
1326 * merge_acl_with_grant throws away old_acl.
1328 noldmembers = aclmembers(old_acl, &oldmembers);
1330 else
1332 /* If no or null entry, start with the default ACL value */
1333 old_acl = aclcopy(def_acl);
1334 /* There are no old member roles according to the catalogs */
1335 noldmembers = 0;
1336 oldmembers = NULL;
1340 * Generate new ACL. Grantor of rights is always the same as the target
1341 * role.
1343 new_acl = merge_acl_with_grant(old_acl,
1344 iacls->is_grant,
1345 iacls->grant_option,
1346 iacls->behavior,
1347 iacls->grantees,
1348 this_privileges,
1349 iacls->roleid,
1350 iacls->roleid);
1353 * If the result is the same as the default value, we do not need an
1354 * explicit pg_default_acl entry, and should in fact remove the entry if
1355 * it exists. Must sort both arrays to compare properly.
1357 aclitemsort(new_acl);
1358 aclitemsort(def_acl);
1359 if (aclequal(new_acl, def_acl))
1361 /* delete old entry, if indeed there is one */
1362 if (!isNew)
1364 ObjectAddress myself;
1367 * The dependency machinery will take care of removing all
1368 * associated dependency entries. We use DROP_RESTRICT since
1369 * there shouldn't be anything depending on this entry.
1371 myself.classId = DefaultAclRelationId;
1372 myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1373 myself.objectSubId = 0;
1375 performDeletion(&myself, DROP_RESTRICT, 0);
1378 else
1380 Datum values[Natts_pg_default_acl] = {0};
1381 bool nulls[Natts_pg_default_acl] = {0};
1382 bool replaces[Natts_pg_default_acl] = {0};
1383 Oid defAclOid;
1385 if (isNew)
1387 /* insert new entry */
1388 defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1389 Anum_pg_default_acl_oid);
1390 values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1391 values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1392 values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1393 values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1394 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1396 newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1397 CatalogTupleInsert(rel, newtuple);
1399 else
1401 defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1403 /* update existing entry */
1404 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1405 replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1407 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1408 values, nulls, replaces);
1409 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1412 /* these dependencies don't change in an update */
1413 if (isNew)
1415 /* dependency on role */
1416 recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1417 iacls->roleid);
1419 /* dependency on namespace */
1420 if (OidIsValid(iacls->nspid))
1422 ObjectAddress myself,
1423 referenced;
1425 myself.classId = DefaultAclRelationId;
1426 myself.objectId = defAclOid;
1427 myself.objectSubId = 0;
1429 referenced.classId = NamespaceRelationId;
1430 referenced.objectId = iacls->nspid;
1431 referenced.objectSubId = 0;
1433 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1438 * Update the shared dependency ACL info
1440 nnewmembers = aclmembers(new_acl, &newmembers);
1442 updateAclDependencies(DefaultAclRelationId,
1443 defAclOid, 0,
1444 iacls->roleid,
1445 noldmembers, oldmembers,
1446 nnewmembers, newmembers);
1448 if (isNew)
1449 InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1450 else
1451 InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1454 if (HeapTupleIsValid(tuple))
1455 ReleaseSysCache(tuple);
1457 table_close(rel, RowExclusiveLock);
1459 /* prevent error when processing duplicate objects */
1460 CommandCounterIncrement();
1465 * RemoveRoleFromObjectACL
1467 * Used by shdepDropOwned to remove mentions of a role in ACLs
1469 void
1470 RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1472 if (classid == DefaultAclRelationId)
1474 InternalDefaultACL iacls;
1475 Form_pg_default_acl pg_default_acl_tuple;
1476 Relation rel;
1477 ScanKeyData skey[1];
1478 SysScanDesc scan;
1479 HeapTuple tuple;
1481 /* first fetch info needed by SetDefaultACL */
1482 rel = table_open(DefaultAclRelationId, AccessShareLock);
1484 ScanKeyInit(&skey[0],
1485 Anum_pg_default_acl_oid,
1486 BTEqualStrategyNumber, F_OIDEQ,
1487 ObjectIdGetDatum(objid));
1489 scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1490 NULL, 1, skey);
1492 tuple = systable_getnext(scan);
1494 if (!HeapTupleIsValid(tuple))
1495 elog(ERROR, "could not find tuple for default ACL %u", objid);
1497 pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1499 iacls.roleid = pg_default_acl_tuple->defaclrole;
1500 iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1502 switch (pg_default_acl_tuple->defaclobjtype)
1504 case DEFACLOBJ_RELATION:
1505 iacls.objtype = OBJECT_TABLE;
1506 break;
1507 case DEFACLOBJ_SEQUENCE:
1508 iacls.objtype = OBJECT_SEQUENCE;
1509 break;
1510 case DEFACLOBJ_FUNCTION:
1511 iacls.objtype = OBJECT_FUNCTION;
1512 break;
1513 case DEFACLOBJ_TYPE:
1514 iacls.objtype = OBJECT_TYPE;
1515 break;
1516 case DEFACLOBJ_NAMESPACE:
1517 iacls.objtype = OBJECT_SCHEMA;
1518 break;
1519 default:
1520 /* Shouldn't get here */
1521 elog(ERROR, "unexpected default ACL type: %d",
1522 (int) pg_default_acl_tuple->defaclobjtype);
1523 break;
1526 systable_endscan(scan);
1527 table_close(rel, AccessShareLock);
1529 iacls.is_grant = false;
1530 iacls.all_privs = true;
1531 iacls.privileges = ACL_NO_RIGHTS;
1532 iacls.grantees = list_make1_oid(roleid);
1533 iacls.grant_option = false;
1534 iacls.behavior = DROP_CASCADE;
1536 /* Do it */
1537 SetDefaultACL(&iacls);
1539 else
1541 InternalGrant istmt;
1543 switch (classid)
1545 case RelationRelationId:
1546 /* it's OK to use TABLE for a sequence */
1547 istmt.objtype = OBJECT_TABLE;
1548 break;
1549 case DatabaseRelationId:
1550 istmt.objtype = OBJECT_DATABASE;
1551 break;
1552 case TypeRelationId:
1553 istmt.objtype = OBJECT_TYPE;
1554 break;
1555 case ProcedureRelationId:
1556 istmt.objtype = OBJECT_ROUTINE;
1557 break;
1558 case LanguageRelationId:
1559 istmt.objtype = OBJECT_LANGUAGE;
1560 break;
1561 case LargeObjectRelationId:
1562 istmt.objtype = OBJECT_LARGEOBJECT;
1563 break;
1564 case NamespaceRelationId:
1565 istmt.objtype = OBJECT_SCHEMA;
1566 break;
1567 case TableSpaceRelationId:
1568 istmt.objtype = OBJECT_TABLESPACE;
1569 break;
1570 case ForeignServerRelationId:
1571 istmt.objtype = OBJECT_FOREIGN_SERVER;
1572 break;
1573 case ForeignDataWrapperRelationId:
1574 istmt.objtype = OBJECT_FDW;
1575 break;
1576 case ParameterAclRelationId:
1577 istmt.objtype = OBJECT_PARAMETER_ACL;
1578 break;
1579 default:
1580 elog(ERROR, "unexpected object class %u", classid);
1581 break;
1583 istmt.is_grant = false;
1584 istmt.objects = list_make1_oid(objid);
1585 istmt.all_privs = true;
1586 istmt.privileges = ACL_NO_RIGHTS;
1587 istmt.col_privs = NIL;
1588 istmt.grantees = list_make1_oid(roleid);
1589 istmt.grant_option = false;
1590 istmt.behavior = DROP_CASCADE;
1592 ExecGrantStmt_oids(&istmt);
1598 * expand_col_privileges
1600 * OR the specified privilege(s) into per-column array entries for each
1601 * specified attribute. The per-column array is indexed starting at
1602 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1604 static void
1605 expand_col_privileges(List *colnames, Oid table_oid,
1606 AclMode this_privileges,
1607 AclMode *col_privileges,
1608 int num_col_privileges)
1610 ListCell *cell;
1612 foreach(cell, colnames)
1614 char *colname = strVal(lfirst(cell));
1615 AttrNumber attnum;
1617 attnum = get_attnum(table_oid, colname);
1618 if (attnum == InvalidAttrNumber)
1619 ereport(ERROR,
1620 (errcode(ERRCODE_UNDEFINED_COLUMN),
1621 errmsg("column \"%s\" of relation \"%s\" does not exist",
1622 colname, get_rel_name(table_oid))));
1623 attnum -= FirstLowInvalidHeapAttributeNumber;
1624 if (attnum <= 0 || attnum >= num_col_privileges)
1625 elog(ERROR, "column number out of range"); /* safety check */
1626 col_privileges[attnum] |= this_privileges;
1631 * expand_all_col_privileges
1633 * OR the specified privilege(s) into per-column array entries for each valid
1634 * attribute of a relation. The per-column array is indexed starting at
1635 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1637 static void
1638 expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
1639 AclMode this_privileges,
1640 AclMode *col_privileges,
1641 int num_col_privileges)
1643 AttrNumber curr_att;
1645 Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1646 for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1647 curr_att <= classForm->relnatts;
1648 curr_att++)
1650 HeapTuple attTuple;
1651 bool isdropped;
1653 if (curr_att == InvalidAttrNumber)
1654 continue;
1656 /* Views don't have any system columns at all */
1657 if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1658 continue;
1660 attTuple = SearchSysCache2(ATTNUM,
1661 ObjectIdGetDatum(table_oid),
1662 Int16GetDatum(curr_att));
1663 if (!HeapTupleIsValid(attTuple))
1664 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1665 curr_att, table_oid);
1667 isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1669 ReleaseSysCache(attTuple);
1671 /* ignore dropped columns */
1672 if (isdropped)
1673 continue;
1675 col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1680 * This processes attributes, but expects to be called from
1681 * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1683 static void
1684 ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1685 AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1686 Relation attRelation, const Acl *old_rel_acl)
1688 HeapTuple attr_tuple;
1689 Form_pg_attribute pg_attribute_tuple;
1690 Acl *old_acl;
1691 Acl *new_acl;
1692 Acl *merged_acl;
1693 Datum aclDatum;
1694 bool isNull;
1695 Oid grantorId;
1696 AclMode avail_goptions;
1697 bool need_update;
1698 HeapTuple newtuple;
1699 Datum values[Natts_pg_attribute] = {0};
1700 bool nulls[Natts_pg_attribute] = {0};
1701 bool replaces[Natts_pg_attribute] = {0};
1702 int noldmembers;
1703 int nnewmembers;
1704 Oid *oldmembers;
1705 Oid *newmembers;
1707 attr_tuple = SearchSysCache2(ATTNUM,
1708 ObjectIdGetDatum(relOid),
1709 Int16GetDatum(attnum));
1710 if (!HeapTupleIsValid(attr_tuple))
1711 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1712 attnum, relOid);
1713 pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1716 * Get working copy of existing ACL. If there's no ACL, substitute the
1717 * proper default.
1719 aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1720 &isNull);
1721 if (isNull)
1723 old_acl = acldefault(OBJECT_COLUMN, ownerId);
1724 /* There are no old member roles according to the catalogs */
1725 noldmembers = 0;
1726 oldmembers = NULL;
1728 else
1730 old_acl = DatumGetAclPCopy(aclDatum);
1731 /* Get the roles mentioned in the existing ACL */
1732 noldmembers = aclmembers(old_acl, &oldmembers);
1736 * In select_best_grantor we should consider existing table-level ACL bits
1737 * as well as the per-column ACL. Build a new ACL that is their
1738 * concatenation. (This is a bit cheap and dirty compared to merging them
1739 * properly with no duplications, but it's all we need here.)
1741 merged_acl = aclconcat(old_rel_acl, old_acl);
1743 /* Determine ID to do the grant as, and available grant options */
1744 select_best_grantor(GetUserId(), col_privileges,
1745 merged_acl, ownerId,
1746 &grantorId, &avail_goptions);
1748 pfree(merged_acl);
1751 * Restrict the privileges to what we can actually grant, and emit the
1752 * standards-mandated warning and error messages. Note: we don't track
1753 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1754 * each column; we just approximate it by whether all the possible
1755 * privileges are specified now. Since the all_privs flag only determines
1756 * whether a warning is issued, this seems close enough.
1758 col_privileges =
1759 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1760 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1761 col_privileges,
1762 relOid, grantorId, OBJECT_COLUMN,
1763 relname, attnum,
1764 NameStr(pg_attribute_tuple->attname));
1767 * Generate new ACL.
1769 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1770 istmt->grant_option,
1771 istmt->behavior, istmt->grantees,
1772 col_privileges, grantorId,
1773 ownerId);
1776 * We need the members of both old and new ACLs so we can correct the
1777 * shared dependency information.
1779 nnewmembers = aclmembers(new_acl, &newmembers);
1781 /* finished building new ACL value, now insert it */
1784 * If the updated ACL is empty, we can set attacl to null, and maybe even
1785 * avoid an update of the pg_attribute row. This is worth testing because
1786 * we'll come through here multiple times for any relation-level REVOKE,
1787 * even if there were never any column GRANTs. Note we are assuming that
1788 * the "default" ACL state for columns is empty.
1790 if (ACL_NUM(new_acl) > 0)
1792 values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1793 need_update = true;
1795 else
1797 nulls[Anum_pg_attribute_attacl - 1] = true;
1798 need_update = !isNull;
1800 replaces[Anum_pg_attribute_attacl - 1] = true;
1802 if (need_update)
1804 newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1805 values, nulls, replaces);
1807 CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1809 /* Update initial privileges for extensions */
1810 recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1811 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1813 /* Update the shared dependency ACL info */
1814 updateAclDependencies(RelationRelationId, relOid, attnum,
1815 ownerId,
1816 noldmembers, oldmembers,
1817 nnewmembers, newmembers);
1820 pfree(new_acl);
1822 ReleaseSysCache(attr_tuple);
1826 * This processes both sequences and non-sequences.
1828 static void
1829 ExecGrant_Relation(InternalGrant *istmt)
1831 Relation relation;
1832 Relation attRelation;
1833 ListCell *cell;
1835 relation = table_open(RelationRelationId, RowExclusiveLock);
1836 attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1838 foreach(cell, istmt->objects)
1840 Oid relOid = lfirst_oid(cell);
1841 Datum aclDatum;
1842 Form_pg_class pg_class_tuple;
1843 bool isNull;
1844 AclMode this_privileges;
1845 AclMode *col_privileges;
1846 int num_col_privileges;
1847 bool have_col_privileges;
1848 Acl *old_acl;
1849 Acl *old_rel_acl;
1850 int noldmembers;
1851 Oid *oldmembers;
1852 Oid ownerId;
1853 HeapTuple tuple;
1854 ListCell *cell_colprivs;
1856 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1857 if (!HeapTupleIsValid(tuple))
1858 elog(ERROR, "cache lookup failed for relation %u", relOid);
1859 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1861 /* Not sensible to grant on an index */
1862 if (pg_class_tuple->relkind == RELKIND_INDEX ||
1863 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1864 ereport(ERROR,
1865 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1866 errmsg("\"%s\" is an index",
1867 NameStr(pg_class_tuple->relname))));
1869 /* Composite types aren't tables either */
1870 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1871 ereport(ERROR,
1872 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1873 errmsg("\"%s\" is a composite type",
1874 NameStr(pg_class_tuple->relname))));
1876 /* Used GRANT SEQUENCE on a non-sequence? */
1877 if (istmt->objtype == OBJECT_SEQUENCE &&
1878 pg_class_tuple->relkind != RELKIND_SEQUENCE)
1879 ereport(ERROR,
1880 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1881 errmsg("\"%s\" is not a sequence",
1882 NameStr(pg_class_tuple->relname))));
1884 /* Adjust the default permissions based on object type */
1885 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1887 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1888 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1889 else
1890 this_privileges = ACL_ALL_RIGHTS_RELATION;
1892 else
1893 this_privileges = istmt->privileges;
1896 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1897 * so we have to look at the relkind to determine the supported
1898 * permissions. The OR of table and sequence permissions were already
1899 * checked.
1901 if (istmt->objtype == OBJECT_TABLE)
1903 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1906 * For backward compatibility, just throw a warning for
1907 * invalid sequence permissions when using the non-sequence
1908 * GRANT syntax.
1910 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1913 * Mention the object name because the user needs to know
1914 * which operations succeeded. This is required because
1915 * WARNING allows the command to continue.
1917 ereport(WARNING,
1918 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1919 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1920 NameStr(pg_class_tuple->relname))));
1921 this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1924 else
1926 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1929 * USAGE is the only permission supported by sequences but
1930 * not by non-sequences. Don't mention the object name
1931 * because we didn't in the combined TABLE | SEQUENCE
1932 * check.
1934 ereport(ERROR,
1935 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1936 errmsg("invalid privilege type %s for table",
1937 "USAGE")));
1943 * Set up array in which we'll accumulate any column privilege bits
1944 * that need modification. The array is indexed such that entry [0]
1945 * corresponds to FirstLowInvalidHeapAttributeNumber.
1947 num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1948 col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1949 have_col_privileges = false;
1952 * If we are revoking relation privileges that are also column
1953 * privileges, we must implicitly revoke them from each column too,
1954 * per SQL spec. (We don't need to implicitly add column privileges
1955 * during GRANT because the permissions-checking code always checks
1956 * both relation and per-column privileges.)
1958 if (!istmt->is_grant &&
1959 (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1961 expand_all_col_privileges(relOid, pg_class_tuple,
1962 this_privileges & ACL_ALL_RIGHTS_COLUMN,
1963 col_privileges,
1964 num_col_privileges);
1965 have_col_privileges = true;
1969 * Get owner ID and working copy of existing ACL. If there's no ACL,
1970 * substitute the proper default.
1972 ownerId = pg_class_tuple->relowner;
1973 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1974 &isNull);
1975 if (isNull)
1977 switch (pg_class_tuple->relkind)
1979 case RELKIND_SEQUENCE:
1980 old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1981 break;
1982 default:
1983 old_acl = acldefault(OBJECT_TABLE, ownerId);
1984 break;
1986 /* There are no old member roles according to the catalogs */
1987 noldmembers = 0;
1988 oldmembers = NULL;
1990 else
1992 old_acl = DatumGetAclPCopy(aclDatum);
1993 /* Get the roles mentioned in the existing ACL */
1994 noldmembers = aclmembers(old_acl, &oldmembers);
1997 /* Need an extra copy of original rel ACL for column handling */
1998 old_rel_acl = aclcopy(old_acl);
2001 * Handle relation-level privileges, if any were specified
2003 if (this_privileges != ACL_NO_RIGHTS)
2005 AclMode avail_goptions;
2006 Acl *new_acl;
2007 Oid grantorId;
2008 HeapTuple newtuple;
2009 Datum values[Natts_pg_class] = {0};
2010 bool nulls[Natts_pg_class] = {0};
2011 bool replaces[Natts_pg_class] = {0};
2012 int nnewmembers;
2013 Oid *newmembers;
2014 ObjectType objtype;
2016 /* Determine ID to do the grant as, and available grant options */
2017 select_best_grantor(GetUserId(), this_privileges,
2018 old_acl, ownerId,
2019 &grantorId, &avail_goptions);
2021 switch (pg_class_tuple->relkind)
2023 case RELKIND_SEQUENCE:
2024 objtype = OBJECT_SEQUENCE;
2025 break;
2026 default:
2027 objtype = OBJECT_TABLE;
2028 break;
2032 * Restrict the privileges to what we can actually grant, and emit
2033 * the standards-mandated warning and error messages.
2035 this_privileges =
2036 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2037 istmt->all_privs, this_privileges,
2038 relOid, grantorId, objtype,
2039 NameStr(pg_class_tuple->relname),
2040 0, NULL);
2043 * Generate new ACL.
2045 new_acl = merge_acl_with_grant(old_acl,
2046 istmt->is_grant,
2047 istmt->grant_option,
2048 istmt->behavior,
2049 istmt->grantees,
2050 this_privileges,
2051 grantorId,
2052 ownerId);
2055 * We need the members of both old and new ACLs so we can correct
2056 * the shared dependency information.
2058 nnewmembers = aclmembers(new_acl, &newmembers);
2060 /* finished building new ACL value, now insert it */
2061 replaces[Anum_pg_class_relacl - 1] = true;
2062 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
2064 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2065 values, nulls, replaces);
2067 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2069 /* Update initial privileges for extensions */
2070 recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2072 /* Update the shared dependency ACL info */
2073 updateAclDependencies(RelationRelationId, relOid, 0,
2074 ownerId,
2075 noldmembers, oldmembers,
2076 nnewmembers, newmembers);
2078 pfree(new_acl);
2082 * Handle column-level privileges, if any were specified or implied.
2083 * We first expand the user-specified column privileges into the
2084 * array, and then iterate over all nonempty array entries.
2086 foreach(cell_colprivs, istmt->col_privs)
2088 AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2090 if (col_privs->priv_name == NULL)
2091 this_privileges = ACL_ALL_RIGHTS_COLUMN;
2092 else
2093 this_privileges = string_to_privilege(col_privs->priv_name);
2095 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2096 ereport(ERROR,
2097 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2098 errmsg("invalid privilege type %s for column",
2099 privilege_to_string(this_privileges))));
2101 if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2102 this_privileges & ~((AclMode) ACL_SELECT))
2105 * The only column privilege allowed on sequences is SELECT.
2106 * This is a warning not error because we do it that way for
2107 * relation-level privileges.
2109 ereport(WARNING,
2110 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2111 errmsg("sequence \"%s\" only supports SELECT column privileges",
2112 NameStr(pg_class_tuple->relname))));
2114 this_privileges &= (AclMode) ACL_SELECT;
2117 expand_col_privileges(col_privs->cols, relOid,
2118 this_privileges,
2119 col_privileges,
2120 num_col_privileges);
2121 have_col_privileges = true;
2124 if (have_col_privileges)
2126 AttrNumber i;
2128 for (i = 0; i < num_col_privileges; i++)
2130 if (col_privileges[i] == ACL_NO_RIGHTS)
2131 continue;
2132 ExecGrant_Attribute(istmt,
2133 relOid,
2134 NameStr(pg_class_tuple->relname),
2135 i + FirstLowInvalidHeapAttributeNumber,
2136 ownerId,
2137 col_privileges[i],
2138 attRelation,
2139 old_rel_acl);
2143 pfree(old_rel_acl);
2144 pfree(col_privileges);
2146 ReleaseSysCache(tuple);
2148 /* prevent error when processing duplicate objects */
2149 CommandCounterIncrement();
2152 table_close(attRelation, RowExclusiveLock);
2153 table_close(relation, RowExclusiveLock);
2156 static void
2157 ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
2158 void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
2160 int cacheid;
2161 Relation relation;
2162 ListCell *cell;
2164 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2165 istmt->privileges = default_privs;
2167 cacheid = get_object_catcache_oid(classid);
2169 relation = table_open(classid, RowExclusiveLock);
2171 foreach(cell, istmt->objects)
2173 Oid objectid = lfirst_oid(cell);
2174 Datum aclDatum;
2175 Datum nameDatum;
2176 bool isNull;
2177 AclMode avail_goptions;
2178 AclMode this_privileges;
2179 Acl *old_acl;
2180 Acl *new_acl;
2181 Oid grantorId;
2182 Oid ownerId;
2183 HeapTuple tuple;
2184 HeapTuple newtuple;
2185 Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2186 bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2187 bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2188 int noldmembers;
2189 int nnewmembers;
2190 Oid *oldmembers;
2191 Oid *newmembers;
2193 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
2194 if (!HeapTupleIsValid(tuple))
2195 elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2198 * Additional object-type-specific checks
2200 if (object_check)
2201 object_check(istmt, tuple);
2204 * Get owner ID and working copy of existing ACL. If there's no ACL,
2205 * substitute the proper default.
2207 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2208 tuple,
2209 get_object_attnum_owner(classid)));
2210 aclDatum = SysCacheGetAttr(cacheid,
2211 tuple,
2212 get_object_attnum_acl(classid),
2213 &isNull);
2214 if (isNull)
2216 old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2217 /* There are no old member roles according to the catalogs */
2218 noldmembers = 0;
2219 oldmembers = NULL;
2221 else
2223 old_acl = DatumGetAclPCopy(aclDatum);
2224 /* Get the roles mentioned in the existing ACL */
2225 noldmembers = aclmembers(old_acl, &oldmembers);
2228 /* Determine ID to do the grant as, and available grant options */
2229 select_best_grantor(GetUserId(), istmt->privileges,
2230 old_acl, ownerId,
2231 &grantorId, &avail_goptions);
2233 nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2234 get_object_attnum_name(classid));
2237 * Restrict the privileges to what we can actually grant, and emit the
2238 * standards-mandated warning and error messages.
2240 this_privileges =
2241 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2242 istmt->all_privs, istmt->privileges,
2243 objectid, grantorId, get_object_type(classid, objectid),
2244 NameStr(*DatumGetName(nameDatum)),
2245 0, NULL);
2248 * Generate new ACL.
2250 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2251 istmt->grant_option, istmt->behavior,
2252 istmt->grantees, this_privileges,
2253 grantorId, ownerId);
2256 * We need the members of both old and new ACLs so we can correct the
2257 * shared dependency information.
2259 nnewmembers = aclmembers(new_acl, &newmembers);
2261 /* finished building new ACL value, now insert it */
2262 replaces[get_object_attnum_acl(classid) - 1] = true;
2263 values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2265 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2266 nulls, replaces);
2268 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2270 /* Update initial privileges for extensions */
2271 recordExtensionInitPriv(objectid, classid, 0, new_acl);
2273 /* Update the shared dependency ACL info */
2274 updateAclDependencies(classid,
2275 objectid, 0,
2276 ownerId,
2277 noldmembers, oldmembers,
2278 nnewmembers, newmembers);
2280 ReleaseSysCache(tuple);
2282 pfree(new_acl);
2284 /* prevent error when processing duplicate objects */
2285 CommandCounterIncrement();
2288 table_close(relation, RowExclusiveLock);
2291 static void
2292 ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
2294 Form_pg_language pg_language_tuple;
2296 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2298 if (!pg_language_tuple->lanpltrusted)
2299 ereport(ERROR,
2300 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2301 errmsg("language \"%s\" is not trusted",
2302 NameStr(pg_language_tuple->lanname)),
2303 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2304 "because only superusers can use untrusted languages.")));
2307 static void
2308 ExecGrant_Largeobject(InternalGrant *istmt)
2310 Relation relation;
2311 ListCell *cell;
2313 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2314 istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
2316 relation = table_open(LargeObjectMetadataRelationId,
2317 RowExclusiveLock);
2319 foreach(cell, istmt->objects)
2321 Oid loid = lfirst_oid(cell);
2322 Form_pg_largeobject_metadata form_lo_meta;
2323 char loname[NAMEDATALEN];
2324 Datum aclDatum;
2325 bool isNull;
2326 AclMode avail_goptions;
2327 AclMode this_privileges;
2328 Acl *old_acl;
2329 Acl *new_acl;
2330 Oid grantorId;
2331 Oid ownerId;
2332 HeapTuple newtuple;
2333 Datum values[Natts_pg_largeobject_metadata] = {0};
2334 bool nulls[Natts_pg_largeobject_metadata] = {0};
2335 bool replaces[Natts_pg_largeobject_metadata] = {0};
2336 int noldmembers;
2337 int nnewmembers;
2338 Oid *oldmembers;
2339 Oid *newmembers;
2340 ScanKeyData entry[1];
2341 SysScanDesc scan;
2342 HeapTuple tuple;
2344 /* There's no syscache for pg_largeobject_metadata */
2345 ScanKeyInit(&entry[0],
2346 Anum_pg_largeobject_metadata_oid,
2347 BTEqualStrategyNumber, F_OIDEQ,
2348 ObjectIdGetDatum(loid));
2350 scan = systable_beginscan(relation,
2351 LargeObjectMetadataOidIndexId, true,
2352 NULL, 1, entry);
2354 tuple = systable_getnext(scan);
2355 if (!HeapTupleIsValid(tuple))
2356 elog(ERROR, "could not find tuple for large object %u", loid);
2358 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2361 * Get owner ID and working copy of existing ACL. If there's no ACL,
2362 * substitute the proper default.
2364 ownerId = form_lo_meta->lomowner;
2365 aclDatum = heap_getattr(tuple,
2366 Anum_pg_largeobject_metadata_lomacl,
2367 RelationGetDescr(relation), &isNull);
2368 if (isNull)
2370 old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2371 /* There are no old member roles according to the catalogs */
2372 noldmembers = 0;
2373 oldmembers = NULL;
2375 else
2377 old_acl = DatumGetAclPCopy(aclDatum);
2378 /* Get the roles mentioned in the existing ACL */
2379 noldmembers = aclmembers(old_acl, &oldmembers);
2382 /* Determine ID to do the grant as, and available grant options */
2383 select_best_grantor(GetUserId(), istmt->privileges,
2384 old_acl, ownerId,
2385 &grantorId, &avail_goptions);
2388 * Restrict the privileges to what we can actually grant, and emit the
2389 * standards-mandated warning and error messages.
2391 snprintf(loname, sizeof(loname), "large object %u", loid);
2392 this_privileges =
2393 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2394 istmt->all_privs, istmt->privileges,
2395 loid, grantorId, OBJECT_LARGEOBJECT,
2396 loname, 0, NULL);
2399 * Generate new ACL.
2401 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2402 istmt->grant_option, istmt->behavior,
2403 istmt->grantees, this_privileges,
2404 grantorId, ownerId);
2407 * We need the members of both old and new ACLs so we can correct the
2408 * shared dependency information.
2410 nnewmembers = aclmembers(new_acl, &newmembers);
2412 /* finished building new ACL value, now insert it */
2413 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2414 values[Anum_pg_largeobject_metadata_lomacl - 1]
2415 = PointerGetDatum(new_acl);
2417 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2418 values, nulls, replaces);
2420 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2422 /* Update initial privileges for extensions */
2423 recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2425 /* Update the shared dependency ACL info */
2426 updateAclDependencies(LargeObjectRelationId,
2427 form_lo_meta->oid, 0,
2428 ownerId,
2429 noldmembers, oldmembers,
2430 nnewmembers, newmembers);
2432 systable_endscan(scan);
2434 pfree(new_acl);
2436 /* prevent error when processing duplicate objects */
2437 CommandCounterIncrement();
2440 table_close(relation, RowExclusiveLock);
2443 static void
2444 ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
2446 Form_pg_type pg_type_tuple;
2448 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2450 /* Disallow GRANT on dependent types */
2451 if (IsTrueArrayType(pg_type_tuple))
2452 ereport(ERROR,
2453 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2454 errmsg("cannot set privileges of array types"),
2455 errhint("Set the privileges of the element type instead.")));
2456 if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2457 ereport(ERROR,
2458 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2459 errmsg("cannot set privileges of multirange types"),
2460 errhint("Set the privileges of the range type instead.")));
2462 /* Used GRANT DOMAIN on a non-domain? */
2463 if (istmt->objtype == OBJECT_DOMAIN &&
2464 pg_type_tuple->typtype != TYPTYPE_DOMAIN)
2465 ereport(ERROR,
2466 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2467 errmsg("\"%s\" is not a domain",
2468 NameStr(pg_type_tuple->typname))));
2471 static void
2472 ExecGrant_Parameter(InternalGrant *istmt)
2474 Relation relation;
2475 ListCell *cell;
2477 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2478 istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
2480 relation = table_open(ParameterAclRelationId, RowExclusiveLock);
2482 foreach(cell, istmt->objects)
2484 Oid parameterId = lfirst_oid(cell);
2485 Datum nameDatum;
2486 const char *parname;
2487 Datum aclDatum;
2488 bool isNull;
2489 AclMode avail_goptions;
2490 AclMode this_privileges;
2491 Acl *old_acl;
2492 Acl *new_acl;
2493 Oid grantorId;
2494 Oid ownerId;
2495 HeapTuple tuple;
2496 int noldmembers;
2497 int nnewmembers;
2498 Oid *oldmembers;
2499 Oid *newmembers;
2501 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
2502 if (!HeapTupleIsValid(tuple))
2503 elog(ERROR, "cache lookup failed for parameter ACL %u",
2504 parameterId);
2506 /* We'll need the GUC's name */
2507 nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
2508 Anum_pg_parameter_acl_parname);
2509 parname = TextDatumGetCString(nameDatum);
2511 /* Treat all parameters as belonging to the bootstrap superuser. */
2512 ownerId = BOOTSTRAP_SUPERUSERID;
2515 * Get working copy of existing ACL. If there's no ACL, substitute the
2516 * proper default.
2518 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
2519 Anum_pg_parameter_acl_paracl,
2520 &isNull);
2522 if (isNull)
2524 old_acl = acldefault(istmt->objtype, ownerId);
2525 /* There are no old member roles according to the catalogs */
2526 noldmembers = 0;
2527 oldmembers = NULL;
2529 else
2531 old_acl = DatumGetAclPCopy(aclDatum);
2532 /* Get the roles mentioned in the existing ACL */
2533 noldmembers = aclmembers(old_acl, &oldmembers);
2536 /* Determine ID to do the grant as, and available grant options */
2537 select_best_grantor(GetUserId(), istmt->privileges,
2538 old_acl, ownerId,
2539 &grantorId, &avail_goptions);
2542 * Restrict the privileges to what we can actually grant, and emit the
2543 * standards-mandated warning and error messages.
2545 this_privileges =
2546 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2547 istmt->all_privs, istmt->privileges,
2548 parameterId, grantorId,
2549 OBJECT_PARAMETER_ACL,
2550 parname,
2551 0, NULL);
2554 * Generate new ACL.
2556 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2557 istmt->grant_option, istmt->behavior,
2558 istmt->grantees, this_privileges,
2559 grantorId, ownerId);
2562 * We need the members of both old and new ACLs so we can correct the
2563 * shared dependency information.
2565 nnewmembers = aclmembers(new_acl, &newmembers);
2568 * If the new ACL is equal to the default, we don't need the catalog
2569 * entry any longer. Delete it rather than updating it, to avoid
2570 * leaving a degenerate entry.
2572 if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
2574 CatalogTupleDelete(relation, &tuple->t_self);
2576 else
2578 /* finished building new ACL value, now insert it */
2579 HeapTuple newtuple;
2580 Datum values[Natts_pg_parameter_acl] = {0};
2581 bool nulls[Natts_pg_parameter_acl] = {0};
2582 bool replaces[Natts_pg_parameter_acl] = {0};
2584 replaces[Anum_pg_parameter_acl_paracl - 1] = true;
2585 values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
2587 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2588 values, nulls, replaces);
2590 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2593 /* Update initial privileges for extensions */
2594 recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
2595 new_acl);
2597 /* Update the shared dependency ACL info */
2598 updateAclDependencies(ParameterAclRelationId, parameterId, 0,
2599 ownerId,
2600 noldmembers, oldmembers,
2601 nnewmembers, newmembers);
2603 ReleaseSysCache(tuple);
2604 pfree(new_acl);
2606 /* prevent error when processing duplicate objects */
2607 CommandCounterIncrement();
2610 table_close(relation, RowExclusiveLock);
2614 static AclMode
2615 string_to_privilege(const char *privname)
2617 if (strcmp(privname, "insert") == 0)
2618 return ACL_INSERT;
2619 if (strcmp(privname, "select") == 0)
2620 return ACL_SELECT;
2621 if (strcmp(privname, "update") == 0)
2622 return ACL_UPDATE;
2623 if (strcmp(privname, "delete") == 0)
2624 return ACL_DELETE;
2625 if (strcmp(privname, "truncate") == 0)
2626 return ACL_TRUNCATE;
2627 if (strcmp(privname, "references") == 0)
2628 return ACL_REFERENCES;
2629 if (strcmp(privname, "trigger") == 0)
2630 return ACL_TRIGGER;
2631 if (strcmp(privname, "execute") == 0)
2632 return ACL_EXECUTE;
2633 if (strcmp(privname, "usage") == 0)
2634 return ACL_USAGE;
2635 if (strcmp(privname, "create") == 0)
2636 return ACL_CREATE;
2637 if (strcmp(privname, "temporary") == 0)
2638 return ACL_CREATE_TEMP;
2639 if (strcmp(privname, "temp") == 0)
2640 return ACL_CREATE_TEMP;
2641 if (strcmp(privname, "connect") == 0)
2642 return ACL_CONNECT;
2643 if (strcmp(privname, "set") == 0)
2644 return ACL_SET;
2645 if (strcmp(privname, "alter system") == 0)
2646 return ACL_ALTER_SYSTEM;
2647 if (strcmp(privname, "rule") == 0)
2648 return 0; /* ignore old RULE privileges */
2649 ereport(ERROR,
2650 (errcode(ERRCODE_SYNTAX_ERROR),
2651 errmsg("unrecognized privilege type \"%s\"", privname)));
2652 return 0; /* appease compiler */
2655 static const char *
2656 privilege_to_string(AclMode privilege)
2658 switch (privilege)
2660 case ACL_INSERT:
2661 return "INSERT";
2662 case ACL_SELECT:
2663 return "SELECT";
2664 case ACL_UPDATE:
2665 return "UPDATE";
2666 case ACL_DELETE:
2667 return "DELETE";
2668 case ACL_TRUNCATE:
2669 return "TRUNCATE";
2670 case ACL_REFERENCES:
2671 return "REFERENCES";
2672 case ACL_TRIGGER:
2673 return "TRIGGER";
2674 case ACL_EXECUTE:
2675 return "EXECUTE";
2676 case ACL_USAGE:
2677 return "USAGE";
2678 case ACL_CREATE:
2679 return "CREATE";
2680 case ACL_CREATE_TEMP:
2681 return "TEMP";
2682 case ACL_CONNECT:
2683 return "CONNECT";
2684 case ACL_SET:
2685 return "SET";
2686 case ACL_ALTER_SYSTEM:
2687 return "ALTER SYSTEM";
2688 default:
2689 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2691 return NULL; /* appease compiler */
2695 * Standardized reporting of aclcheck permissions failures.
2697 * Note: we do not double-quote the %s's below, because many callers
2698 * supply strings that might be already quoted.
2700 void
2701 aclcheck_error(AclResult aclerr, ObjectType objtype,
2702 const char *objectname)
2704 switch (aclerr)
2706 case ACLCHECK_OK:
2707 /* no error, so return to caller */
2708 break;
2709 case ACLCHECK_NO_PRIV:
2711 const char *msg = "???";
2713 switch (objtype)
2715 case OBJECT_AGGREGATE:
2716 msg = gettext_noop("permission denied for aggregate %s");
2717 break;
2718 case OBJECT_COLLATION:
2719 msg = gettext_noop("permission denied for collation %s");
2720 break;
2721 case OBJECT_COLUMN:
2722 msg = gettext_noop("permission denied for column %s");
2723 break;
2724 case OBJECT_CONVERSION:
2725 msg = gettext_noop("permission denied for conversion %s");
2726 break;
2727 case OBJECT_DATABASE:
2728 msg = gettext_noop("permission denied for database %s");
2729 break;
2730 case OBJECT_DOMAIN:
2731 msg = gettext_noop("permission denied for domain %s");
2732 break;
2733 case OBJECT_EVENT_TRIGGER:
2734 msg = gettext_noop("permission denied for event trigger %s");
2735 break;
2736 case OBJECT_EXTENSION:
2737 msg = gettext_noop("permission denied for extension %s");
2738 break;
2739 case OBJECT_FDW:
2740 msg = gettext_noop("permission denied for foreign-data wrapper %s");
2741 break;
2742 case OBJECT_FOREIGN_SERVER:
2743 msg = gettext_noop("permission denied for foreign server %s");
2744 break;
2745 case OBJECT_FOREIGN_TABLE:
2746 msg = gettext_noop("permission denied for foreign table %s");
2747 break;
2748 case OBJECT_FUNCTION:
2749 msg = gettext_noop("permission denied for function %s");
2750 break;
2751 case OBJECT_INDEX:
2752 msg = gettext_noop("permission denied for index %s");
2753 break;
2754 case OBJECT_LANGUAGE:
2755 msg = gettext_noop("permission denied for language %s");
2756 break;
2757 case OBJECT_LARGEOBJECT:
2758 msg = gettext_noop("permission denied for large object %s");
2759 break;
2760 case OBJECT_MATVIEW:
2761 msg = gettext_noop("permission denied for materialized view %s");
2762 break;
2763 case OBJECT_OPCLASS:
2764 msg = gettext_noop("permission denied for operator class %s");
2765 break;
2766 case OBJECT_OPERATOR:
2767 msg = gettext_noop("permission denied for operator %s");
2768 break;
2769 case OBJECT_OPFAMILY:
2770 msg = gettext_noop("permission denied for operator family %s");
2771 break;
2772 case OBJECT_PARAMETER_ACL:
2773 msg = gettext_noop("permission denied for parameter %s");
2774 break;
2775 case OBJECT_POLICY:
2776 msg = gettext_noop("permission denied for policy %s");
2777 break;
2778 case OBJECT_PROCEDURE:
2779 msg = gettext_noop("permission denied for procedure %s");
2780 break;
2781 case OBJECT_PUBLICATION:
2782 msg = gettext_noop("permission denied for publication %s");
2783 break;
2784 case OBJECT_ROUTINE:
2785 msg = gettext_noop("permission denied for routine %s");
2786 break;
2787 case OBJECT_SCHEMA:
2788 msg = gettext_noop("permission denied for schema %s");
2789 break;
2790 case OBJECT_SEQUENCE:
2791 msg = gettext_noop("permission denied for sequence %s");
2792 break;
2793 case OBJECT_STATISTIC_EXT:
2794 msg = gettext_noop("permission denied for statistics object %s");
2795 break;
2796 case OBJECT_SUBSCRIPTION:
2797 msg = gettext_noop("permission denied for subscription %s");
2798 break;
2799 case OBJECT_TABLE:
2800 msg = gettext_noop("permission denied for table %s");
2801 break;
2802 case OBJECT_TABLESPACE:
2803 msg = gettext_noop("permission denied for tablespace %s");
2804 break;
2805 case OBJECT_TSCONFIGURATION:
2806 msg = gettext_noop("permission denied for text search configuration %s");
2807 break;
2808 case OBJECT_TSDICTIONARY:
2809 msg = gettext_noop("permission denied for text search dictionary %s");
2810 break;
2811 case OBJECT_TYPE:
2812 msg = gettext_noop("permission denied for type %s");
2813 break;
2814 case OBJECT_VIEW:
2815 msg = gettext_noop("permission denied for view %s");
2816 break;
2817 /* these currently aren't used */
2818 case OBJECT_ACCESS_METHOD:
2819 case OBJECT_AMOP:
2820 case OBJECT_AMPROC:
2821 case OBJECT_ATTRIBUTE:
2822 case OBJECT_CAST:
2823 case OBJECT_DEFAULT:
2824 case OBJECT_DEFACL:
2825 case OBJECT_DOMCONSTRAINT:
2826 case OBJECT_PUBLICATION_NAMESPACE:
2827 case OBJECT_PUBLICATION_REL:
2828 case OBJECT_ROLE:
2829 case OBJECT_RULE:
2830 case OBJECT_TABCONSTRAINT:
2831 case OBJECT_TRANSFORM:
2832 case OBJECT_TRIGGER:
2833 case OBJECT_TSPARSER:
2834 case OBJECT_TSTEMPLATE:
2835 case OBJECT_USER_MAPPING:
2836 elog(ERROR, "unsupported object type: %d", objtype);
2839 ereport(ERROR,
2840 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2841 errmsg(msg, objectname)));
2842 break;
2844 case ACLCHECK_NOT_OWNER:
2846 const char *msg = "???";
2848 switch (objtype)
2850 case OBJECT_AGGREGATE:
2851 msg = gettext_noop("must be owner of aggregate %s");
2852 break;
2853 case OBJECT_COLLATION:
2854 msg = gettext_noop("must be owner of collation %s");
2855 break;
2856 case OBJECT_CONVERSION:
2857 msg = gettext_noop("must be owner of conversion %s");
2858 break;
2859 case OBJECT_DATABASE:
2860 msg = gettext_noop("must be owner of database %s");
2861 break;
2862 case OBJECT_DOMAIN:
2863 msg = gettext_noop("must be owner of domain %s");
2864 break;
2865 case OBJECT_EVENT_TRIGGER:
2866 msg = gettext_noop("must be owner of event trigger %s");
2867 break;
2868 case OBJECT_EXTENSION:
2869 msg = gettext_noop("must be owner of extension %s");
2870 break;
2871 case OBJECT_FDW:
2872 msg = gettext_noop("must be owner of foreign-data wrapper %s");
2873 break;
2874 case OBJECT_FOREIGN_SERVER:
2875 msg = gettext_noop("must be owner of foreign server %s");
2876 break;
2877 case OBJECT_FOREIGN_TABLE:
2878 msg = gettext_noop("must be owner of foreign table %s");
2879 break;
2880 case OBJECT_FUNCTION:
2881 msg = gettext_noop("must be owner of function %s");
2882 break;
2883 case OBJECT_INDEX:
2884 msg = gettext_noop("must be owner of index %s");
2885 break;
2886 case OBJECT_LANGUAGE:
2887 msg = gettext_noop("must be owner of language %s");
2888 break;
2889 case OBJECT_LARGEOBJECT:
2890 msg = gettext_noop("must be owner of large object %s");
2891 break;
2892 case OBJECT_MATVIEW:
2893 msg = gettext_noop("must be owner of materialized view %s");
2894 break;
2895 case OBJECT_OPCLASS:
2896 msg = gettext_noop("must be owner of operator class %s");
2897 break;
2898 case OBJECT_OPERATOR:
2899 msg = gettext_noop("must be owner of operator %s");
2900 break;
2901 case OBJECT_OPFAMILY:
2902 msg = gettext_noop("must be owner of operator family %s");
2903 break;
2904 case OBJECT_PROCEDURE:
2905 msg = gettext_noop("must be owner of procedure %s");
2906 break;
2907 case OBJECT_PUBLICATION:
2908 msg = gettext_noop("must be owner of publication %s");
2909 break;
2910 case OBJECT_ROUTINE:
2911 msg = gettext_noop("must be owner of routine %s");
2912 break;
2913 case OBJECT_SEQUENCE:
2914 msg = gettext_noop("must be owner of sequence %s");
2915 break;
2916 case OBJECT_SUBSCRIPTION:
2917 msg = gettext_noop("must be owner of subscription %s");
2918 break;
2919 case OBJECT_TABLE:
2920 msg = gettext_noop("must be owner of table %s");
2921 break;
2922 case OBJECT_TYPE:
2923 msg = gettext_noop("must be owner of type %s");
2924 break;
2925 case OBJECT_VIEW:
2926 msg = gettext_noop("must be owner of view %s");
2927 break;
2928 case OBJECT_SCHEMA:
2929 msg = gettext_noop("must be owner of schema %s");
2930 break;
2931 case OBJECT_STATISTIC_EXT:
2932 msg = gettext_noop("must be owner of statistics object %s");
2933 break;
2934 case OBJECT_TABLESPACE:
2935 msg = gettext_noop("must be owner of tablespace %s");
2936 break;
2937 case OBJECT_TSCONFIGURATION:
2938 msg = gettext_noop("must be owner of text search configuration %s");
2939 break;
2940 case OBJECT_TSDICTIONARY:
2941 msg = gettext_noop("must be owner of text search dictionary %s");
2942 break;
2945 * Special cases: For these, the error message talks
2946 * about "relation", because that's where the
2947 * ownership is attached. See also
2948 * check_object_ownership().
2950 case OBJECT_COLUMN:
2951 case OBJECT_POLICY:
2952 case OBJECT_RULE:
2953 case OBJECT_TABCONSTRAINT:
2954 case OBJECT_TRIGGER:
2955 msg = gettext_noop("must be owner of relation %s");
2956 break;
2957 /* these currently aren't used */
2958 case OBJECT_ACCESS_METHOD:
2959 case OBJECT_AMOP:
2960 case OBJECT_AMPROC:
2961 case OBJECT_ATTRIBUTE:
2962 case OBJECT_CAST:
2963 case OBJECT_DEFAULT:
2964 case OBJECT_DEFACL:
2965 case OBJECT_DOMCONSTRAINT:
2966 case OBJECT_PARAMETER_ACL:
2967 case OBJECT_PUBLICATION_NAMESPACE:
2968 case OBJECT_PUBLICATION_REL:
2969 case OBJECT_ROLE:
2970 case OBJECT_TRANSFORM:
2971 case OBJECT_TSPARSER:
2972 case OBJECT_TSTEMPLATE:
2973 case OBJECT_USER_MAPPING:
2974 elog(ERROR, "unsupported object type: %d", objtype);
2977 ereport(ERROR,
2978 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2979 errmsg(msg, objectname)));
2980 break;
2982 default:
2983 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2984 break;
2989 void
2990 aclcheck_error_col(AclResult aclerr, ObjectType objtype,
2991 const char *objectname, const char *colname)
2993 switch (aclerr)
2995 case ACLCHECK_OK:
2996 /* no error, so return to caller */
2997 break;
2998 case ACLCHECK_NO_PRIV:
2999 ereport(ERROR,
3000 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3001 errmsg("permission denied for column \"%s\" of relation \"%s\"",
3002 colname, objectname)));
3003 break;
3004 case ACLCHECK_NOT_OWNER:
3005 /* relation msg is OK since columns don't have separate owners */
3006 aclcheck_error(aclerr, objtype, objectname);
3007 break;
3008 default:
3009 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3010 break;
3016 * Special common handling for types: use element type instead of array type,
3017 * and format nicely
3019 void
3020 aclcheck_error_type(AclResult aclerr, Oid typeOid)
3022 Oid element_type = get_element_type(typeOid);
3024 aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
3029 * Relay for the various pg_*_mask routines depending on object kind
3031 static AclMode
3032 pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
3033 AclMode mask, AclMaskHow how)
3035 switch (objtype)
3037 case OBJECT_COLUMN:
3038 return
3039 pg_class_aclmask(object_oid, roleid, mask, how) |
3040 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
3041 case OBJECT_TABLE:
3042 case OBJECT_SEQUENCE:
3043 return pg_class_aclmask(object_oid, roleid, mask, how);
3044 case OBJECT_DATABASE:
3045 return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
3046 case OBJECT_FUNCTION:
3047 return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
3048 case OBJECT_LANGUAGE:
3049 return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
3050 case OBJECT_LARGEOBJECT:
3051 return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3052 mask, how, NULL);
3053 case OBJECT_PARAMETER_ACL:
3054 return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
3055 case OBJECT_SCHEMA:
3056 return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
3057 case OBJECT_STATISTIC_EXT:
3058 elog(ERROR, "grantable rights not supported for statistics objects");
3059 /* not reached, but keep compiler quiet */
3060 return ACL_NO_RIGHTS;
3061 case OBJECT_TABLESPACE:
3062 return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3063 case OBJECT_FDW:
3064 return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3065 case OBJECT_FOREIGN_SERVER:
3066 return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3067 case OBJECT_EVENT_TRIGGER:
3068 elog(ERROR, "grantable rights not supported for event triggers");
3069 /* not reached, but keep compiler quiet */
3070 return ACL_NO_RIGHTS;
3071 case OBJECT_TYPE:
3072 return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3073 default:
3074 elog(ERROR, "unrecognized object type: %d",
3075 (int) objtype);
3076 /* not reached, but keep compiler quiet */
3077 return ACL_NO_RIGHTS;
3082 /* ****************************************************************
3083 * Exported routines for examining a user's privileges for various objects
3085 * See aclmask() for a description of the common API for these functions.
3087 * Note: we give lookup failure the full ereport treatment because the
3088 * has_xxx_privilege() family of functions allow users to pass any random
3089 * OID to these functions.
3090 * ****************************************************************
3094 * Generic routine for examining a user's privileges for an object
3096 static AclMode
3097 object_aclmask(Oid classid, Oid objectid, Oid roleid,
3098 AclMode mask, AclMaskHow how)
3100 return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3104 * Generic routine for examining a user's privileges for an object,
3105 * with is_missing
3107 static AclMode
3108 object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
3109 AclMode mask, AclMaskHow how,
3110 bool *is_missing)
3112 int cacheid;
3113 AclMode result;
3114 HeapTuple tuple;
3115 Datum aclDatum;
3116 bool isNull;
3117 Acl *acl;
3118 Oid ownerId;
3120 /* Special cases */
3121 switch (classid)
3123 case NamespaceRelationId:
3124 return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
3125 is_missing);
3126 case TypeRelationId:
3127 return pg_type_aclmask_ext(objectid, roleid, mask, how,
3128 is_missing);
3131 /* Even more special cases */
3132 Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3133 Assert(classid != LargeObjectMetadataRelationId); /* should use
3134 * pg_largeobject_acl* */
3136 /* Superusers bypass all permission checking. */
3137 if (superuser_arg(roleid))
3138 return mask;
3141 * Get the object's ACL from its catalog
3144 cacheid = get_object_catcache_oid(classid);
3146 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3147 if (!HeapTupleIsValid(tuple))
3149 if (is_missing != NULL)
3151 /* return "no privileges" instead of throwing an error */
3152 *is_missing = true;
3153 return 0;
3155 else
3156 ereport(ERROR,
3157 (errcode(ERRCODE_UNDEFINED_OBJECT),
3158 errmsg("%s with OID %u does not exist",
3159 get_object_class_descr(classid), objectid)));
3162 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3163 tuple,
3164 get_object_attnum_owner(classid)));
3166 aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3167 &isNull);
3168 if (isNull)
3170 /* No ACL, so build default ACL */
3171 acl = acldefault(get_object_type(classid, objectid), ownerId);
3172 aclDatum = (Datum) 0;
3174 else
3176 /* detoast ACL if necessary */
3177 acl = DatumGetAclP(aclDatum);
3180 result = aclmask(acl, roleid, ownerId, mask, how);
3182 /* if we have a detoasted copy, free it */
3183 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3184 pfree(acl);
3186 ReleaseSysCache(tuple);
3188 return result;
3192 * Routine for examining a user's privileges for a column
3194 * Note: this considers only privileges granted specifically on the column.
3195 * It is caller's responsibility to take relation-level privileges into account
3196 * as appropriate. (For the same reason, we have no special case for
3197 * superuser-ness here.)
3199 static AclMode
3200 pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
3201 AclMode mask, AclMaskHow how)
3203 return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3204 mask, how, NULL);
3208 * Routine for examining a user's privileges for a column, with is_missing
3210 static AclMode
3211 pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid,
3212 AclMode mask, AclMaskHow how, bool *is_missing)
3214 AclMode result;
3215 HeapTuple classTuple;
3216 HeapTuple attTuple;
3217 Form_pg_class classForm;
3218 Form_pg_attribute attributeForm;
3219 Datum aclDatum;
3220 bool isNull;
3221 Acl *acl;
3222 Oid ownerId;
3225 * First, get the column's ACL from its pg_attribute entry
3227 attTuple = SearchSysCache2(ATTNUM,
3228 ObjectIdGetDatum(table_oid),
3229 Int16GetDatum(attnum));
3230 if (!HeapTupleIsValid(attTuple))
3232 if (is_missing != NULL)
3234 /* return "no privileges" instead of throwing an error */
3235 *is_missing = true;
3236 return 0;
3238 else
3239 ereport(ERROR,
3240 (errcode(ERRCODE_UNDEFINED_COLUMN),
3241 errmsg("attribute %d of relation with OID %u does not exist",
3242 attnum, table_oid)));
3245 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3247 /* Check dropped columns, too */
3248 if (attributeForm->attisdropped)
3250 if (is_missing != NULL)
3252 /* return "no privileges" instead of throwing an error */
3253 *is_missing = true;
3254 ReleaseSysCache(attTuple);
3255 return 0;
3257 else
3258 ereport(ERROR,
3259 (errcode(ERRCODE_UNDEFINED_COLUMN),
3260 errmsg("attribute %d of relation with OID %u does not exist",
3261 attnum, table_oid)));
3264 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3265 &isNull);
3268 * Here we hard-wire knowledge that the default ACL for a column grants no
3269 * privileges, so that we can fall out quickly in the very common case
3270 * where attacl is null.
3272 if (isNull)
3274 ReleaseSysCache(attTuple);
3275 return 0;
3279 * Must get the relation's ownerId from pg_class. Since we already found
3280 * a pg_attribute entry, the only likely reason for this to fail is that a
3281 * concurrent DROP of the relation committed since then (which could only
3282 * happen if we don't have lock on the relation). Treat that similarly to
3283 * not finding the attribute entry.
3285 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3286 if (!HeapTupleIsValid(classTuple))
3288 ReleaseSysCache(attTuple);
3289 if (is_missing != NULL)
3291 /* return "no privileges" instead of throwing an error */
3292 *is_missing = true;
3293 return 0;
3295 else
3296 ereport(ERROR,
3297 (errcode(ERRCODE_UNDEFINED_TABLE),
3298 errmsg("relation with OID %u does not exist",
3299 table_oid)));
3301 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3303 ownerId = classForm->relowner;
3305 ReleaseSysCache(classTuple);
3307 /* detoast column's ACL if necessary */
3308 acl = DatumGetAclP(aclDatum);
3310 result = aclmask(acl, roleid, ownerId, mask, how);
3312 /* if we have a detoasted copy, free it */
3313 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3314 pfree(acl);
3316 ReleaseSysCache(attTuple);
3318 return result;
3322 * Exported routine for examining a user's privileges for a table
3324 AclMode
3325 pg_class_aclmask(Oid table_oid, Oid roleid,
3326 AclMode mask, AclMaskHow how)
3328 return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3332 * Routine for examining a user's privileges for a table, with is_missing
3334 static AclMode
3335 pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
3336 AclMaskHow how, bool *is_missing)
3338 AclMode result;
3339 HeapTuple tuple;
3340 Form_pg_class classForm;
3341 Datum aclDatum;
3342 bool isNull;
3343 Acl *acl;
3344 Oid ownerId;
3347 * Must get the relation's tuple from pg_class
3349 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3350 if (!HeapTupleIsValid(tuple))
3352 if (is_missing != NULL)
3354 /* return "no privileges" instead of throwing an error */
3355 *is_missing = true;
3356 return 0;
3358 else
3359 ereport(ERROR,
3360 (errcode(ERRCODE_UNDEFINED_TABLE),
3361 errmsg("relation with OID %u does not exist",
3362 table_oid)));
3365 classForm = (Form_pg_class) GETSTRUCT(tuple);
3368 * Deny anyone permission to update a system catalog unless
3369 * pg_authid.rolsuper is set.
3371 * As of 7.4 we have some updatable system views; those shouldn't be
3372 * protected in this way. Assume the view rules can take care of
3373 * themselves. ACL_USAGE is if we ever have system sequences.
3375 if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3376 IsSystemClass(table_oid, classForm) &&
3377 classForm->relkind != RELKIND_VIEW &&
3378 !superuser_arg(roleid))
3379 mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
3382 * Otherwise, superusers bypass all permission-checking.
3384 if (superuser_arg(roleid))
3386 ReleaseSysCache(tuple);
3387 return mask;
3391 * Normal case: get the relation's ACL from pg_class
3393 ownerId = classForm->relowner;
3395 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3396 &isNull);
3397 if (isNull)
3399 /* No ACL, so build default ACL */
3400 switch (classForm->relkind)
3402 case RELKIND_SEQUENCE:
3403 acl = acldefault(OBJECT_SEQUENCE, ownerId);
3404 break;
3405 default:
3406 acl = acldefault(OBJECT_TABLE, ownerId);
3407 break;
3409 aclDatum = (Datum) 0;
3411 else
3413 /* detoast rel's ACL if necessary */
3414 acl = DatumGetAclP(aclDatum);
3417 result = aclmask(acl, roleid, ownerId, mask, how);
3419 /* if we have a detoasted copy, free it */
3420 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3421 pfree(acl);
3423 ReleaseSysCache(tuple);
3426 * Check if ACL_SELECT is being checked and, if so, and not set already as
3427 * part of the result, then check if the user is a member of the
3428 * pg_read_all_data role, which allows read access to all relations.
3430 if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
3431 has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
3432 result |= ACL_SELECT;
3435 * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3436 * so, and not set already as part of the result, then check if the user
3437 * is a member of the pg_write_all_data role, which allows
3438 * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3439 * which requires superuser, see above).
3441 if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
3442 !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
3443 has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
3444 result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
3446 return result;
3450 * Routine for examining a user's privileges for a configuration
3451 * parameter (GUC), identified by GUC name.
3453 static AclMode
3454 pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
3456 AclMode result;
3457 char *parname;
3458 text *partext;
3459 HeapTuple tuple;
3461 /* Superusers bypass all permission checking. */
3462 if (superuser_arg(roleid))
3463 return mask;
3465 /* Convert name to the form it should have in pg_parameter_acl... */
3466 parname = convert_GUC_name_for_parameter_acl(name);
3467 partext = cstring_to_text(parname);
3469 /* ... and look it up */
3470 tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3472 if (!HeapTupleIsValid(tuple))
3474 /* If no entry, GUC has no permissions for non-superusers */
3475 result = ACL_NO_RIGHTS;
3477 else
3479 Datum aclDatum;
3480 bool isNull;
3481 Acl *acl;
3483 aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3484 Anum_pg_parameter_acl_paracl,
3485 &isNull);
3486 if (isNull)
3488 /* No ACL, so build default ACL */
3489 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3490 aclDatum = (Datum) 0;
3492 else
3494 /* detoast ACL if necessary */
3495 acl = DatumGetAclP(aclDatum);
3498 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3500 /* if we have a detoasted copy, free it */
3501 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3502 pfree(acl);
3504 ReleaseSysCache(tuple);
3507 pfree(parname);
3508 pfree(partext);
3510 return result;
3514 * Routine for examining a user's privileges for a configuration
3515 * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
3517 static AclMode
3518 pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
3520 AclMode result;
3521 HeapTuple tuple;
3522 Datum aclDatum;
3523 bool isNull;
3524 Acl *acl;
3526 /* Superusers bypass all permission checking. */
3527 if (superuser_arg(roleid))
3528 return mask;
3530 /* Get the ACL from pg_parameter_acl */
3531 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3532 if (!HeapTupleIsValid(tuple))
3533 ereport(ERROR,
3534 (errcode(ERRCODE_UNDEFINED_OBJECT),
3535 errmsg("parameter ACL with OID %u does not exist",
3536 acl_oid)));
3538 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3539 Anum_pg_parameter_acl_paracl,
3540 &isNull);
3541 if (isNull)
3543 /* No ACL, so build default ACL */
3544 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3545 aclDatum = (Datum) 0;
3547 else
3549 /* detoast ACL if necessary */
3550 acl = DatumGetAclP(aclDatum);
3553 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3555 /* if we have a detoasted copy, free it */
3556 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3557 pfree(acl);
3559 ReleaseSysCache(tuple);
3561 return result;
3565 * Routine for examining a user's privileges for a largeobject
3567 * When a large object is opened for reading, it is opened relative to the
3568 * caller's snapshot, but when it is opened for writing, a current
3569 * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
3570 * takes a snapshot argument so that the permissions check can be made
3571 * relative to the same snapshot that will be used to read the underlying
3572 * data. The caller will actually pass NULL for an instantaneous MVCC
3573 * snapshot, since all we do with the snapshot argument is pass it through
3574 * to systable_beginscan().
3576 static AclMode
3577 pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
3578 AclMode mask, AclMaskHow how,
3579 Snapshot snapshot)
3581 AclMode result;
3582 Relation pg_lo_meta;
3583 ScanKeyData entry[1];
3584 SysScanDesc scan;
3585 HeapTuple tuple;
3586 Datum aclDatum;
3587 bool isNull;
3588 Acl *acl;
3589 Oid ownerId;
3591 /* Superusers bypass all permission checking. */
3592 if (superuser_arg(roleid))
3593 return mask;
3596 * Get the largeobject's ACL from pg_largeobject_metadata
3598 pg_lo_meta = table_open(LargeObjectMetadataRelationId,
3599 AccessShareLock);
3601 ScanKeyInit(&entry[0],
3602 Anum_pg_largeobject_metadata_oid,
3603 BTEqualStrategyNumber, F_OIDEQ,
3604 ObjectIdGetDatum(lobj_oid));
3606 scan = systable_beginscan(pg_lo_meta,
3607 LargeObjectMetadataOidIndexId, true,
3608 snapshot, 1, entry);
3610 tuple = systable_getnext(scan);
3611 if (!HeapTupleIsValid(tuple))
3612 ereport(ERROR,
3613 (errcode(ERRCODE_UNDEFINED_OBJECT),
3614 errmsg("large object %u does not exist", lobj_oid)));
3616 ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
3618 aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
3619 RelationGetDescr(pg_lo_meta), &isNull);
3621 if (isNull)
3623 /* No ACL, so build default ACL */
3624 acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
3625 aclDatum = (Datum) 0;
3627 else
3629 /* detoast ACL if necessary */
3630 acl = DatumGetAclP(aclDatum);
3633 result = aclmask(acl, roleid, ownerId, mask, how);
3635 /* if we have a detoasted copy, free it */
3636 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3637 pfree(acl);
3639 systable_endscan(scan);
3641 table_close(pg_lo_meta, AccessShareLock);
3643 return result;
3647 * Routine for examining a user's privileges for a namespace, with is_missing
3649 static AclMode
3650 pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
3651 AclMode mask, AclMaskHow how,
3652 bool *is_missing)
3654 AclMode result;
3655 HeapTuple tuple;
3656 Datum aclDatum;
3657 bool isNull;
3658 Acl *acl;
3659 Oid ownerId;
3661 /* Superusers bypass all permission checking. */
3662 if (superuser_arg(roleid))
3663 return mask;
3666 * If we have been assigned this namespace as a temp namespace, check to
3667 * make sure we have CREATE TEMP permission on the database, and if so act
3668 * as though we have all standard (but not GRANT OPTION) permissions on
3669 * the namespace. If we don't have CREATE TEMP, act as though we have
3670 * only USAGE (and not CREATE) rights.
3672 * This may seem redundant given the check in InitTempTableNamespace, but
3673 * it really isn't since current user ID may have changed since then. The
3674 * upshot of this behavior is that a SECURITY DEFINER function can create
3675 * temp tables that can then be accessed (if permission is granted) by
3676 * code in the same session that doesn't have permissions to create temp
3677 * tables.
3679 * XXX Would it be safe to ereport a special error message as
3680 * InitTempTableNamespace does? Returning zero here means we'll get a
3681 * generic "permission denied for schema pg_temp_N" message, which is not
3682 * remarkably user-friendly.
3684 if (isTempNamespace(nsp_oid))
3686 if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
3687 ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
3688 return mask & ACL_ALL_RIGHTS_SCHEMA;
3689 else
3690 return mask & ACL_USAGE;
3694 * Get the schema's ACL from pg_namespace
3696 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
3697 if (!HeapTupleIsValid(tuple))
3699 if (is_missing != NULL)
3701 /* return "no privileges" instead of throwing an error */
3702 *is_missing = true;
3703 return 0;
3705 else
3706 ereport(ERROR,
3707 (errcode(ERRCODE_UNDEFINED_SCHEMA),
3708 errmsg("schema with OID %u does not exist", nsp_oid)));
3711 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3713 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
3714 &isNull);
3715 if (isNull)
3717 /* No ACL, so build default ACL */
3718 acl = acldefault(OBJECT_SCHEMA, ownerId);
3719 aclDatum = (Datum) 0;
3721 else
3723 /* detoast ACL if necessary */
3724 acl = DatumGetAclP(aclDatum);
3727 result = aclmask(acl, roleid, ownerId, mask, how);
3729 /* if we have a detoasted copy, free it */
3730 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3731 pfree(acl);
3733 ReleaseSysCache(tuple);
3736 * Check if ACL_USAGE is being checked and, if so, and not set already as
3737 * part of the result, then check if the user is a member of the
3738 * pg_read_all_data or pg_write_all_data roles, which allow usage access
3739 * to all schemas.
3741 if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
3742 (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
3743 has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
3744 result |= ACL_USAGE;
3745 return result;
3749 * Routine for examining a user's privileges for a type, with is_missing
3751 static AclMode
3752 pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
3753 bool *is_missing)
3755 AclMode result;
3756 HeapTuple tuple;
3757 Form_pg_type typeForm;
3758 Datum aclDatum;
3759 bool isNull;
3760 Acl *acl;
3761 Oid ownerId;
3763 /* Bypass permission checks for superusers */
3764 if (superuser_arg(roleid))
3765 return mask;
3768 * Must get the type's tuple from pg_type
3770 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3771 if (!HeapTupleIsValid(tuple))
3773 if (is_missing != NULL)
3775 /* return "no privileges" instead of throwing an error */
3776 *is_missing = true;
3777 return 0;
3779 else
3780 ereport(ERROR,
3781 (errcode(ERRCODE_UNDEFINED_OBJECT),
3782 errmsg("type with OID %u does not exist",
3783 type_oid)));
3785 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3788 * "True" array types don't manage permissions of their own; consult the
3789 * element type instead.
3791 if (IsTrueArrayType(typeForm))
3793 Oid elttype_oid = typeForm->typelem;
3795 ReleaseSysCache(tuple);
3797 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3798 if (!HeapTupleIsValid(tuple))
3800 if (is_missing != NULL)
3802 /* return "no privileges" instead of throwing an error */
3803 *is_missing = true;
3804 return 0;
3806 else
3807 ereport(ERROR,
3808 (errcode(ERRCODE_UNDEFINED_OBJECT),
3809 errmsg("type with OID %u does not exist",
3810 elttype_oid)));
3812 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3816 * Likewise, multirange types don't manage their own permissions; consult
3817 * the associated range type. (Note we must do this after the array step
3818 * to get the right answer for arrays of multiranges.)
3820 if (typeForm->typtype == TYPTYPE_MULTIRANGE)
3822 Oid rangetype = get_multirange_range(typeForm->oid);
3824 ReleaseSysCache(tuple);
3826 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
3827 if (!HeapTupleIsValid(tuple))
3829 if (is_missing != NULL)
3831 /* return "no privileges" instead of throwing an error */
3832 *is_missing = true;
3833 return 0;
3835 else
3836 ereport(ERROR,
3837 (errcode(ERRCODE_UNDEFINED_OBJECT),
3838 errmsg("type with OID %u does not exist",
3839 rangetype)));
3841 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3845 * Now get the type's owner and ACL from the tuple
3847 ownerId = typeForm->typowner;
3849 aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3850 Anum_pg_type_typacl, &isNull);
3851 if (isNull)
3853 /* No ACL, so build default ACL */
3854 acl = acldefault(OBJECT_TYPE, ownerId);
3855 aclDatum = (Datum) 0;
3857 else
3859 /* detoast rel's ACL if necessary */
3860 acl = DatumGetAclP(aclDatum);
3863 result = aclmask(acl, roleid, ownerId, mask, how);
3865 /* if we have a detoasted copy, free it */
3866 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3867 pfree(acl);
3869 ReleaseSysCache(tuple);
3871 return result;
3875 * Exported generic routine for checking a user's access privileges to an object
3877 AclResult
3878 object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
3880 return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3884 * Exported generic routine for checking a user's access privileges to an
3885 * object, with is_missing
3887 AclResult
3888 object_aclcheck_ext(Oid classid, Oid objectid,
3889 Oid roleid, AclMode mode,
3890 bool *is_missing)
3892 if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
3893 is_missing) != 0)
3894 return ACLCHECK_OK;
3895 else
3896 return ACLCHECK_NO_PRIV;
3900 * Exported routine for checking a user's access privileges to a column
3902 * Returns ACLCHECK_OK if the user has any of the privileges identified by
3903 * 'mode'; otherwise returns a suitable error code (in practice, always
3904 * ACLCHECK_NO_PRIV).
3906 * As with pg_attribute_aclmask, only privileges granted directly on the
3907 * column are considered here.
3909 AclResult
3910 pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
3911 Oid roleid, AclMode mode)
3913 return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3918 * Exported routine for checking a user's access privileges to a column,
3919 * with is_missing
3921 AclResult
3922 pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
3923 Oid roleid, AclMode mode, bool *is_missing)
3925 if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3926 ACLMASK_ANY, is_missing) != 0)
3927 return ACLCHECK_OK;
3928 else
3929 return ACLCHECK_NO_PRIV;
3933 * Exported routine for checking a user's access privileges to any/all columns
3935 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
3936 * privileges identified by 'mode' on any non-dropped column in the relation;
3937 * otherwise returns a suitable error code (in practice, always
3938 * ACLCHECK_NO_PRIV).
3940 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
3941 * privileges identified by 'mode' on each non-dropped column in the relation
3942 * (and there must be at least one such column); otherwise returns a suitable
3943 * error code (in practice, always ACLCHECK_NO_PRIV).
3945 * As with pg_attribute_aclmask, only privileges granted directly on the
3946 * column(s) are considered here.
3948 * Note: system columns are not considered here; there are cases where that
3949 * might be appropriate but there are also cases where it wouldn't.
3951 AclResult
3952 pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
3953 AclMaskHow how)
3955 return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3959 * Exported routine for checking a user's access privileges to any/all columns,
3960 * with is_missing
3962 AclResult
3963 pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid,
3964 AclMode mode, AclMaskHow how,
3965 bool *is_missing)
3967 AclResult result;
3968 HeapTuple classTuple;
3969 Form_pg_class classForm;
3970 Oid ownerId;
3971 AttrNumber nattrs;
3972 AttrNumber curr_att;
3975 * Must fetch pg_class row to get owner ID and number of attributes.
3977 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3978 if (!HeapTupleIsValid(classTuple))
3980 if (is_missing != NULL)
3982 /* return "no privileges" instead of throwing an error */
3983 *is_missing = true;
3984 return ACLCHECK_NO_PRIV;
3986 else
3987 ereport(ERROR,
3988 (errcode(ERRCODE_UNDEFINED_TABLE),
3989 errmsg("relation with OID %u does not exist",
3990 table_oid)));
3992 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3994 ownerId = classForm->relowner;
3995 nattrs = classForm->relnatts;
3997 ReleaseSysCache(classTuple);
4000 * Initialize result in case there are no non-dropped columns. We want to
4001 * report failure in such cases for either value of 'how'.
4003 result = ACLCHECK_NO_PRIV;
4005 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4007 HeapTuple attTuple;
4008 Datum aclDatum;
4009 bool isNull;
4010 Acl *acl;
4011 AclMode attmask;
4013 attTuple = SearchSysCache2(ATTNUM,
4014 ObjectIdGetDatum(table_oid),
4015 Int16GetDatum(curr_att));
4018 * Lookup failure probably indicates that the table was just dropped,
4019 * but we'll treat it the same as a dropped column rather than
4020 * throwing error.
4022 if (!HeapTupleIsValid(attTuple))
4023 continue;
4025 /* ignore dropped columns */
4026 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4028 ReleaseSysCache(attTuple);
4029 continue;
4032 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
4033 &isNull);
4036 * Here we hard-wire knowledge that the default ACL for a column
4037 * grants no privileges, so that we can fall out quickly in the very
4038 * common case where attacl is null.
4040 if (isNull)
4041 attmask = 0;
4042 else
4044 /* detoast column's ACL if necessary */
4045 acl = DatumGetAclP(aclDatum);
4047 attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
4049 /* if we have a detoasted copy, free it */
4050 if ((Pointer) acl != DatumGetPointer(aclDatum))
4051 pfree(acl);
4054 ReleaseSysCache(attTuple);
4056 if (attmask != 0)
4058 result = ACLCHECK_OK;
4059 if (how == ACLMASK_ANY)
4060 break; /* succeed on any success */
4062 else
4064 result = ACLCHECK_NO_PRIV;
4065 if (how == ACLMASK_ALL)
4066 break; /* fail on any failure */
4070 return result;
4074 * Exported routine for checking a user's access privileges to a table
4076 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4077 * 'mode'; otherwise returns a suitable error code (in practice, always
4078 * ACLCHECK_NO_PRIV).
4080 AclResult
4081 pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
4083 return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
4087 * Exported routine for checking a user's access privileges to a table,
4088 * with is_missing
4090 AclResult
4091 pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
4092 AclMode mode, bool *is_missing)
4094 if (pg_class_aclmask_ext(table_oid, roleid, mode,
4095 ACLMASK_ANY, is_missing) != 0)
4096 return ACLCHECK_OK;
4097 else
4098 return ACLCHECK_NO_PRIV;
4102 * Exported routine for checking a user's access privileges to a configuration
4103 * parameter (GUC), identified by GUC name.
4105 AclResult
4106 pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
4108 if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4109 return ACLCHECK_OK;
4110 else
4111 return ACLCHECK_NO_PRIV;
4115 * Exported routine for checking a user's access privileges to a largeobject
4117 AclResult
4118 pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
4119 Snapshot snapshot)
4121 if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4122 ACLMASK_ANY, snapshot) != 0)
4123 return ACLCHECK_OK;
4124 else
4125 return ACLCHECK_NO_PRIV;
4129 * Generic ownership check for an object
4131 bool
4132 object_ownercheck(Oid classid, Oid objectid, Oid roleid)
4134 int cacheid;
4135 Oid ownerId;
4137 /* Superusers bypass all permission checking. */
4138 if (superuser_arg(roleid))
4139 return true;
4141 /* For large objects, the catalog to consult is pg_largeobject_metadata */
4142 if (classid == LargeObjectRelationId)
4143 classid = LargeObjectMetadataRelationId;
4145 cacheid = get_object_catcache_oid(classid);
4146 if (cacheid != -1)
4148 /* we can get the object's tuple from the syscache */
4149 HeapTuple tuple;
4151 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4152 if (!HeapTupleIsValid(tuple))
4153 ereport(ERROR,
4154 (errcode(ERRCODE_UNDEFINED_OBJECT),
4155 errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
4157 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4158 tuple,
4159 get_object_attnum_owner(classid)));
4160 ReleaseSysCache(tuple);
4162 else
4164 /* for catalogs without an appropriate syscache */
4165 Relation rel;
4166 ScanKeyData entry[1];
4167 SysScanDesc scan;
4168 HeapTuple tuple;
4169 bool isnull;
4171 rel = table_open(classid, AccessShareLock);
4173 ScanKeyInit(&entry[0],
4174 get_object_attnum_oid(classid),
4175 BTEqualStrategyNumber, F_OIDEQ,
4176 ObjectIdGetDatum(objectid));
4178 scan = systable_beginscan(rel,
4179 get_object_oid_index(classid), true,
4180 NULL, 1, entry);
4182 tuple = systable_getnext(scan);
4183 if (!HeapTupleIsValid(tuple))
4184 ereport(ERROR,
4185 (errcode(ERRCODE_UNDEFINED_OBJECT),
4186 errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
4188 ownerId = DatumGetObjectId(heap_getattr(tuple,
4189 get_object_attnum_owner(classid),
4190 RelationGetDescr(rel),
4191 &isnull));
4192 Assert(!isnull);
4194 systable_endscan(scan);
4195 table_close(rel, AccessShareLock);
4198 return has_privs_of_role(roleid, ownerId);
4202 * Check whether specified role has CREATEROLE privilege (or is a superuser)
4204 * Note: roles do not have owners per se; instead we use this test in
4205 * places where an ownership-like permissions test is needed for a role.
4206 * Be sure to apply it to the role trying to do the operation, not the
4207 * role being operated on! Also note that this generally should not be
4208 * considered enough privilege if the target role is a superuser.
4209 * (We don't handle that consideration here because we want to give a
4210 * separate error message for such cases, so the caller has to deal with it.)
4212 bool
4213 has_createrole_privilege(Oid roleid)
4215 bool result = false;
4216 HeapTuple utup;
4218 /* Superusers bypass all permission checking. */
4219 if (superuser_arg(roleid))
4220 return true;
4222 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4223 if (HeapTupleIsValid(utup))
4225 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4226 ReleaseSysCache(utup);
4228 return result;
4231 bool
4232 has_bypassrls_privilege(Oid roleid)
4234 bool result = false;
4235 HeapTuple utup;
4237 /* Superusers bypass all permission checking. */
4238 if (superuser_arg(roleid))
4239 return true;
4241 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4242 if (HeapTupleIsValid(utup))
4244 result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4245 ReleaseSysCache(utup);
4247 return result;
4251 * Fetch pg_default_acl entry for given role, namespace and object type
4252 * (object type must be given in pg_default_acl's encoding).
4253 * Returns NULL if no such entry.
4255 static Acl *
4256 get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
4258 Acl *result = NULL;
4259 HeapTuple tuple;
4261 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4262 ObjectIdGetDatum(roleId),
4263 ObjectIdGetDatum(nsp_oid),
4264 CharGetDatum(objtype));
4266 if (HeapTupleIsValid(tuple))
4268 Datum aclDatum;
4269 bool isNull;
4271 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4272 Anum_pg_default_acl_defaclacl,
4273 &isNull);
4274 if (!isNull)
4275 result = DatumGetAclPCopy(aclDatum);
4276 ReleaseSysCache(tuple);
4279 return result;
4283 * Get default permissions for newly created object within given schema
4285 * Returns NULL if built-in system defaults should be used.
4287 * If the result is not NULL, caller must call recordDependencyOnNewAcl
4288 * once the OID of the new object is known.
4290 Acl *
4291 get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
4293 Acl *result;
4294 Acl *glob_acl;
4295 Acl *schema_acl;
4296 Acl *def_acl;
4297 char defaclobjtype;
4300 * Use NULL during bootstrap, since pg_default_acl probably isn't there
4301 * yet.
4303 if (IsBootstrapProcessingMode())
4304 return NULL;
4306 /* Check if object type is supported in pg_default_acl */
4307 switch (objtype)
4309 case OBJECT_TABLE:
4310 defaclobjtype = DEFACLOBJ_RELATION;
4311 break;
4313 case OBJECT_SEQUENCE:
4314 defaclobjtype = DEFACLOBJ_SEQUENCE;
4315 break;
4317 case OBJECT_FUNCTION:
4318 defaclobjtype = DEFACLOBJ_FUNCTION;
4319 break;
4321 case OBJECT_TYPE:
4322 defaclobjtype = DEFACLOBJ_TYPE;
4323 break;
4325 case OBJECT_SCHEMA:
4326 defaclobjtype = DEFACLOBJ_NAMESPACE;
4327 break;
4329 default:
4330 return NULL;
4333 /* Look up the relevant pg_default_acl entries */
4334 glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4335 schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4337 /* Quick out if neither entry exists */
4338 if (glob_acl == NULL && schema_acl == NULL)
4339 return NULL;
4341 /* We need to know the hard-wired default value, too */
4342 def_acl = acldefault(objtype, ownerId);
4344 /* If there's no global entry, substitute the hard-wired default */
4345 if (glob_acl == NULL)
4346 glob_acl = def_acl;
4348 /* Merge in any per-schema privileges */
4349 result = aclmerge(glob_acl, schema_acl, ownerId);
4352 * For efficiency, we want to return NULL if the result equals default.
4353 * This requires sorting both arrays to get an accurate comparison.
4355 aclitemsort(result);
4356 aclitemsort(def_acl);
4357 if (aclequal(result, def_acl))
4358 result = NULL;
4360 return result;
4364 * Record dependencies on roles mentioned in a new object's ACL.
4366 void
4367 recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
4368 Oid ownerId, Acl *acl)
4370 int nmembers;
4371 Oid *members;
4373 /* Nothing to do if ACL is defaulted */
4374 if (acl == NULL)
4375 return;
4377 /* Extract roles mentioned in ACL */
4378 nmembers = aclmembers(acl, &members);
4380 /* Update the shared dependency ACL info */
4381 updateAclDependencies(classId, objectId, objsubId,
4382 ownerId,
4383 0, NULL,
4384 nmembers, members);
4388 * Record initial privileges for the top-level object passed in.
4390 * For the object passed in, this will record its ACL (if any) and the ACLs of
4391 * any sub-objects (eg: columns) into pg_init_privs.
4393 void
4394 recordExtObjInitPriv(Oid objoid, Oid classoid)
4397 * pg_class / pg_attribute
4399 * If this is a relation then we need to see if there are any sub-objects
4400 * (eg: columns) for it and, if so, be sure to call
4401 * recordExtensionInitPrivWorker() for each one.
4403 if (classoid == RelationRelationId)
4405 Form_pg_class pg_class_tuple;
4406 Datum aclDatum;
4407 bool isNull;
4408 HeapTuple tuple;
4410 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4411 if (!HeapTupleIsValid(tuple))
4412 elog(ERROR, "cache lookup failed for relation %u", objoid);
4413 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4416 * Indexes don't have permissions, neither do the pg_class rows for
4417 * composite types. (These cases are unreachable given the
4418 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4420 if (pg_class_tuple->relkind == RELKIND_INDEX ||
4421 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4422 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4424 ReleaseSysCache(tuple);
4425 return;
4429 * If this isn't a sequence then it's possibly going to have
4430 * column-level ACLs associated with it.
4432 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4434 AttrNumber curr_att;
4435 AttrNumber nattrs = pg_class_tuple->relnatts;
4437 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4439 HeapTuple attTuple;
4440 Datum attaclDatum;
4442 attTuple = SearchSysCache2(ATTNUM,
4443 ObjectIdGetDatum(objoid),
4444 Int16GetDatum(curr_att));
4446 if (!HeapTupleIsValid(attTuple))
4447 continue;
4449 /* ignore dropped columns */
4450 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4452 ReleaseSysCache(attTuple);
4453 continue;
4456 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4457 Anum_pg_attribute_attacl,
4458 &isNull);
4460 /* no need to do anything for a NULL ACL */
4461 if (isNull)
4463 ReleaseSysCache(attTuple);
4464 continue;
4467 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4468 DatumGetAclP(attaclDatum));
4470 ReleaseSysCache(attTuple);
4474 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4475 &isNull);
4477 /* Add the record, if any, for the top-level object */
4478 if (!isNull)
4479 recordExtensionInitPrivWorker(objoid, classoid, 0,
4480 DatumGetAclP(aclDatum));
4482 ReleaseSysCache(tuple);
4484 else if (classoid == LargeObjectRelationId)
4486 /* For large objects, we must consult pg_largeobject_metadata */
4487 Datum aclDatum;
4488 bool isNull;
4489 HeapTuple tuple;
4490 ScanKeyData entry[1];
4491 SysScanDesc scan;
4492 Relation relation;
4495 * Note: this is dead code, given that we don't allow large objects to
4496 * be made extension members. But it seems worth carrying in case
4497 * some future caller of this function has need for it.
4499 relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4501 /* There's no syscache for pg_largeobject_metadata */
4502 ScanKeyInit(&entry[0],
4503 Anum_pg_largeobject_metadata_oid,
4504 BTEqualStrategyNumber, F_OIDEQ,
4505 ObjectIdGetDatum(objoid));
4507 scan = systable_beginscan(relation,
4508 LargeObjectMetadataOidIndexId, true,
4509 NULL, 1, entry);
4511 tuple = systable_getnext(scan);
4512 if (!HeapTupleIsValid(tuple))
4513 elog(ERROR, "could not find tuple for large object %u", objoid);
4515 aclDatum = heap_getattr(tuple,
4516 Anum_pg_largeobject_metadata_lomacl,
4517 RelationGetDescr(relation), &isNull);
4519 /* Add the record, if any, for the top-level object */
4520 if (!isNull)
4521 recordExtensionInitPrivWorker(objoid, classoid, 0,
4522 DatumGetAclP(aclDatum));
4524 systable_endscan(scan);
4526 /* This will error on unsupported classoid. */
4527 else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4529 Datum aclDatum;
4530 bool isNull;
4531 HeapTuple tuple;
4533 tuple = SearchSysCache1(get_object_catcache_oid(classoid),
4534 ObjectIdGetDatum(objoid));
4535 if (!HeapTupleIsValid(tuple))
4536 elog(ERROR, "cache lookup failed for %s %u",
4537 get_object_class_descr(classoid), objoid);
4539 aclDatum = SysCacheGetAttr(get_object_catcache_oid(classoid), tuple,
4540 get_object_attnum_acl(classoid),
4541 &isNull);
4543 /* Add the record, if any, for the top-level object */
4544 if (!isNull)
4545 recordExtensionInitPrivWorker(objoid, classoid, 0,
4546 DatumGetAclP(aclDatum));
4548 ReleaseSysCache(tuple);
4553 * For the object passed in, remove its ACL and the ACLs of any object subIds
4554 * from pg_init_privs (via recordExtensionInitPrivWorker()).
4556 void
4557 removeExtObjInitPriv(Oid objoid, Oid classoid)
4560 * If this is a relation then we need to see if there are any sub-objects
4561 * (eg: columns) for it and, if so, be sure to call
4562 * recordExtensionInitPrivWorker() for each one.
4564 if (classoid == RelationRelationId)
4566 Form_pg_class pg_class_tuple;
4567 HeapTuple tuple;
4569 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4570 if (!HeapTupleIsValid(tuple))
4571 elog(ERROR, "cache lookup failed for relation %u", objoid);
4572 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4575 * Indexes don't have permissions, neither do the pg_class rows for
4576 * composite types. (These cases are unreachable given the
4577 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4579 if (pg_class_tuple->relkind == RELKIND_INDEX ||
4580 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4581 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4583 ReleaseSysCache(tuple);
4584 return;
4588 * If this isn't a sequence then it's possibly going to have
4589 * column-level ACLs associated with it.
4591 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4593 AttrNumber curr_att;
4594 AttrNumber nattrs = pg_class_tuple->relnatts;
4596 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4598 HeapTuple attTuple;
4600 attTuple = SearchSysCache2(ATTNUM,
4601 ObjectIdGetDatum(objoid),
4602 Int16GetDatum(curr_att));
4604 if (!HeapTupleIsValid(attTuple))
4605 continue;
4607 /* when removing, remove all entries, even dropped columns */
4609 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4611 ReleaseSysCache(attTuple);
4615 ReleaseSysCache(tuple);
4618 /* Remove the record, if any, for the top-level object */
4619 recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
4623 * Record initial ACL for an extension object
4625 * Can be called at any time, we check if 'creating_extension' is set and, if
4626 * not, exit immediately.
4628 * Pass in the object OID, the OID of the class (the OID of the table which
4629 * the object is defined in) and the 'sub' id of the object (objsubid), if
4630 * any. If there is no 'sub' id (they are currently only used for columns of
4631 * tables) then pass in '0'. Finally, pass in the complete ACL to store.
4633 * If an ACL already exists for this object/sub-object then we will replace
4634 * it with what is passed in.
4636 * Passing in NULL for 'new_acl' will result in the entry for the object being
4637 * removed, if one is found.
4639 static void
4640 recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
4643 * Generally, we only record the initial privileges when an extension is
4644 * being created, but because we don't actually use CREATE EXTENSION
4645 * during binary upgrades with pg_upgrade, there is a variable to let us
4646 * know that the GRANT and REVOKE statements being issued, while this
4647 * variable is true, are for the initial privileges of the extension
4648 * object and therefore we need to record them.
4650 if (!creating_extension && !binary_upgrade_record_init_privs)
4651 return;
4653 recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4657 * Record initial ACL for an extension object, worker.
4659 * This will perform a wholesale replacement of the entire ACL for the object
4660 * passed in, therefore be sure to pass in the complete new ACL to use.
4662 * Generally speaking, do *not* use this function directly but instead use
4663 * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
4664 * This function does *not* check if 'creating_extension' is set as it is also
4665 * used when an object is added to or removed from an extension via ALTER
4666 * EXTENSION ... ADD/DROP.
4668 static void
4669 recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
4671 Relation relation;
4672 ScanKeyData key[3];
4673 SysScanDesc scan;
4674 HeapTuple tuple;
4675 HeapTuple oldtuple;
4677 relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4679 ScanKeyInit(&key[0],
4680 Anum_pg_init_privs_objoid,
4681 BTEqualStrategyNumber, F_OIDEQ,
4682 ObjectIdGetDatum(objoid));
4683 ScanKeyInit(&key[1],
4684 Anum_pg_init_privs_classoid,
4685 BTEqualStrategyNumber, F_OIDEQ,
4686 ObjectIdGetDatum(classoid));
4687 ScanKeyInit(&key[2],
4688 Anum_pg_init_privs_objsubid,
4689 BTEqualStrategyNumber, F_INT4EQ,
4690 Int32GetDatum(objsubid));
4692 scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4693 NULL, 3, key);
4695 /* There should exist only one entry or none. */
4696 oldtuple = systable_getnext(scan);
4698 /* If we find an entry, update it with the latest ACL. */
4699 if (HeapTupleIsValid(oldtuple))
4701 Datum values[Natts_pg_init_privs] = {0};
4702 bool nulls[Natts_pg_init_privs] = {0};
4703 bool replace[Natts_pg_init_privs] = {0};
4705 /* If we have a new ACL to set, then update the row with it. */
4706 if (new_acl)
4708 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4709 replace[Anum_pg_init_privs_initprivs - 1] = true;
4711 oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4712 values, nulls, replace);
4714 CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4716 else
4718 /* new_acl is NULL, so delete the entry we found. */
4719 CatalogTupleDelete(relation, &oldtuple->t_self);
4722 else
4724 Datum values[Natts_pg_init_privs] = {0};
4725 bool nulls[Natts_pg_init_privs] = {0};
4728 * Only add a new entry if the new ACL is non-NULL.
4730 * If we are passed in a NULL ACL and no entry exists, we can just
4731 * fall through and do nothing.
4733 if (new_acl)
4735 /* No entry found, so add it. */
4736 values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4737 values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4738 values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4740 /* This function only handles initial privileges of extensions */
4741 values[Anum_pg_init_privs_privtype - 1] =
4742 CharGetDatum(INITPRIVS_EXTENSION);
4744 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4746 tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4748 CatalogTupleInsert(relation, tuple);
4752 systable_endscan(scan);
4754 /* prevent error when processing objects multiple times */
4755 CommandCounterIncrement();
4757 table_close(relation, RowExclusiveLock);