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