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