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