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 
666  oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
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),
1627  Int16GetDatum(attnum));
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:
3431  case OBJECT_ROLE:
3432  case OBJECT_RULE:
3433  case OBJECT_TABCONSTRAINT:
3434  case OBJECT_TRANSFORM:
3435  case OBJECT_TRIGGER:
3436  case OBJECT_TSPARSER:
3437  case OBJECT_TSTEMPLATE:
3438  case OBJECT_USER_MAPPING:
3439  elog(ERROR, "unsupported object type %d", objtype);
3440  }
3441 
3442  ereport(ERROR,
3443  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3444  errmsg(msg, objectname)));
3445  break;
3446  }
3447  case ACLCHECK_NOT_OWNER:
3448  {
3449  const char *msg = "???";
3450 
3451  switch (objtype)
3452  {
3453  case OBJECT_AGGREGATE:
3454  msg = gettext_noop("must be owner of aggregate %s");
3455  break;
3456  case OBJECT_COLLATION:
3457  msg = gettext_noop("must be owner of collation %s");
3458  break;
3459  case OBJECT_CONVERSION:
3460  msg = gettext_noop("must be owner of conversion %s");
3461  break;
3462  case OBJECT_DATABASE:
3463  msg = gettext_noop("must be owner of database %s");
3464  break;
3465  case OBJECT_DOMAIN:
3466  msg = gettext_noop("must be owner of domain %s");
3467  break;
3468  case OBJECT_EVENT_TRIGGER:
3469  msg = gettext_noop("must be owner of event trigger %s");
3470  break;
3471  case OBJECT_EXTENSION:
3472  msg = gettext_noop("must be owner of extension %s");
3473  break;
3474  case OBJECT_FDW:
3475  msg = gettext_noop("must be owner of foreign-data wrapper %s");
3476  break;
3477  case OBJECT_FOREIGN_SERVER:
3478  msg = gettext_noop("must be owner of foreign server %s");
3479  break;
3480  case OBJECT_FOREIGN_TABLE:
3481  msg = gettext_noop("must be owner of foreign table %s");
3482  break;
3483  case OBJECT_FUNCTION:
3484  msg = gettext_noop("must be owner of function %s");
3485  break;
3486  case OBJECT_INDEX:
3487  msg = gettext_noop("must be owner of index %s");
3488  break;
3489  case OBJECT_LANGUAGE:
3490  msg = gettext_noop("must be owner of language %s");
3491  break;
3492  case OBJECT_LARGEOBJECT:
3493  msg = gettext_noop("must be owner of large object %s");
3494  break;
3495  case OBJECT_MATVIEW:
3496  msg = gettext_noop("must be owner of materialized view %s");
3497  break;
3498  case OBJECT_OPCLASS:
3499  msg = gettext_noop("must be owner of operator class %s");
3500  break;
3501  case OBJECT_OPERATOR:
3502  msg = gettext_noop("must be owner of operator %s");
3503  break;
3504  case OBJECT_OPFAMILY:
3505  msg = gettext_noop("must be owner of operator family %s");
3506  break;
3507  case OBJECT_PROCEDURE:
3508  msg = gettext_noop("must be owner of procedure %s");
3509  break;
3510  case OBJECT_PUBLICATION:
3511  msg = gettext_noop("must be owner of publication %s");
3512  break;
3513  case OBJECT_ROUTINE:
3514  msg = gettext_noop("must be owner of routine %s");
3515  break;
3516  case OBJECT_SEQUENCE:
3517  msg = gettext_noop("must be owner of sequence %s");
3518  break;
3519  case OBJECT_SUBSCRIPTION:
3520  msg = gettext_noop("must be owner of subscription %s");
3521  break;
3522  case OBJECT_TABLE:
3523  msg = gettext_noop("must be owner of table %s");
3524  break;
3525  case OBJECT_TYPE:
3526  msg = gettext_noop("must be owner of type %s");
3527  break;
3528  case OBJECT_VIEW:
3529  msg = gettext_noop("must be owner of view %s");
3530  break;
3531  case OBJECT_SCHEMA:
3532  msg = gettext_noop("must be owner of schema %s");
3533  break;
3534  case OBJECT_STATISTIC_EXT:
3535  msg = gettext_noop("must be owner of statistics object %s");
3536  break;
3537  case OBJECT_TABLESPACE:
3538  msg = gettext_noop("must be owner of tablespace %s");
3539  break;
3541  msg = gettext_noop("must be owner of text search configuration %s");
3542  break;
3543  case OBJECT_TSDICTIONARY:
3544  msg = gettext_noop("must be owner of text search dictionary %s");
3545  break;
3546 
3547  /*
3548  * Special cases: For these, the error message talks
3549  * about "relation", because that's where the
3550  * ownership is attached. See also
3551  * check_object_ownership().
3552  */
3553  case OBJECT_COLUMN:
3554  case OBJECT_POLICY:
3555  case OBJECT_RULE:
3556  case OBJECT_TABCONSTRAINT:
3557  case OBJECT_TRIGGER:
3558  msg = gettext_noop("must be owner of relation %s");
3559  break;
3560  /* these currently aren't used */
3561  case OBJECT_ACCESS_METHOD:
3562  case OBJECT_AMOP:
3563  case OBJECT_AMPROC:
3564  case OBJECT_ATTRIBUTE:
3565  case OBJECT_CAST:
3566  case OBJECT_DEFAULT:
3567  case OBJECT_DEFACL:
3568  case OBJECT_DOMCONSTRAINT:
3570  case OBJECT_ROLE:
3571  case OBJECT_TRANSFORM:
3572  case OBJECT_TSPARSER:
3573  case OBJECT_TSTEMPLATE:
3574  case OBJECT_USER_MAPPING:
3575  elog(ERROR, "unsupported object type %d", objtype);
3576  }
3577 
3578  ereport(ERROR,
3579  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3580  errmsg(msg, objectname)));
3581  break;
3582  }
3583  default:
3584  elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3585  break;
3586  }
3587 }
3588 
3589 
3590 void
3592  const char *objectname, const char *colname)
3593 {
3594  switch (aclerr)
3595  {
3596  case ACLCHECK_OK:
3597  /* no error, so return to caller */
3598  break;
3599  case ACLCHECK_NO_PRIV:
3600  ereport(ERROR,
3601  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3602  errmsg("permission denied for column \"%s\" of relation \"%s\"",
3603  colname, objectname)));
3604  break;
3605  case ACLCHECK_NOT_OWNER:
3606  /* relation msg is OK since columns don't have separate owners */
3607  aclcheck_error(aclerr, objtype, objectname);
3608  break;
3609  default:
3610  elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3611  break;
3612  }
3613 }
3614 
3615 
3616 /*
3617  * Special common handling for types: use element type instead of array type,
3618  * and format nicely
3619  */
3620 void
3622 {
3623  Oid element_type = get_element_type(typeOid);
3624 
3625  aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
3626 }
3627 
3628 
3629 /*
3630  * Relay for the various pg_*_mask routines depending on object kind
3631  */
3632 static AclMode
3633 pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid,
3634  AclMode mask, AclMaskHow how)
3635 {
3636  switch (objtype)
3637  {
3638  case OBJECT_COLUMN:
3639  return
3640  pg_class_aclmask(table_oid, roleid, mask, how) |
3641  pg_attribute_aclmask(table_oid, attnum, roleid, mask, how);
3642  case OBJECT_TABLE:
3643  case OBJECT_SEQUENCE:
3644  return pg_class_aclmask(table_oid, roleid, mask, how);
3645  case OBJECT_DATABASE:
3646  return pg_database_aclmask(table_oid, roleid, mask, how);
3647  case OBJECT_FUNCTION:
3648  return pg_proc_aclmask(table_oid, roleid, mask, how);
3649  case OBJECT_LANGUAGE:
3650  return pg_language_aclmask(table_oid, roleid, mask, how);
3651  case OBJECT_LARGEOBJECT:
3652  return pg_largeobject_aclmask_snapshot(table_oid, roleid,
3653  mask, how, NULL);
3654  case OBJECT_SCHEMA:
3655  return pg_namespace_aclmask(table_oid, roleid, mask, how);
3656  case OBJECT_STATISTIC_EXT:
3657  elog(ERROR, "grantable rights not supported for statistics objects");
3658  /* not reached, but keep compiler quiet */
3659  return ACL_NO_RIGHTS;
3660  case OBJECT_TABLESPACE:
3661  return pg_tablespace_aclmask(table_oid, roleid, mask, how);
3662  case OBJECT_FDW:
3663  return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
3664  case OBJECT_FOREIGN_SERVER:
3665  return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
3666  case OBJECT_EVENT_TRIGGER:
3667  elog(ERROR, "grantable rights not supported for event triggers");
3668  /* not reached, but keep compiler quiet */
3669  return ACL_NO_RIGHTS;
3670  case OBJECT_TYPE:
3671  return pg_type_aclmask(table_oid, roleid, mask, how);
3672  default:
3673  elog(ERROR, "unrecognized objtype: %d",
3674  (int) objtype);
3675  /* not reached, but keep compiler quiet */
3676  return ACL_NO_RIGHTS;
3677  }
3678 }
3679 
3680 
3681 /* ****************************************************************
3682  * Exported routines for examining a user's privileges for various objects
3683  *
3684  * See aclmask() for a description of the common API for these functions.
3685  *
3686  * Note: we give lookup failure the full ereport treatment because the
3687  * has_xxx_privilege() family of functions allow users to pass any random
3688  * OID to these functions.
3689  * ****************************************************************
3690  */
3691 
3692 /*
3693  * Exported routine for examining a user's privileges for a column
3694  *
3695  * Note: this considers only privileges granted specifically on the column.
3696  * It is caller's responsibility to take relation-level privileges into account
3697  * as appropriate. (For the same reason, we have no special case for
3698  * superuser-ness here.)
3699  */
3700 AclMode
3702  AclMode mask, AclMaskHow how)
3703 {
3704  return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3705  mask, how, NULL);
3706 }
3707 
3708 /*
3709  * Exported routine for examining a user's privileges for a column
3710  *
3711  * Does the bulk of the work for pg_attribute_aclmask(), and allows other
3712  * callers to avoid the missing attribute ERROR when is_missing is non-NULL.
3713  */
3714 AclMode
3716  AclMode mask, AclMaskHow how, bool *is_missing)
3717 {
3718  AclMode result;
3719  HeapTuple classTuple;
3720  HeapTuple attTuple;
3721  Form_pg_class classForm;
3722  Form_pg_attribute attributeForm;
3723  Datum aclDatum;
3724  bool isNull;
3725  Acl *acl;
3726  Oid ownerId;
3727 
3728  /*
3729  * First, get the column's ACL from its pg_attribute entry
3730  */
3731  attTuple = SearchSysCache2(ATTNUM,
3732  ObjectIdGetDatum(table_oid),
3733  Int16GetDatum(attnum));
3734  if (!HeapTupleIsValid(attTuple))
3735  {
3736  if (is_missing != NULL)
3737  {
3738  /* return "no privileges" instead of throwing an error */
3739  *is_missing = true;
3740  return 0;
3741  }
3742  else
3743  ereport(ERROR,
3744  (errcode(ERRCODE_UNDEFINED_COLUMN),
3745  errmsg("attribute %d of relation with OID %u does not exist",
3746  attnum, table_oid)));
3747  }
3748 
3749  attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3750 
3751  /* Check dropped columns, too */
3752  if (attributeForm->attisdropped)
3753  {
3754  if (is_missing != NULL)
3755  {
3756  /* return "no privileges" instead of throwing an error */
3757  *is_missing = true;
3758  ReleaseSysCache(attTuple);
3759  return 0;
3760  }
3761  else
3762  ereport(ERROR,
3763  (errcode(ERRCODE_UNDEFINED_COLUMN),
3764  errmsg("attribute %d of relation with OID %u does not exist",
3765  attnum, table_oid)));
3766  }
3767 
3768  aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3769  &isNull);
3770 
3771  /*
3772  * Here we hard-wire knowledge that the default ACL for a column grants no
3773  * privileges, so that we can fall out quickly in the very common case
3774  * where attacl is null.
3775  */
3776  if (isNull)
3777  {
3778  ReleaseSysCache(attTuple);
3779  return 0;
3780  }
3781 
3782  /*
3783  * Must get the relation's ownerId from pg_class. Since we already found
3784  * a pg_attribute entry, the only likely reason for this to fail is that a
3785  * concurrent DROP of the relation committed since then (which could only
3786  * happen if we don't have lock on the relation). We prefer to report "no
3787  * privileges" rather than failing in such a case, so as to avoid unwanted
3788  * failures in has_column_privilege() tests.
3789  */
3790  classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3791  if (!HeapTupleIsValid(classTuple))
3792  {
3793  ReleaseSysCache(attTuple);
3794  return 0;
3795  }
3796  classForm = (Form_pg_class) GETSTRUCT(classTuple);
3797 
3798  ownerId = classForm->relowner;
3799 
3800  ReleaseSysCache(classTuple);
3801 
3802  /* detoast column's ACL if necessary */
3803  acl = DatumGetAclP(aclDatum);
3804 
3805  result = aclmask(acl, roleid, ownerId, mask, how);
3806 
3807  /* if we have a detoasted copy, free it */
3808  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3809  pfree(acl);
3810 
3811  ReleaseSysCache(attTuple);
3812 
3813  return result;
3814 }
3815 
3816 /*
3817  * Exported routine for examining a user's privileges for a table
3818  */
3819 AclMode
3820 pg_class_aclmask(Oid table_oid, Oid roleid,
3821  AclMode mask, AclMaskHow how)
3822 {
3823  return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3824 }
3825 
3826 /*
3827  * Exported routine for examining a user's privileges for a table
3828  *
3829  * Does the bulk of the work for pg_class_aclmask(), and allows other
3830  * callers to avoid the missing relation ERROR when is_missing is non-NULL.
3831  */
3832 AclMode
3833 pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
3834  AclMaskHow how, bool *is_missing)
3835 {
3836  AclMode result;
3837  HeapTuple tuple;
3838  Form_pg_class classForm;
3839  Datum aclDatum;
3840  bool isNull;
3841  Acl *acl;
3842  Oid ownerId;
3843 
3844  /*
3845  * Must get the relation's tuple from pg_class
3846  */
3847  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3848  if (!HeapTupleIsValid(tuple))
3849  {
3850  if (is_missing != NULL)
3851  {
3852  /* return "no privileges" instead of throwing an error */
3853  *is_missing = true;
3854  return 0;
3855  }
3856  else
3857  ereport(ERROR,
3859  errmsg("relation with OID %u does not exist",
3860  table_oid)));
3861  }
3862 
3863  classForm = (Form_pg_class) GETSTRUCT(tuple);
3864 
3865  /*
3866  * Deny anyone permission to update a system catalog unless
3867  * pg_authid.rolsuper is set.
3868  *
3869  * As of 7.4 we have some updatable system views; those shouldn't be
3870  * protected in this way. Assume the view rules can take care of
3871  * themselves. ACL_USAGE is if we ever have system sequences.
3872  */
3873  if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3874  IsSystemClass(table_oid, classForm) &&
3875  classForm->relkind != RELKIND_VIEW &&
3876  !superuser_arg(roleid))
3878 
3879  /*
3880  * Otherwise, superusers bypass all permission-checking.
3881  */
3882  if (superuser_arg(roleid))
3883  {
3884  ReleaseSysCache(tuple);
3885  return mask;
3886  }
3887 
3888  /*
3889  * Normal case: get the relation's ACL from pg_class
3890  */
3891  ownerId = classForm->relowner;
3892 
3893  aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3894  &isNull);
3895  if (isNull)
3896  {
3897  /* No ACL, so build default ACL */
3898  switch (classForm->relkind)
3899  {
3900  case RELKIND_SEQUENCE:
3901  acl = acldefault(OBJECT_SEQUENCE, ownerId);
3902  break;
3903  default:
3904  acl = acldefault(OBJECT_TABLE, ownerId);
3905  break;
3906  }
3907  aclDatum = (Datum) 0;
3908  }
3909  else
3910  {
3911  /* detoast rel's ACL if necessary */
3912  acl = DatumGetAclP(aclDatum);
3913  }
3914 
3915  result = aclmask(acl, roleid, ownerId, mask, how);
3916 
3917  /* if we have a detoasted copy, free it */
3918  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3919  pfree(acl);
3920 
3921  ReleaseSysCache(tuple);
3922 
3923  /*
3924  * Check if ACL_SELECT is being checked and, if so, and not set already as
3925  * part of the result, then check if the user is a member of the
3926  * pg_read_all_data role, which allows read access to all relations.
3927  */
3928  if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
3929  has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
3930  result |= ACL_SELECT;
3931 
3932  /*
3933  * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3934  * so, and not set already as part of the result, then check if the user
3935  * is a member of the pg_write_all_data role, which allows
3936  * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3937  * which requires superuser, see above).
3938  */
3939  if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
3940  !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
3941  has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
3942  result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
3943 
3944  return result;
3945 }
3946 
3947 /*
3948  * Exported routine for examining a user's privileges for a database
3949  */
3950 AclMode
3951 pg_database_aclmask(Oid db_oid, Oid roleid,
3952  AclMode mask, AclMaskHow how)
3953 {
3954  AclMode result;
3955  HeapTuple tuple;
3956  Datum aclDatum;
3957  bool isNull;
3958  Acl *acl;
3959  Oid ownerId;
3960 
3961  /* Superusers bypass all permission checking. */
3962  if (superuser_arg(roleid))
3963  return mask;
3964 
3965  /*
3966  * Get the database's ACL from pg_database
3967  */
3968  tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
3969  if (!HeapTupleIsValid(tuple))
3970  ereport(ERROR,
3971  (errcode(ERRCODE_UNDEFINED_DATABASE),
3972  errmsg("database with OID %u does not exist", db_oid)));
3973 
3974  ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
3975 
3976  aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
3977  &isNull);
3978  if (isNull)
3979  {
3980  /* No ACL, so build default ACL */
3981  acl = acldefault(OBJECT_DATABASE, ownerId);
3982  aclDatum = (Datum) 0;
3983  }
3984  else
3985  {
3986  /* detoast ACL if necessary */
3987  acl = DatumGetAclP(aclDatum);
3988  }
3989 
3990  result = aclmask(acl, roleid, ownerId, mask, how);
3991 
3992  /* if we have a detoasted copy, free it */
3993  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3994  pfree(acl);
3995 
3996  ReleaseSysCache(tuple);
3997 
3998  return result;
3999 }
4000 
4001 /*
4002  * Exported routine for examining a user's privileges for a function
4003  */
4004 AclMode
4005 pg_proc_aclmask(Oid proc_oid, Oid roleid,
4006  AclMode mask, AclMaskHow how)
4007 {
4008  AclMode result;
4009  HeapTuple tuple;
4010  Datum aclDatum;
4011  bool isNull;
4012  Acl *acl;
4013  Oid ownerId;
4014 
4015  /* Superusers bypass all permission checking. */
4016  if (superuser_arg(roleid))
4017  return mask;
4018 
4019  /*
4020  * Get the function's ACL from pg_proc
4021  */
4022  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
4023  if (!HeapTupleIsValid(tuple))
4024  ereport(ERROR,
4025  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4026  errmsg("function with OID %u does not exist", proc_oid)));
4027 
4028  ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
4029 
4030  aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
4031  &isNull);
4032  if (isNull)
4033  {
4034  /* No ACL, so build default ACL */
4035  acl = acldefault(OBJECT_FUNCTION, ownerId);
4036  aclDatum = (Datum) 0;
4037  }
4038  else
4039  {
4040  /* detoast ACL if necessary */
4041  acl = DatumGetAclP(aclDatum);
4042  }
4043 
4044  result = aclmask(acl, roleid, ownerId, mask, how);
4045 
4046  /* if we have a detoasted copy, free it */
4047  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4048  pfree(acl);
4049 
4050  ReleaseSysCache(tuple);
4051 
4052  return result;
4053 }
4054 
4055 /*
4056  * Exported routine for examining a user's privileges for a language
4057  */
4058 AclMode
4059 pg_language_aclmask(Oid lang_oid, Oid roleid,
4060  AclMode mask, AclMaskHow how)
4061 {
4062  AclMode result;
4063  HeapTuple tuple;
4064  Datum aclDatum;
4065  bool isNull;
4066  Acl *acl;
4067  Oid ownerId;
4068 
4069  /* Superusers bypass all permission checking. */
4070  if (superuser_arg(roleid))
4071  return mask;
4072 
4073  /*
4074  * Get the language's ACL from pg_language
4075  */
4076  tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid));
4077  if (!HeapTupleIsValid(tuple))
4078  ereport(ERROR,
4079  (errcode(ERRCODE_UNDEFINED_OBJECT),
4080  errmsg("language with OID %u does not exist", lang_oid)));
4081 
4082  ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
4083 
4084  aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
4085  &isNull);
4086  if (isNull)
4087  {
4088  /* No ACL, so build default ACL */
4089  acl = acldefault(OBJECT_LANGUAGE, ownerId);
4090  aclDatum = (Datum) 0;
4091  }
4092  else
4093  {
4094  /* detoast ACL if necessary */
4095  acl = DatumGetAclP(aclDatum);
4096  }
4097 
4098  result = aclmask(acl, roleid, ownerId, mask, how);
4099 
4100  /* if we have a detoasted copy, free it */
4101  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4102  pfree(acl);
4103 
4104  ReleaseSysCache(tuple);
4105 
4106  return result;
4107 }
4108 
4109 /*
4110  * Exported routine for examining a user's privileges for a largeobject
4111  *
4112  * When a large object is opened for reading, it is opened relative to the
4113  * caller's snapshot, but when it is opened for writing, a current
4114  * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
4115  * takes a snapshot argument so that the permissions check can be made
4116  * relative to the same snapshot that will be used to read the underlying
4117  * data. The caller will actually pass NULL for an instantaneous MVCC
4118  * snapshot, since all we do with the snapshot argument is pass it through
4119  * to systable_beginscan().
4120  */
4121 AclMode
4123  AclMode mask, AclMaskHow how,
4124  Snapshot snapshot)
4125 {
4126  AclMode result;
4127  Relation pg_lo_meta;
4128  ScanKeyData entry[1];
4129  SysScanDesc scan;
4130  HeapTuple tuple;
4131  Datum aclDatum;
4132  bool isNull;
4133  Acl *acl;
4134  Oid ownerId;
4135 
4136  /* Superusers bypass all permission checking. */
4137  if (superuser_arg(roleid))
4138  return mask;
4139 
4140  /*
4141  * Get the largeobject's ACL from pg_largeobject_metadata
4142  */
4143  pg_lo_meta = table_open(LargeObjectMetadataRelationId,
4144  AccessShareLock);
4145 
4146  ScanKeyInit(&entry[0],
4147  Anum_pg_largeobject_metadata_oid,
4148  BTEqualStrategyNumber, F_OIDEQ,
4149  ObjectIdGetDatum(lobj_oid));
4150 
4151  scan = systable_beginscan(pg_lo_meta,
4152  LargeObjectMetadataOidIndexId, true,
4153  snapshot, 1, entry);
4154 
4155  tuple = systable_getnext(scan);
4156  if (!HeapTupleIsValid(tuple))
4157  ereport(ERROR,
4158  (errcode(ERRCODE_UNDEFINED_OBJECT),
4159  errmsg("large object %u does not exist", lobj_oid)));
4160 
4161  ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
4162 
4163  aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
4164  RelationGetDescr(pg_lo_meta), &isNull);
4165 
4166  if (isNull)
4167  {
4168  /* No ACL, so build default ACL */
4169  acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
4170  aclDatum = (Datum) 0;
4171  }
4172  else
4173  {
4174  /* detoast ACL if necessary */
4175  acl = DatumGetAclP(aclDatum);
4176  }
4177 
4178  result = aclmask(acl, roleid, ownerId, mask, how);
4179 
4180  /* if we have a detoasted copy, free it */
4181  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4182  pfree(acl);
4183 
4184  systable_endscan(scan);
4185 
4186  table_close(pg_lo_meta, AccessShareLock);
4187 
4188  return result;
4189 }
4190 
4191 /*
4192  * Exported routine for examining a user's privileges for a namespace
4193  */
4194 AclMode
4195 pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
4196  AclMode mask, AclMaskHow how)
4197 {
4198  AclMode result;
4199  HeapTuple tuple;
4200  Datum aclDatum;
4201  bool isNull;
4202  Acl *acl;
4203  Oid ownerId;
4204 
4205  /* Superusers bypass all permission checking. */
4206  if (superuser_arg(roleid))
4207  return mask;
4208 
4209  /*
4210  * If we have been assigned this namespace as a temp namespace, check to
4211  * make sure we have CREATE TEMP permission on the database, and if so act
4212  * as though we have all standard (but not GRANT OPTION) permissions on
4213  * the namespace. If we don't have CREATE TEMP, act as though we have
4214  * only USAGE (and not CREATE) rights.
4215  *
4216  * This may seem redundant given the check in InitTempTableNamespace, but
4217  * it really isn't since current user ID may have changed since then. The
4218  * upshot of this behavior is that a SECURITY DEFINER function can create
4219  * temp tables that can then be accessed (if permission is granted) by
4220  * code in the same session that doesn't have permissions to create temp
4221  * tables.
4222  *
4223  * XXX Would it be safe to ereport a special error message as
4224  * InitTempTableNamespace does? Returning zero here means we'll get a
4225  * generic "permission denied for schema pg_temp_N" message, which is not
4226  * remarkably user-friendly.
4227  */
4228  if (isTempNamespace(nsp_oid))
4229  {
4230  if (pg_database_aclcheck(MyDatabaseId, roleid,
4232  return mask & ACL_ALL_RIGHTS_SCHEMA;
4233  else
4234  return mask & ACL_USAGE;
4235  }
4236 
4237  /*
4238  * Get the schema's ACL from pg_namespace
4239  */
4240  tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
4241  if (!HeapTupleIsValid(tuple))
4242  ereport(ERROR,
4243  (errcode(ERRCODE_UNDEFINED_SCHEMA),
4244  errmsg("schema with OID %u does not exist", nsp_oid)));
4245 
4246  ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
4247 
4248  aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
4249  &isNull);
4250  if (isNull)
4251  {
4252  /* No ACL, so build default ACL */
4253  acl = acldefault(OBJECT_SCHEMA, ownerId);
4254  aclDatum = (Datum) 0;
4255  }
4256  else
4257  {
4258  /* detoast ACL if necessary */
4259  acl = DatumGetAclP(aclDatum);
4260  }
4261 
4262  result = aclmask(acl, roleid, ownerId, mask, how);
4263 
4264  /* if we have a detoasted copy, free it */
4265  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4266  pfree(acl);
4267 
4268  ReleaseSysCache(tuple);
4269 
4270  /*
4271  * Check if ACL_USAGE is being checked and, if so, and not set already as
4272  * part of the result, then check if the user is a member of the
4273  * pg_read_all_data or pg_write_all_data roles, which allow usage access
4274  * to all schemas.
4275  */
4276  if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
4277  (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
4278  has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
4279  result |= ACL_USAGE;
4280  return result;
4281 }
4282 
4283 /*
4284  * Exported routine for examining a user's privileges for a tablespace
4285  */
4286 AclMode
4288  AclMode mask, AclMaskHow how)
4289 {
4290  AclMode result;
4291  HeapTuple tuple;
4292  Datum aclDatum;
4293  bool isNull;
4294  Acl *acl;
4295  Oid ownerId;
4296 
4297  /* Superusers bypass all permission checking. */
4298  if (superuser_arg(roleid))
4299  return mask;
4300 
4301  /*
4302  * Get the tablespace's ACL from pg_tablespace
4303  */
4304  tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
4305  if (!HeapTupleIsValid(tuple))
4306  ereport(ERROR,
4307  (errcode(ERRCODE_UNDEFINED_OBJECT),
4308  errmsg("tablespace with OID %u does not exist", spc_oid)));
4309 
4310  ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
4311 
4312  aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple,
4313  Anum_pg_tablespace_spcacl,
4314  &isNull);
4315 
4316  if (isNull)
4317  {
4318  /* No ACL, so build default ACL */
4319  acl = acldefault(OBJECT_TABLESPACE, ownerId);
4320  aclDatum = (Datum) 0;
4321  }
4322  else
4323  {
4324  /* detoast ACL if necessary */
4325  acl = DatumGetAclP(aclDatum);
4326  }
4327 
4328  result = aclmask(acl, roleid, ownerId, mask, how);
4329 
4330  /* if we have a detoasted copy, free it */
4331  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4332  pfree(acl);
4333 
4334  ReleaseSysCache(tuple);
4335 
4336  return result;
4337 }
4338 
4339 /*
4340  * Exported routine for examining a user's privileges for a foreign
4341  * data wrapper
4342  */
4343 AclMode
4345  AclMode mask, AclMaskHow how)
4346 {
4347  AclMode result;
4348  HeapTuple tuple;
4349  Datum aclDatum;
4350  bool isNull;
4351  Acl *acl;
4352  Oid ownerId;
4353 
4355 
4356  /* Bypass permission checks for superusers */
4357  if (superuser_arg(roleid))
4358  return mask;
4359 
4360  /*
4361  * Must get the FDW's tuple from pg_foreign_data_wrapper
4362  */
4364  if (!HeapTupleIsValid(tuple))
4365  ereport(ERROR,
4366  (errcode(ERRCODE_UNDEFINED_OBJECT),
4367  errmsg("foreign-data wrapper with OID %u does not exist",
4368  fdw_oid)));
4369  fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
4370 
4371  /*
4372  * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
4373  */
4374  ownerId = fdwForm->fdwowner;
4375 
4376  aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
4377  Anum_pg_foreign_data_wrapper_fdwacl, &isNull);
4378  if (isNull)
4379  {
4380  /* No ACL, so build default ACL */
4381  acl = acldefault(OBJECT_FDW, ownerId);
4382  aclDatum = (Datum) 0;
4383  }
4384  else
4385  {
4386  /* detoast rel's ACL if necessary */
4387  acl = DatumGetAclP(aclDatum);
4388  }
4389 
4390  result = aclmask(acl, roleid, ownerId, mask, how);
4391 
4392  /* if we have a detoasted copy, free it */
4393  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4394  pfree(acl);
4395 
4396  ReleaseSysCache(tuple);
4397 
4398  return result;
4399 }
4400 
4401 /*
4402  * Exported routine for examining a user's privileges for a foreign
4403  * server.
4404  */
4405 AclMode
4407  AclMode mask, AclMaskHow how)
4408 {
4409  AclMode result;
4410  HeapTuple tuple;
4411  Datum aclDatum;
4412  bool isNull;
4413  Acl *acl;
4414  Oid ownerId;
4415 
4416  Form_pg_foreign_server srvForm;
4417 
4418  /* Bypass permission checks for superusers */
4419  if (superuser_arg(roleid))
4420  return mask;
4421 
4422  /*
4423  * Must get the FDW's tuple from pg_foreign_data_wrapper
4424  */
4426  if (!HeapTupleIsValid(tuple))
4427  ereport(ERROR,
4428  (errcode(ERRCODE_UNDEFINED_OBJECT),
4429  errmsg("foreign server with OID %u does not exist",
4430  srv_oid)));
4431  srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
4432 
4433  /*
4434  * Normal case: get the foreign server's ACL from pg_foreign_server
4435  */
4436  ownerId = srvForm->srvowner;
4437 
4438  aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
4439  Anum_pg_foreign_server_srvacl, &isNull);
4440  if (isNull)
4441  {
4442  /* No ACL, so build default ACL */
4443  acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
4444  aclDatum = (Datum) 0;
4445  }
4446  else
4447  {
4448  /* detoast rel's ACL if necessary */
4449  acl = DatumGetAclP(aclDatum);
4450  }
4451 
4452  result = aclmask(acl, roleid, ownerId, mask, how);
4453 
4454  /* if we have a detoasted copy, free it */
4455  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4456  pfree(acl);
4457 
4458  ReleaseSysCache(tuple);
4459 
4460  return result;
4461 }
4462 
4463 /*
4464  * Exported routine for examining a user's privileges for a type.
4465  */
4466 AclMode
4467 pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
4468 {
4469  AclMode result;
4470  HeapTuple tuple;
4471  Datum aclDatum;
4472  bool isNull;
4473  Acl *acl;
4474  Oid ownerId;
4475 
4476  Form_pg_type typeForm;
4477 
4478  /* Bypass permission checks for superusers */
4479  if (superuser_arg(roleid))
4480  return mask;
4481 
4482  /*
4483  * Must get the type's tuple from pg_type
4484  */
4485  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
4486  if (!HeapTupleIsValid(tuple))
4487  ereport(ERROR,
4488  (errcode(ERRCODE_UNDEFINED_OBJECT),
4489  errmsg("type with OID %u does not exist",
4490  type_oid)));
4491  typeForm = (Form_pg_type) GETSTRUCT(tuple);
4492 
4493  /*
4494  * "True" array types don't manage permissions of their own; consult the
4495  * element type instead.
4496  */
4497  if (IsTrueArrayType(typeForm))
4498  {
4499  Oid elttype_oid = typeForm->typelem;
4500 
4501  ReleaseSysCache(tuple);
4502 
4503  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
4504  /* this case is not a user-facing error, so elog not ereport */
4505  if (!HeapTupleIsValid(tuple))
4506  elog(ERROR, "cache lookup failed for type %u", elttype_oid);
4507  typeForm = (Form_pg_type) GETSTRUCT(tuple);
4508  }
4509 
4510  /*
4511  * Now get the type's owner and ACL from the tuple
4512  */
4513  ownerId = typeForm->typowner;
4514 
4515  aclDatum = SysCacheGetAttr(TYPEOID, tuple,
4516  Anum_pg_type_typacl, &isNull);
4517  if (isNull)
4518  {
4519  /* No ACL, so build default ACL */
4520  acl = acldefault(OBJECT_TYPE, ownerId);
4521  aclDatum = (Datum) 0;
4522  }
4523  else
4524  {
4525  /* detoast rel's ACL if necessary */
4526  acl = DatumGetAclP(aclDatum);
4527  }
4528 
4529  result = aclmask(acl, roleid, ownerId, mask, how);
4530 
4531  /* if we have a detoasted copy, free it */
4532  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4533  pfree(acl);
4534 
4535  ReleaseSysCache(tuple);
4536 
4537  return result;
4538 }
4539 
4540 /*
4541  * Exported routine for checking a user's access privileges to a column
4542  *
4543  * Returns ACLCHECK_OK if the user has any of the privileges identified by
4544  * 'mode'; otherwise returns a suitable error code (in practice, always
4545  * ACLCHECK_NO_PRIV).
4546  *
4547  * As with pg_attribute_aclmask, only privileges granted directly on the
4548  * column are considered here.
4549  */
4550 AclResult
4552  Oid roleid, AclMode mode)
4553 {
4554  return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
4555 }
4556 
4557 
4558 /*
4559  * Exported routine for checking a user's access privileges to a column
4560  *
4561  * Does the bulk of the work for pg_attribute_aclcheck(), and allows other
4562  * callers to avoid the missing attribute ERROR when is_missing is non-NULL.
4563  */
4564 AclResult
4566  Oid roleid, AclMode mode, bool *is_missing)
4567 {
4568  if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
4569  ACLMASK_ANY, is_missing) != 0)
4570  return ACLCHECK_OK;
4571  else
4572  return ACLCHECK_NO_PRIV;
4573 }
4574 
4575 /*
4576  * Exported routine for checking a user's access privileges to any/all columns
4577  *
4578  * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
4579  * privileges identified by 'mode' on any non-dropped column in the relation;
4580  * otherwise returns a suitable error code (in practice, always
4581  * ACLCHECK_NO_PRIV).
4582  *
4583  * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
4584  * privileges identified by 'mode' on each non-dropped column in the relation
4585  * (and there must be at least one such column); otherwise returns a suitable
4586  * error code (in practice, always ACLCHECK_NO_PRIV).
4587  *
4588  * As with pg_attribute_aclmask, only privileges granted directly on the
4589  * column(s) are considered here.
4590  *
4591  * Note: system columns are not considered here; there are cases where that
4592  * might be appropriate but there are also cases where it wouldn't.
4593  */
4594 AclResult
4596  AclMaskHow how)
4597 {
4598  AclResult result;
4599  HeapTuple classTuple;
4600  Form_pg_class classForm;
4601  AttrNumber nattrs;
4602  AttrNumber curr_att;
4603 
4604  /*
4605  * Must fetch pg_class row to check number of attributes. As in
4606  * pg_attribute_aclmask, we prefer to return "no privileges" instead of
4607  * throwing an error if we get any unexpected lookup errors.
4608  */
4609  classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
4610  if (!HeapTupleIsValid(classTuple))
4611  return ACLCHECK_NO_PRIV;
4612  classForm = (Form_pg_class) GETSTRUCT(classTuple);
4613 
4614  nattrs = classForm->relnatts;
4615 
4616  ReleaseSysCache(classTuple);
4617 
4618  /*
4619  * Initialize result in case there are no non-dropped columns. We want to
4620  * report failure in such cases for either value of 'how'.
4621  */
4622  result = ACLCHECK_NO_PRIV;
4623 
4624  for (curr_att = 1; curr_att <= nattrs; curr_att++)
4625  {
4626  HeapTuple attTuple;
4627  AclMode attmask;
4628 
4629  attTuple = SearchSysCache2(ATTNUM,
4630  ObjectIdGetDatum(table_oid),
4631  Int16GetDatum(curr_att));
4632  if (!HeapTupleIsValid(attTuple))
4633  continue;
4634 
4635  /* ignore dropped columns */
4636  if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4637  {
4638  ReleaseSysCache(attTuple);
4639  continue;
4640  }
4641 
4642  /*
4643  * Here we hard-wire knowledge that the default ACL for a column
4644  * grants no privileges, so that we can fall out quickly in the very
4645  * common case where attacl is null.
4646  */
4647  if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
4648  attmask = 0;
4649  else
4650  attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
4651  mode, ACLMASK_ANY);
4652 
4653  ReleaseSysCache(attTuple);
4654 
4655  if (attmask != 0)
4656  {
4657  result = ACLCHECK_OK;
4658  if (how == ACLMASK_ANY)
4659  break; /* succeed on any success */
4660  }
4661  else
4662  {
4663  result = ACLCHECK_NO_PRIV;
4664  if (how == ACLMASK_ALL)
4665  break; /* fail on any failure */
4666  }
4667  }
4668 
4669  return result;
4670 }
4671 
4672 /*
4673  * Exported routine for checking a user's access privileges to a table
4674  *
4675  * Returns ACLCHECK_OK if the user has any of the privileges identified by
4676  * 'mode'; otherwise returns a suitable error code (in practice, always
4677  * ACLCHECK_NO_PRIV).
4678  */
4679 AclResult
4680 pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
4681 {
4682  return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
4683 }
4684 
4685 /*
4686  * Exported routine for checking a user's access privileges to a table
4687  *
4688  * Does the bulk of the work for pg_class_aclcheck(), and allows other
4689  * callers to avoid the missing relation ERROR when is_missing is non-NULL.
4690  */
4691 AclResult
4692 pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
4693  AclMode mode, bool *is_missing)
4694 {
4695  if (pg_class_aclmask_ext(table_oid, roleid, mode,
4696  ACLMASK_ANY, is_missing) != 0)
4697  return ACLCHECK_OK;
4698  else
4699  return ACLCHECK_NO_PRIV;
4700 }
4701 
4702 /*
4703  * Exported routine for checking a user's access privileges to a database
4704  */
4705 AclResult
4707 {
4708  if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
4709  return ACLCHECK_OK;
4710  else
4711  return ACLCHECK_NO_PRIV;
4712 }
4713 
4714 /*
4715  * Exported routine for checking a user's access privileges to a function
4716  */
4717 AclResult
4719 {
4720  if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
4721  return ACLCHECK_OK;
4722  else
4723  return ACLCHECK_NO_PRIV;
4724 }
4725 
4726 /*
4727  * Exported routine for checking a user's access privileges to a language
4728  */
4729 AclResult
4731 {
4732  if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
4733  return ACLCHECK_OK;
4734  else
4735  return ACLCHECK_NO_PRIV;
4736 }
4737 
4738 /*
4739  * Exported routine for checking a user's access privileges to a largeobject
4740  */
4741 AclResult
4743  Snapshot snapshot)
4744 {
4745  if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4746  ACLMASK_ANY, snapshot) != 0)
4747  return ACLCHECK_OK;
4748  else
4749  return ACLCHECK_NO_PRIV;
4750 }
4751 
4752 /*
4753  * Exported routine for checking a user's access privileges to a namespace
4754  */
4755 AclResult
4757 {
4758  if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
4759  return ACLCHECK_OK;
4760  else
4761  return ACLCHECK_NO_PRIV;
4762 }
4763 
4764 /*
4765  * Exported routine for checking a user's access privileges to a tablespace
4766  */
4767 AclResult
4769 {
4770  if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
4771  return ACLCHECK_OK;
4772  else
4773  return ACLCHECK_NO_PRIV;
4774 }
4775 
4776 /*
4777  * Exported routine for checking a user's access privileges to a foreign
4778  * data wrapper
4779  */
4780 AclResult
4782 {
4783  if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0)
4784  return ACLCHECK_OK;
4785  else
4786  return ACLCHECK_NO_PRIV;
4787 }
4788 
4789 /*
4790  * Exported routine for checking a user's access privileges to a foreign
4791  * server
4792  */
4793 AclResult
4795 {
4796  if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0)
4797  return ACLCHECK_OK;
4798  else
4799  return ACLCHECK_NO_PRIV;
4800 }
4801 
4802 /*
4803  * Exported routine for checking a user's access privileges to a type
4804  */
4805 AclResult
4807 {
4808  if (pg_type_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0)
4809  return ACLCHECK_OK;
4810  else
4811  return ACLCHECK_NO_PRIV;
4812 }
4813 
4814 /*
4815  * Ownership check for a relation (specified by OID).
4816  */
4817 bool
4818 pg_class_ownercheck(Oid class_oid, Oid roleid)
4819 {
4820  HeapTuple tuple;
4821  Oid ownerId;
4822 
4823  /* Superusers bypass all permission checking. */
4824  if (superuser_arg(roleid))
4825  return true;
4826 
4827  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid));
4828  if (!HeapTupleIsValid(tuple))
4829  ereport(ERROR,
4831  errmsg("relation with OID %u does not exist", class_oid)));
4832 
4833  ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
4834 
4835  ReleaseSysCache(tuple);
4836 
4837  return has_privs_of_role(roleid, ownerId);
4838 }
4839 
4840 /*
4841  * Ownership check for a type (specified by OID).
4842  */
4843 bool
4844 pg_type_ownercheck(Oid type_oid, Oid roleid)
4845 {
4846  HeapTuple tuple;
4847  Oid ownerId;
4848 
4849  /* Superusers bypass all permission checking. */
4850  if (superuser_arg(roleid))
4851  return true;
4852 
4853  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
4854  if (!HeapTupleIsValid(tuple))
4855  ereport(ERROR,
4856  (errcode(ERRCODE_UNDEFINED_OBJECT),
4857  errmsg("type with OID %u does not exist", type_oid)));
4858 
4859  ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
4860 
4861  ReleaseSysCache(tuple);
4862 
4863  return has_privs_of_role(roleid, ownerId);
4864 }
4865 
4866 /*
4867  * Ownership check for an operator (specified by OID).
4868  */
4869 bool
4870 pg_oper_ownercheck(Oid oper_oid, Oid roleid)
4871 {
4872  HeapTuple tuple;
4873  Oid ownerId;
4874 
4875  /* Superusers bypass all permission checking. */
4876  if (superuser_arg(roleid))
4877  return true;
4878 
4879  tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(oper_oid));
4880  if (!HeapTupleIsValid(tuple))
4881  ereport(ERROR,
4882  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4883  errmsg("operator with OID %u does not exist", oper_oid)));
4884 
4885  ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
4886 
4887  ReleaseSysCache(tuple);
4888 
4889  return has_privs_of_role(roleid, ownerId);
4890 }
4891 
4892 /*
4893  * Ownership check for a function (specified by OID).
4894  */
4895 bool
4896 pg_proc_ownercheck(Oid proc_oid, Oid roleid)
4897 {
4898  HeapTuple tuple;
4899  Oid ownerId;
4900 
4901  /* Superusers bypass all permission checking. */
4902  if (superuser_arg(roleid))
4903  return true;
4904 
4905  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
4906  if (!HeapTupleIsValid(tuple))
4907  ereport(ERROR,
4908  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4909  errmsg("function with OID %u does not exist", proc_oid)));
4910 
4911  ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
4912 
4913  ReleaseSysCache(tuple);
4914 
4915  return has_privs_of_role(roleid, ownerId);
4916 }
4917 
4918 /*
4919  * Ownership check for a procedural language (specified by OID)
4920  */
4921 bool
4923 {
4924  HeapTuple tuple;
4925  Oid ownerId;
4926 
4927  /* Superusers bypass all permission checking. */
4928  if (superuser_arg(roleid))
4929  return true;
4930 
4931  tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lan_oid));
4932  if (!HeapTupleIsValid(tuple))
4933  ereport(ERROR,
4934  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4935  errmsg("language with OID %u does not exist", lan_oid)));
4936 
4937  ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
4938 
4939  ReleaseSysCache(tuple);
4940 
4941  return has_privs_of_role(roleid, ownerId);
4942 }
4943 
4944 /*
4945  * Ownership check for a largeobject (specified by OID)
4946  *
4947  * This is only used for operations like ALTER LARGE OBJECT that are always
4948  * relative to an up-to-date snapshot.
4949  */
4950 bool
4952 {
4953  Relation pg_lo_meta;
4954  ScanKeyData entry[1];
4955  SysScanDesc scan;
4956  HeapTuple tuple;
4957  Oid ownerId;
4958 
4959  /* Superusers bypass all permission checking. */
4960  if (superuser_arg(roleid))
4961  return true;
4962 
4963  /* There's no syscache for pg_largeobject_metadata */
4964  pg_lo_meta = table_open(LargeObjectMetadataRelationId,
4965  AccessShareLock);
4966 
4967  ScanKeyInit(&entry[0],
4968  Anum_pg_largeobject_metadata_oid,
4969  BTEqualStrategyNumber, F_OIDEQ,
4970  ObjectIdGetDatum(lobj_oid));
4971 
4972  scan = systable_beginscan(pg_lo_meta,
4973  LargeObjectMetadataOidIndexId, true,
4974  NULL, 1, entry);
4975 
4976  tuple = systable_getnext(scan);
4977  if (!HeapTupleIsValid(tuple))
4978  ereport(ERROR,
4979  (errcode(ERRCODE_UNDEFINED_OBJECT),
4980  errmsg("large object %u does not exist", lobj_oid)));
4981 
4982  ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
4983 
4984  systable_endscan(scan);
4985  table_close(pg_lo_meta, AccessShareLock);
4986 
4987  return has_privs_of_role(roleid, ownerId);
4988 }
4989 
4990 /*
4991  * Ownership check for a namespace (specified by OID).
4992  */
4993 bool
4995 {
4996  HeapTuple tuple;
4997  Oid ownerId;
4998 
4999  /* Superusers bypass all permission checking. */
5000  if (superuser_arg(roleid))
5001  return true;
5002 
5003  tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
5004  if (!HeapTupleIsValid(tuple))
5005  ereport(ERROR,
5006  (errcode(ERRCODE_UNDEFINED_SCHEMA),
5007  errmsg("schema with OID %u does not exist", nsp_oid)));
5008 
5009  ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
5010 
5011  ReleaseSysCache(tuple);
5012 
5013  return has_privs_of_role(roleid, ownerId);
5014 }
5015 
5016 /*
5017  * Ownership check for a tablespace (specified by OID).
5018  */
5019 bool
5021 {
5022  HeapTuple spctuple;
5023  Oid spcowner;
5024 
5025  /* Superusers bypass all permission checking. */
5026  if (superuser_arg(roleid))
5027  return true;
5028 
5029  /* Search syscache for pg_tablespace */
5030  spctuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
5031  if (!HeapTupleIsValid(spctuple))
5032  ereport(ERROR,
5033  (errcode(ERRCODE_UNDEFINED_OBJECT),
5034  errmsg("tablespace with OID %u does not exist", spc_oid)));
5035 
5036  spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
5037 
5038  ReleaseSysCache(spctuple);
5039 
5040  return has_privs_of_role(roleid, spcowner);
5041 }
5042 
5043 /*
5044  * Ownership check for an operator class (specified by OID).
5045  */
5046 bool
5048 {
5049  HeapTuple tuple;
5050  Oid ownerId;
5051 
5052  /* Superusers bypass all permission checking. */
5053  if (superuser_arg(roleid))
5054  return true;
5055 
5056  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opc_oid));
5057  if (!HeapTupleIsValid(tuple))
5058  ereport(ERROR,
5059  (errcode(ERRCODE_UNDEFINED_OBJECT),
5060  errmsg("operator class with OID %u does not exist",
5061  opc_oid)));
5062 
5063  ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
5064 
5065  ReleaseSysCache(tuple);
5066 
5067  return has_privs_of_role(roleid, ownerId);
5068 }
5069 
5070 /*
5071  * Ownership check for an operator family (specified by OID).
5072  */
5073 bool
5075 {
5076  HeapTuple tuple;
5077  Oid ownerId;
5078 
5079  /* Superusers bypass all permission checking. */
5080  if (superuser_arg(roleid))
5081  return true;
5082 
5083  tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opf_oid));
5084  if (!HeapTupleIsValid(tuple))
5085  ereport(ERROR,
5086  (errcode(ERRCODE_UNDEFINED_OBJECT),
5087  errmsg("operator family with OID %u does not exist",
5088  opf_oid)));
5089 
5090  ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
5091 
5092  ReleaseSysCache(tuple);
5093 
5094  return has_privs_of_role(roleid, ownerId);
5095 }
5096 
5097 /*
5098  * Ownership check for a text search dictionary (specified by OID).
5099  */
5100 bool
5101 pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid)
5102 {
5103  HeapTuple tuple;
5104  Oid ownerId;
5105 
5106  /* Superusers bypass all permission checking. */
5107  if (superuser_arg(roleid))
5108  return true;
5109 
5110  tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dict_oid));
5111  if (!HeapTupleIsValid(tuple))
5112  ereport(ERROR,
5113  (errcode(ERRCODE_UNDEFINED_OBJECT),
5114  errmsg("text search dictionary with OID %u does not exist",
5115  dict_oid)));
5116 
5117  ownerId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictowner;
5118 
5119  ReleaseSysCache(tuple);
5120 
5121  return has_privs_of_role(roleid, ownerId);
5122 }
5123 
5124 /*
5125  * Ownership check for a text search configuration (specified by OID).
5126  */
5127 bool
5129 {
5130  HeapTuple tuple;
5131  Oid ownerId;
5132 
5133  /* Superusers bypass all permission checking. */
5134  if (superuser_arg(roleid))
5135  return true;
5136 
5137  tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfg_oid));
5138  if (!HeapTupleIsValid(tuple))
5139  ereport(ERROR,
5140  (errcode(ERRCODE_UNDEFINED_OBJECT),
5141  errmsg("text search configuration with OID %u does not exist",
5142  cfg_oid)));
5143 
5144  ownerId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgowner;
5145 
5146  ReleaseSysCache(tuple);
5147 
5148  return has_privs_of_role(roleid, ownerId);
5149 }
5150 
5151 /*
5152  * Ownership check for a foreign-data wrapper (specified by OID).
5153  */
5154 bool
5156 {
5157  HeapTuple tuple;
5158  Oid ownerId;
5159 
5160  /* Superusers bypass all permission checking. */
5161  if (superuser_arg(roleid))
5162  return true;
5163 
5165  if (!HeapTupleIsValid(tuple))
5166  ereport(ERROR,
5167  (errcode(ERRCODE_UNDEFINED_OBJECT),
5168  errmsg("foreign-data wrapper with OID %u does not exist",
5169  srv_oid)));
5170 
5171  ownerId = ((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwowner;
5172 
5173  ReleaseSysCache(tuple);
5174 
5175  return has_privs_of_role(roleid, ownerId);
5176 }
5177 
5178 /*
5179  * Ownership check for a foreign server (specified by OID).
5180  */
5181 bool
5183 {
5184  HeapTuple tuple;
5185  Oid ownerId;
5186 
5187  /* Superusers bypass all permission checking. */
5188  if (superuser_arg(roleid))
5189  return true;
5190 
5192  if (!HeapTupleIsValid(tuple))
5193  ereport(ERROR,
5194  (errcode(ERRCODE_UNDEFINED_OBJECT),
5195  errmsg("foreign server with OID %u does not exist",
5196  srv_oid)));
5197 
5198  ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner;
5199 
5200  ReleaseSysCache(tuple);
5201 
5202  return has_privs_of_role(roleid, ownerId);
5203 }
5204 
5205 /*
5206  * Ownership check for an event trigger (specified by OID).
5207  */
5208 bool
5210 {
5211  HeapTuple tuple;
5212  Oid ownerId;
5213 
5214  /* Superusers bypass all permission checking. */
5215  if (superuser_arg(roleid))
5216  return true;
5217 
5219  if (!HeapTupleIsValid(tuple))
5220  ereport(ERROR,
5221  (errcode(ERRCODE_UNDEFINED_OBJECT),
5222  errmsg("event trigger with OID %u does not exist",
5223  et_oid)));
5224 
5225  ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
5226 
5227  ReleaseSysCache(tuple);
5228 
5229  return has_privs_of_role(roleid, ownerId);
5230 }
5231 
5232 /*
5233  * Ownership check for a database (specified by OID).
5234  */
5235 bool
5237 {
5238  HeapTuple tuple;
5239  Oid dba;
5240 
5241  /* Superusers bypass all permission checking. */
5242  if (superuser_arg(roleid))
5243  return true;
5244 
5245  tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
5246  if (!HeapTupleIsValid(tuple))
5247  ereport(ERROR,
5248  (errcode(ERRCODE_UNDEFINED_DATABASE),
5249  errmsg("database with OID %u does not exist", db_oid)));
5250 
5251  dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
5252 
5253  ReleaseSysCache(tuple);
5254 
5255  return has_privs_of_role(roleid, dba);
5256 }
5257 
5258 /*
5259  * Ownership check for a collation (specified by OID).
5260  */
5261 bool
5263 {
5264  HeapTuple tuple;
5265  Oid ownerId;
5266 
5267  /* Superusers bypass all permission checking. */
5268  if (superuser_arg(roleid))
5269  return true;
5270 
5271  tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(coll_oid));
5272  if (!HeapTupleIsValid(tuple))
5273  ereport(ERROR,
5274  (errcode(ERRCODE_UNDEFINED_OBJECT),
5275  errmsg("collation with OID %u does not exist", coll_oid)));
5276 
5277  ownerId = ((Form_pg_collation) GETSTRUCT(tuple))->collowner;
5278 
5279  ReleaseSysCache(tuple);
5280 
5281  return has_privs_of_role(roleid, ownerId);
5282 }
5283 
5284 /*
5285  * Ownership check for a conversion (specified by OID).
5286  */
5287 bool
5289 {
5290  HeapTuple tuple;
5291  Oid ownerId;
5292 
5293  /* Superusers bypass all permission checking. */
5294  if (superuser_arg(roleid))
5295  return true;
5296 
5297  tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conv_oid));
5298  if (!HeapTupleIsValid(tuple))
5299  ereport(ERROR,
5300  (errcode(ERRCODE_UNDEFINED_OBJECT),
5301  errmsg("conversion with OID %u does not exist", conv_oid)));
5302 
5303  ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
5304 
5305  ReleaseSysCache(tuple);
5306 
5307  return has_privs_of_role(roleid, ownerId);
5308 }
5309 
5310 /*
5311  * Ownership check for an extension (specified by OID).
5312  */
5313 bool
5315 {
5316  Relation pg_extension;
5317  ScanKeyData entry[1];
5318  SysScanDesc scan;
5319  HeapTuple tuple;
5320  Oid ownerId;
5321 
5322  /* Superusers bypass all permission checking. */
5323  if (superuser_arg(roleid))
5324  return true;
5325 
5326  /* There's no syscache for pg_extension, so do it the hard way */
5327  pg_extension = table_open(ExtensionRelationId, AccessShareLock);
5328 
5329  ScanKeyInit(&entry[0],
5330  Anum_pg_extension_oid,
5331  BTEqualStrategyNumber, F_OIDEQ,
5332  ObjectIdGetDatum(ext_oid));
5333 
5334  scan = systable_beginscan(pg_extension,
5335  ExtensionOidIndexId, true,
5336  NULL, 1, entry);
5337 
5338  tuple = systable_getnext(scan);
5339  if (!HeapTupleIsValid(tuple))
5340  ereport(ERROR,
5341  (errcode(ERRCODE_UNDEFINED_OBJECT),
5342  errmsg("extension with OID %u does not exist", ext_oid)));
5343 
5344  ownerId = ((Form_pg_extension) GETSTRUCT(tuple))->extowner;
5345 
5346  systable_endscan(scan);
5347  table_close(pg_extension, AccessShareLock);
5348 
5349  return has_privs_of_role(roleid, ownerId);
5350 }
5351 
5352 /*
5353  * Ownership check for a publication (specified by OID).
5354  */
5355 bool
5357 {
5358  HeapTuple tuple;
5359  Oid ownerId;
5360 
5361  /* Superusers bypass all permission checking. */
5362  if (superuser_arg(roleid))
5363  return true;
5364 
5365  tuple = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pub_oid));
5366  if (!HeapTupleIsValid(tuple))
5367  ereport(ERROR,
5368  (errcode(ERRCODE_UNDEFINED_OBJECT),
5369  errmsg("publication with OID %u does not exist", pub_oid)));
5370 
5371  ownerId = ((Form_pg_publication) GETSTRUCT(tuple))->pubowner;
5372 
5373  ReleaseSysCache(tuple);
5374 
5375  return has_privs_of_role(roleid, ownerId);
5376 }
5377 
5378 /*
5379  * Ownership check for a subscription (specified by OID).
5380  */
5381 bool
5383 {
5384  HeapTuple tuple;
5385  Oid ownerId;
5386 
5387  /* Superusers bypass all permission checking. */
5388  if (superuser_arg(roleid))
5389  return true;
5390 
5392  if (!HeapTupleIsValid(tuple))
5393  ereport(ERROR,
5394  (errcode(ERRCODE_UNDEFINED_OBJECT),
5395  errmsg("subscription with OID %u does not exist", sub_oid)));
5396 
5397  ownerId = ((Form_pg_subscription) GETSTRUCT(tuple))->subowner;
5398 
5399  ReleaseSysCache(tuple);
5400 
5401  return has_privs_of_role(roleid, ownerId);
5402 }
5403 
5404 /*
5405  * Ownership check for a statistics object (specified by OID).
5406  */
5407 bool
5409 {
5410  HeapTuple tuple;
5411  Oid ownerId;
5412 
5413  /* Superusers bypass all permission checking. */
5414  if (superuser_arg(roleid))
5415  return true;
5416 
5417  tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stat_oid));
5418  if (!HeapTupleIsValid(tuple))
5419  ereport(ERROR,
5420  (errcode(ERRCODE_UNDEFINED_OBJECT),
5421  errmsg("statistics object with OID %u does not exist",
5422  stat_oid)));
5423 
5424  ownerId = ((Form_pg_statistic_ext) GETSTRUCT(tuple))->stxowner;
5425 
5426  ReleaseSysCache(tuple);
5427 
5428  return has_privs_of_role(roleid, ownerId);
5429 }
5430 
5431 /*
5432  * Check whether specified role has CREATEROLE privilege (or is a superuser)
5433  *
5434  * Note: roles do not have owners per se; instead we use this test in
5435  * places where an ownership-like permissions test is needed for a role.
5436  * Be sure to apply it to the role trying to do the operation, not the
5437  * role being operated on! Also note that this generally should not be
5438  * considered enough privilege if the target role is a superuser.
5439  * (We don't handle that consideration here because we want to give a
5440  * separate error message for such cases, so the caller has to deal with it.)
5441  */
5442 bool
5444 {
5445  bool result = false;
5446  HeapTuple utup;
5447 
5448  /* Superusers bypass all permission checking. */
5449  if (superuser_arg(roleid))
5450  return true;
5451 
5452  utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
5453  if (HeapTupleIsValid(utup))
5454  {
5455  result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
5456  ReleaseSysCache(utup);
5457  }
5458  return result;
5459 }
5460 
5461 bool
5463 {
5464  bool result = false;
5465  HeapTuple utup;
5466 
5467  /* Superusers bypass all permission checking. */
5468  if (superuser_arg(roleid))
5469  return true;
5470 
5471  utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
5472  if (HeapTupleIsValid(utup))
5473  {
5474  result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
5475  ReleaseSysCache(utup);
5476  }
5477  return result;
5478 }
5479 
5480 /*
5481  * Fetch pg_default_acl entry for given role, namespace and object type
5482  * (object type must be given in pg_default_acl's encoding).
5483  * Returns NULL if no such entry.
5484  */
5485 static Acl *
5486 get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
5487 {
5488  Acl *result = NULL;
5489  HeapTuple tuple;
5490 
5492  ObjectIdGetDatum(roleId),
5493  ObjectIdGetDatum(nsp_oid),
5494  CharGetDatum(objtype));
5495 
5496  if (HeapTupleIsValid(tuple))
5497  {
5498  Datum aclDatum;
5499  bool isNull;
5500 
5501  aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
5502  Anum_pg_default_acl_defaclacl,
5503  &isNull);
5504  if (!isNull)
5505  result = DatumGetAclPCopy(aclDatum);
5506  ReleaseSysCache(tuple);
5507  }
5508 
5509  return result;
5510 }
5511 
5512 /*
5513  * Get default permissions for newly created object within given schema
5514  *
5515  * Returns NULL if built-in system defaults should be used.
5516  *
5517  * If the result is not NULL, caller must call recordDependencyOnNewAcl
5518  * once the OID of the new object is known.
5519  */
5520 Acl *
5521 get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
5522 {
5523  Acl *result;
5524  Acl *glob_acl;
5525  Acl *schema_acl;
5526  Acl *def_acl;
5527  char defaclobjtype;
5528 
5529  /*
5530  * Use NULL during bootstrap, since pg_default_acl probably isn't there
5531  * yet.
5532  */
5534  return NULL;
5535 
5536  /* Check if object type is supported in pg_default_acl */
5537  switch (objtype)
5538  {
5539  case OBJECT_TABLE:
5540  defaclobjtype = DEFACLOBJ_RELATION;
5541  break;
5542 
5543  case OBJECT_SEQUENCE:
5544  defaclobjtype = DEFACLOBJ_SEQUENCE;
5545  break;
5546 
5547  case OBJECT_FUNCTION:
5548  defaclobjtype = DEFACLOBJ_FUNCTION;
5549  break;
5550 
5551  case OBJECT_TYPE:
5552  defaclobjtype = DEFACLOBJ_TYPE;
5553  break;
5554 
5555  case OBJECT_SCHEMA:
5556  defaclobjtype = DEFACLOBJ_NAMESPACE;
5557  break;
5558 
5559  default:
5560  return NULL;
5561  }
5562 
5563  /* Look up the relevant pg_default_acl entries */
5564  glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
5565  schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
5566 
5567  /* Quick out if neither entry exists */
5568  if (glob_acl == NULL && schema_acl == NULL)
5569  return NULL;
5570 
5571  /* We need to know the hard-wired default value, too */
5572  def_acl = acldefault(objtype, ownerId);
5573 
5574  /* If there's no global entry, substitute the hard-wired default */
5575  if (glob_acl == NULL)
5576  glob_acl = def_acl;
5577 
5578  /* Merge in any per-schema privileges */
5579  result = aclmerge(glob_acl, schema_acl, ownerId);
5580 
5581  /*
5582  * For efficiency, we want to return NULL if the result equals default.
5583  * This requires sorting both arrays to get an accurate comparison.
5584  */
5585  aclitemsort(result);
5586  aclitemsort(def_acl);
5587  if (aclequal(result, def_acl))
5588  result = NULL;
5589 
5590  return result;
5591 }
5592 
5593 /*
5594  * Record dependencies on roles mentioned in a new object's ACL.
5595  */
5596 void
5597 recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
5598  Oid ownerId, Acl *acl)
5599 {
5600  int nmembers;
5601  Oid *members;
5602 
5603  /* Nothing to do if ACL is defaulted */
5604  if (acl == NULL)
5605  return;
5606 
5607  /* Extract roles mentioned in ACL */
5608  nmembers = aclmembers(acl, &members);
5609 
5610  /* Update the shared dependency ACL info */
5611  updateAclDependencies(classId, objectId, objsubId,
5612  ownerId,
5613  0, NULL,
5614  nmembers, members);
5615 }
5616 
5617 /*
5618  * Record initial privileges for the top-level object passed in.
5619  *
5620  * For the object passed in, this will record its ACL (if any) and the ACLs of
5621  * any sub-objects (eg: columns) into pg_init_privs.
5622  *
5623  * Any new kinds of objects which have ACLs associated with them and can be
5624  * added to an extension should be added to the if-else tree below.
5625  */
5626 void
5627 recordExtObjInitPriv(Oid objoid, Oid classoid)
5628 {
5629  /*
5630  * pg_class / pg_attribute
5631  *
5632  * If this is a relation then we need to see if there are any sub-objects
5633  * (eg: columns) for it and, if so, be sure to call
5634  * recordExtensionInitPrivWorker() for each one.
5635  */
5636  if (classoid == RelationRelationId)
5637  {
5638  Form_pg_class pg_class_tuple;
5639  Datum aclDatum;
5640  bool isNull;
5641  HeapTuple tuple;
5642 
5643  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
5644  if (!HeapTupleIsValid(tuple))
5645  elog(ERROR, "cache lookup failed for relation %u", objoid);
5646  pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
5647 
5648  /*
5649  * Indexes don't have permissions, neither do the pg_class rows for
5650  * composite types. (These cases are unreachable given the
5651  * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
5652  */
5653  if (pg_class_tuple->relkind == RELKIND_INDEX ||
5654  pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
5655  pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
5656  {
5657  ReleaseSysCache(tuple);
5658  return;
5659  }
5660 
5661  /*
5662  * If this isn't a sequence then it's possibly going to have
5663  * column-level ACLs associated with it.
5664  */
5665  if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
5666  {
5667  AttrNumber curr_att;
5668  AttrNumber nattrs = pg_class_tuple->relnatts;
5669 
5670  for (curr_att = 1; curr_att <= nattrs; curr_att++)
5671  {
5672  HeapTuple attTuple;
5673  Datum attaclDatum;
5674 
5675  attTuple = SearchSysCache2(ATTNUM,
5676  ObjectIdGetDatum(objoid),
5677  Int16GetDatum(curr_att));
5678 
5679  if (!HeapTupleIsValid(attTuple))
5680  continue;
5681 
5682  /* ignore dropped columns */
5683  if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
5684  {
5685  ReleaseSysCache(attTuple);
5686  continue;
5687  }
5688 
5689  attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
5690  Anum_pg_attribute_attacl,
5691  &isNull);
5692 
5693  /* no need to do anything for a NULL ACL */
5694  if (isNull)
5695  {
5696  ReleaseSysCache(attTuple);
5697  continue;
5698  }
5699 
5700  recordExtensionInitPrivWorker(objoid, classoid, curr_att,
5701  DatumGetAclP(attaclDatum));
5702 
5703  ReleaseSysCache(attTuple);
5704  }
5705  }
5706 
5707  aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
5708  &isNull);
5709 
5710  /* Add the record, if any, for the top-level object */
5711  if (!isNull)
5712  recordExtensionInitPrivWorker(objoid, classoid, 0,
5713  DatumGetAclP(aclDatum));
5714 
5715  ReleaseSysCache(tuple);
5716  }
5717  /* pg_foreign_data_wrapper */
5718  else if (classoid == ForeignDataWrapperRelationId)
5719  {
5720  Datum aclDatum;
5721  bool isNull;
5722  HeapTuple tuple;
5723 
5725  ObjectIdGetDatum(objoid));
5726  if (!HeapTupleIsValid(tuple))
5727  elog(ERROR, "cache lookup failed for foreign data wrapper %u",
5728  objoid);
5729 
5730  aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
5731  Anum_pg_foreign_data_wrapper_fdwacl,
5732  &isNull);
5733 
5734  /* Add the record, if any, for the top-level object */
5735  if (!isNull)
5736  recordExtensionInitPrivWorker(objoid, classoid, 0,
5737  DatumGetAclP(aclDatum));
5738 
5739  ReleaseSysCache(tuple);
5740  }
5741  /* pg_foreign_server */
5742  else if (classoid == ForeignServerRelationId)
5743  {
5744  Datum aclDatum;
5745  bool isNull;
5746  HeapTuple tuple;
5747 
5749  if (!HeapTupleIsValid(tuple))
5750  elog(ERROR, "cache lookup failed for foreign data wrapper %u",
5751  objoid);
5752 
5753  aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
5754  Anum_pg_foreign_server_srvacl,
5755  &isNull);
5756 
5757  /* Add the record, if any, for the top-level object */
5758  if (!isNull)
5759  recordExtensionInitPrivWorker(objoid, classoid, 0,
5760  DatumGetAclP(aclDatum));
5761 
5762  ReleaseSysCache(tuple);
5763  }
5764  /* pg_language */
5765  else if (classoid == LanguageRelationId)
5766  {
5767  Datum aclDatum;
5768  bool isNull;
5769  HeapTuple tuple;
5770 
5771  tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(objoid));
5772  if (!HeapTupleIsValid(tuple))
5773  elog(ERROR, "cache lookup failed for language %u", objoid);
5774 
5775  aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
5776  &isNull);
5777 
5778  /* Add the record, if any, for the top-level object */
5779  if (!isNull)
5780  recordExtensionInitPrivWorker(objoid, classoid, 0,
5781  DatumGetAclP(aclDatum));
5782 
5783  ReleaseSysCache(tuple);
5784  }
5785  /* pg_largeobject_metadata */
5786