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