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