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