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