PostgreSQL Source Code  git master
aclchk.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * aclchk.c
4  * Routines to check access control permissions.
5  *
6  * Portions Copyright (c) 1996-2024, 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  * The xxx_aclmask() functions in this file are wrappers around
17  * acl.c's aclmask() function; see that for basic usage information.
18  * The wrapper functions add object-type-specific lookup capability.
19  * Generally, they will throw error if the object doesn't exist.
20  *
21  * The xxx_aclmask_ext() functions add the ability to not throw
22  * error if the object doesn't exist. If their "is_missing" argument
23  * isn't NULL, then when the object isn't found they will set
24  * *is_missing = true and return zero (no privileges) instead of
25  * throwing an error. Caller must initialize *is_missing = false.
26  *
27  * The xxx_aclcheck() functions are simplified wrappers around the
28  * corresponding xxx_aclmask() functions, simply returning ACLCHECK_OK
29  * if any of the privileges specified in "mode" are held, and otherwise
30  * a suitable error code (in practice, always ACLCHECK_NO_PRIV).
31  * Again, they will throw error if the object doesn't exist.
32  *
33  * The xxx_aclcheck_ext() functions add the ability to not throw
34  * error if the object doesn't exist. Their "is_missing" argument
35  * works similarly to the xxx_aclmask_ext() functions.
36  *
37  *-------------------------------------------------------------------------
38  */
39 #include "postgres.h"
40 
41 #include "access/genam.h"
42 #include "access/heapam.h"
43 #include "access/htup_details.h"
44 #include "access/sysattr.h"
45 #include "access/tableam.h"
46 #include "access/xact.h"
47 #include "catalog/binary_upgrade.h"
48 #include "catalog/catalog.h"
49 #include "catalog/dependency.h"
50 #include "catalog/indexing.h"
51 #include "catalog/objectaccess.h"
52 #include "catalog/pg_authid.h"
53 #include "catalog/pg_class.h"
54 #include "catalog/pg_database.h"
55 #include "catalog/pg_default_acl.h"
58 #include "catalog/pg_init_privs.h"
59 #include "catalog/pg_language.h"
60 #include "catalog/pg_largeobject.h"
62 #include "catalog/pg_namespace.h"
64 #include "catalog/pg_proc.h"
65 #include "catalog/pg_tablespace.h"
66 #include "catalog/pg_type.h"
67 #include "commands/dbcommands.h"
68 #include "commands/defrem.h"
69 #include "commands/event_trigger.h"
70 #include "commands/extension.h"
71 #include "commands/proclang.h"
72 #include "commands/tablespace.h"
73 #include "foreign/foreign.h"
74 #include "miscadmin.h"
75 #include "nodes/makefuncs.h"
76 #include "parser/parse_func.h"
77 #include "parser/parse_type.h"
78 #include "storage/lmgr.h"
79 #include "utils/acl.h"
80 #include "utils/aclchk_internal.h"
81 #include "utils/builtins.h"
82 #include "utils/fmgroids.h"
83 #include "utils/guc.h"
84 #include "utils/lsyscache.h"
85 #include "utils/rel.h"
86 #include "utils/syscache.h"
87 
88 /*
89  * Internal format used by ALTER DEFAULT PRIVILEGES.
90  */
91 typedef struct
92 {
93  Oid roleid; /* owning role */
94  Oid nspid; /* namespace, or InvalidOid if none */
95  /* remaining fields are same as in InternalGrant: */
96  bool is_grant;
98  bool all_privs;
104 
105 /*
106  * When performing a binary-upgrade, pg_dump will call a function to set
107  * this variable to let us know that we need to populate the pg_init_privs
108  * table for the GRANT/REVOKE commands while this variable is set to true.
109  */
111 
112 static void ExecGrantStmt_oids(InternalGrant *istmt);
113 static void ExecGrant_Relation(InternalGrant *istmt);
114 static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
115  void (*object_check) (InternalGrant *istmt, HeapTuple tuple));
116 static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple);
117 static void ExecGrant_Largeobject(InternalGrant *istmt);
118 static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple);
119 static void ExecGrant_Parameter(InternalGrant *istmt);
120 
121 static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
122 static void SetDefaultACL(InternalDefaultACL *iacls);
123 
124 static List *objectNamesToOids(ObjectType objtype, List *objnames,
125  bool is_grant);
126 static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
127 static List *getRelationsInNamespace(Oid namespaceId, char relkind);
128 static void expand_col_privileges(List *colnames, Oid table_oid,
129  AclMode this_privileges,
130  AclMode *col_privileges,
131  int num_col_privileges);
132 static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
133  AclMode this_privileges,
134  AclMode *col_privileges,
135  int num_col_privileges);
136 static AclMode string_to_privilege(const char *privname);
137 static const char *privilege_to_string(AclMode privilege);
138 static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
139  bool all_privs, AclMode privileges,
140  Oid objectId, Oid grantorId,
141  ObjectType objtype, const char *objname,
142  AttrNumber att_number, const char *colname);
143 static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum,
144  Oid roleid, AclMode mask, AclMaskHow how);
145 static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid,
146  AclMode mask, AclMaskHow how);
147 static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
148  AclMode mask, AclMaskHow how,
149  bool *is_missing);
151  Oid roleid, AclMode mask, AclMaskHow how);
153  Oid roleid, AclMode mask,
154  AclMaskHow how, bool *is_missing);
155 static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid,
156  AclMode mask, AclMaskHow how,
157  bool *is_missing);
158 static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
159  AclMode mask, AclMaskHow how);
160 static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
161  AclMode mask, AclMaskHow how, Snapshot snapshot);
162 static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
163  AclMode mask, AclMaskHow how,
164  bool *is_missing);
165 static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid,
166  AclMode mask, AclMaskHow how,
167  bool *is_missing);
168 static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
169  Acl *new_acl);
170 static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
171  Acl *new_acl);
172 
173 
174 /*
175  * If is_grant is true, adds the given privileges for the list of
176  * grantees to the existing old_acl. If is_grant is false, the
177  * privileges for the given grantees are removed from old_acl.
178  *
179  * NB: the original old_acl is pfree'd.
180  */
181 static Acl *
182 merge_acl_with_grant(Acl *old_acl, bool is_grant,
183  bool grant_option, DropBehavior behavior,
184  List *grantees, AclMode privileges,
185  Oid grantorId, Oid ownerId)
186 {
187  unsigned modechg;
188  ListCell *j;
189  Acl *new_acl;
190 
191  modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
192 
193  new_acl = old_acl;
194 
195  foreach(j, grantees)
196  {
197  AclItem aclitem;
198  Acl *newer_acl;
199 
200  aclitem.ai_grantee = lfirst_oid(j);
201 
202  /*
203  * Grant options can only be granted to individual roles, not PUBLIC.
204  * The reason is that if a user would re-grant a privilege that he
205  * held through PUBLIC, and later the user is removed, the situation
206  * is impossible to clean up.
207  */
208  if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
209  ereport(ERROR,
210  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
211  errmsg("grant options can only be granted to roles")));
212 
213  aclitem.ai_grantor = grantorId;
214 
215  /*
216  * The asymmetry in the conditions here comes from the spec. In
217  * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
218  * to grant both the basic privilege and its grant option. But in
219  * REVOKE, plain revoke revokes both the basic privilege and its grant
220  * option, while REVOKE GRANT OPTION revokes only the option.
221  */
223  (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
224  (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
225 
226  newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
227 
228  /* avoid memory leak when there are many grantees */
229  pfree(new_acl);
230  new_acl = newer_acl;
231  }
232 
233  return new_acl;
234 }
235 
236 /*
237  * Restrict the privileges to what we can actually grant, and emit
238  * the standards-mandated warning and error messages.
239  */
240 static AclMode
241 restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
242  AclMode privileges, Oid objectId, Oid grantorId,
243  ObjectType objtype, const char *objname,
244  AttrNumber att_number, const char *colname)
245 {
246  AclMode this_privileges;
247  AclMode whole_mask;
248 
249  switch (objtype)
250  {
251  case OBJECT_COLUMN:
252  whole_mask = ACL_ALL_RIGHTS_COLUMN;
253  break;
254  case OBJECT_TABLE:
255  whole_mask = ACL_ALL_RIGHTS_RELATION;
256  break;
257  case OBJECT_SEQUENCE:
258  whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
259  break;
260  case OBJECT_DATABASE:
261  whole_mask = ACL_ALL_RIGHTS_DATABASE;
262  break;
263  case OBJECT_FUNCTION:
264  whole_mask = ACL_ALL_RIGHTS_FUNCTION;
265  break;
266  case OBJECT_LANGUAGE:
267  whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
268  break;
269  case OBJECT_LARGEOBJECT:
270  whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
271  break;
272  case OBJECT_SCHEMA:
273  whole_mask = ACL_ALL_RIGHTS_SCHEMA;
274  break;
275  case OBJECT_TABLESPACE:
276  whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
277  break;
278  case OBJECT_FDW:
279  whole_mask = ACL_ALL_RIGHTS_FDW;
280  break;
282  whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
283  break;
285  elog(ERROR, "grantable rights not supported for event triggers");
286  /* not reached, but keep compiler quiet */
287  return ACL_NO_RIGHTS;
288  case OBJECT_TYPE:
289  whole_mask = ACL_ALL_RIGHTS_TYPE;
290  break;
292  whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
293  break;
294  default:
295  elog(ERROR, "unrecognized object type: %d", objtype);
296  /* not reached, but keep compiler quiet */
297  return ACL_NO_RIGHTS;
298  }
299 
300  /*
301  * If we found no grant options, consider whether to issue a hard error.
302  * Per spec, having any privilege at all on the object will get you by
303  * here.
304  */
305  if (avail_goptions == ACL_NO_RIGHTS)
306  {
307  if (pg_aclmask(objtype, objectId, att_number, grantorId,
308  whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
310  {
311  if (objtype == OBJECT_COLUMN && colname)
312  aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
313  else
314  aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
315  }
316  }
317 
318  /*
319  * Restrict the operation to what we can actually grant or revoke, and
320  * issue a warning if appropriate. (For REVOKE this isn't quite what the
321  * spec says to do: the spec seems to want a warning only if no privilege
322  * bits actually change in the ACL. In practice that behavior seems much
323  * too noisy, as well as inconsistent with the GRANT case.)
324  */
325  this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
326  if (is_grant)
327  {
328  if (this_privileges == 0)
329  {
330  if (objtype == OBJECT_COLUMN && colname)
332  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
333  errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
334  colname, objname)));
335  else
337  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
338  errmsg("no privileges were granted for \"%s\"",
339  objname)));
340  }
341  else if (!all_privs && this_privileges != privileges)
342  {
343  if (objtype == OBJECT_COLUMN && colname)
345  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
346  errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
347  colname, objname)));
348  else
350  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
351  errmsg("not all privileges were granted for \"%s\"",
352  objname)));
353  }
354  }
355  else
356  {
357  if (this_privileges == 0)
358  {
359  if (objtype == OBJECT_COLUMN && colname)
361  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
362  errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
363  colname, objname)));
364  else
366  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
367  errmsg("no privileges could be revoked for \"%s\"",
368  objname)));
369  }
370  else if (!all_privs && this_privileges != privileges)
371  {
372  if (objtype == OBJECT_COLUMN && colname)
374  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
375  errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
376  colname, objname)));
377  else
379  (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
380  errmsg("not all privileges could be revoked for \"%s\"",
381  objname)));
382  }
383  }
384 
385  return this_privileges;
386 }
387 
388 /*
389  * Called to execute the utility commands GRANT and REVOKE
390  */
391 void
393 {
394  InternalGrant istmt;
395  ListCell *cell;
396  const char *errormsg;
397  AclMode all_privileges;
398 
399  if (stmt->grantor)
400  {
401  Oid grantor;
402 
403  grantor = get_rolespec_oid(stmt->grantor, false);
404 
405  /*
406  * Currently, this clause is only for SQL compatibility, not very
407  * interesting otherwise.
408  */
409  if (grantor != GetUserId())
410  ereport(ERROR,
411  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
412  errmsg("grantor must be current user")));
413  }
414 
415  /*
416  * Turn the regular GrantStmt into the InternalGrant form.
417  */
418  istmt.is_grant = stmt->is_grant;
419  istmt.objtype = stmt->objtype;
420 
421  /* Collect the OIDs of the target objects */
422  switch (stmt->targtype)
423  {
424  case ACL_TARGET_OBJECT:
425  istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
426  stmt->is_grant);
427  break;
429  istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
430  break;
431  /* ACL_TARGET_DEFAULTS should not be seen here */
432  default:
433  elog(ERROR, "unrecognized GrantStmt.targtype: %d",
434  (int) stmt->targtype);
435  }
436 
437  /* all_privs to be filled below */
438  /* privileges to be filled below */
439  istmt.col_privs = NIL; /* may get filled below */
440  istmt.grantees = NIL; /* filled below */
441  istmt.grant_option = stmt->grant_option;
442  istmt.behavior = stmt->behavior;
443 
444  /*
445  * Convert the RoleSpec list into an Oid list. Note that at this point we
446  * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
447  * there shouldn't be any additional work needed to support this case.
448  */
449  foreach(cell, stmt->grantees)
450  {
451  RoleSpec *grantee = (RoleSpec *) lfirst(cell);
452  Oid grantee_uid;
453 
454  switch (grantee->roletype)
455  {
456  case ROLESPEC_PUBLIC:
457  grantee_uid = ACL_ID_PUBLIC;
458  break;
459  default:
460  grantee_uid = get_rolespec_oid(grantee, false);
461  break;
462  }
463  istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
464  }
465 
466  /*
467  * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
468  * bitmask. Note: objtype can't be OBJECT_COLUMN.
469  */
470  switch (stmt->objtype)
471  {
472  case OBJECT_TABLE:
473 
474  /*
475  * Because this might be a sequence, we test both relation and
476  * sequence bits, and later do a more limited test when we know
477  * the object type.
478  */
480  errormsg = gettext_noop("invalid privilege type %s for relation");
481  break;
482  case OBJECT_SEQUENCE:
483  all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
484  errormsg = gettext_noop("invalid privilege type %s for sequence");
485  break;
486  case OBJECT_DATABASE:
487  all_privileges = ACL_ALL_RIGHTS_DATABASE;
488  errormsg = gettext_noop("invalid privilege type %s for database");
489  break;
490  case OBJECT_DOMAIN:
491  all_privileges = ACL_ALL_RIGHTS_TYPE;
492  errormsg = gettext_noop("invalid privilege type %s for domain");
493  break;
494  case OBJECT_FUNCTION:
495  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
496  errormsg = gettext_noop("invalid privilege type %s for function");
497  break;
498  case OBJECT_LANGUAGE:
499  all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
500  errormsg = gettext_noop("invalid privilege type %s for language");
501  break;
502  case OBJECT_LARGEOBJECT:
503  all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
504  errormsg = gettext_noop("invalid privilege type %s for large object");
505  break;
506  case OBJECT_SCHEMA:
507  all_privileges = ACL_ALL_RIGHTS_SCHEMA;
508  errormsg = gettext_noop("invalid privilege type %s for schema");
509  break;
510  case OBJECT_PROCEDURE:
511  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
512  errormsg = gettext_noop("invalid privilege type %s for procedure");
513  break;
514  case OBJECT_ROUTINE:
515  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
516  errormsg = gettext_noop("invalid privilege type %s for routine");
517  break;
518  case OBJECT_TABLESPACE:
519  all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
520  errormsg = gettext_noop("invalid privilege type %s for tablespace");
521  break;
522  case OBJECT_TYPE:
523  all_privileges = ACL_ALL_RIGHTS_TYPE;
524  errormsg = gettext_noop("invalid privilege type %s for type");
525  break;
526  case OBJECT_FDW:
527  all_privileges = ACL_ALL_RIGHTS_FDW;
528  errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
529  break;
531  all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
532  errormsg = gettext_noop("invalid privilege type %s for foreign server");
533  break;
535  all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
536  errormsg = gettext_noop("invalid privilege type %s for parameter");
537  break;
538  default:
539  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
540  (int) stmt->objtype);
541  /* keep compiler quiet */
542  all_privileges = ACL_NO_RIGHTS;
543  errormsg = NULL;
544  }
545 
546  if (stmt->privileges == NIL)
547  {
548  istmt.all_privs = true;
549 
550  /*
551  * will be turned into ACL_ALL_RIGHTS_* by the internal routines
552  * depending on the object type
553  */
554  istmt.privileges = ACL_NO_RIGHTS;
555  }
556  else
557  {
558  istmt.all_privs = false;
559  istmt.privileges = ACL_NO_RIGHTS;
560 
561  foreach(cell, stmt->privileges)
562  {
563  AccessPriv *privnode = (AccessPriv *) lfirst(cell);
564  AclMode priv;
565 
566  /*
567  * If it's a column-level specification, we just set it aside in
568  * col_privs for the moment; but insist it's for a relation.
569  */
570  if (privnode->cols)
571  {
572  if (stmt->objtype != OBJECT_TABLE)
573  ereport(ERROR,
574  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
575  errmsg("column privileges are only valid for relations")));
576  istmt.col_privs = lappend(istmt.col_privs, privnode);
577  continue;
578  }
579 
580  if (privnode->priv_name == NULL) /* parser mistake? */
581  elog(ERROR, "AccessPriv node must specify privilege or columns");
582  priv = string_to_privilege(privnode->priv_name);
583 
584  if (priv & ~((AclMode) all_privileges))
585  ereport(ERROR,
586  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
587  errmsg(errormsg, privilege_to_string(priv))));
588 
589  istmt.privileges |= priv;
590  }
591  }
592 
593  ExecGrantStmt_oids(&istmt);
594 }
595 
596 /*
597  * ExecGrantStmt_oids
598  *
599  * Internal entry point for granting and revoking privileges.
600  */
601 static void
603 {
604  switch (istmt->objtype)
605  {
606  case OBJECT_TABLE:
607  case OBJECT_SEQUENCE:
608  ExecGrant_Relation(istmt);
609  break;
610  case OBJECT_DATABASE:
611  ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
612  break;
613  case OBJECT_DOMAIN:
614  case OBJECT_TYPE:
616  break;
617  case OBJECT_FDW:
618  ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
619  break;
621  ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
622  break;
623  case OBJECT_FUNCTION:
624  case OBJECT_PROCEDURE:
625  case OBJECT_ROUTINE:
626  ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
627  break;
628  case OBJECT_LANGUAGE:
630  break;
631  case OBJECT_LARGEOBJECT:
632  ExecGrant_Largeobject(istmt);
633  break;
634  case OBJECT_SCHEMA:
635  ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
636  break;
637  case OBJECT_TABLESPACE:
638  ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
639  break;
641  ExecGrant_Parameter(istmt);
642  break;
643  default:
644  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
645  (int) istmt->objtype);
646  }
647 
648  /*
649  * Pass the info to event triggers about the just-executed GRANT. Note
650  * that we prefer to do it after actually executing it, because that gives
651  * the functions a chance to adjust the istmt with privileges actually
652  * granted.
653  */
656 }
657 
658 /*
659  * objectNamesToOids
660  *
661  * Turn a list of object names of a given type into an Oid list.
662  *
663  * XXX: This function doesn't take any sort of locks on the objects whose
664  * names it looks up. In the face of concurrent DDL, we might easily latch
665  * onto an old version of an object, causing the GRANT or REVOKE statement
666  * to fail.
667  */
668 static List *
669 objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
670 {
671  List *objects = NIL;
672  ListCell *cell;
673 
674  Assert(objnames != NIL);
675 
676  switch (objtype)
677  {
678  case OBJECT_TABLE:
679  case OBJECT_SEQUENCE:
680  foreach(cell, objnames)
681  {
682  RangeVar *relvar = (RangeVar *) lfirst(cell);
683  Oid relOid;
684 
685  relOid = RangeVarGetRelid(relvar, NoLock, false);
686  objects = lappend_oid(objects, relOid);
687  }
688  break;
689  case OBJECT_DATABASE:
690  foreach(cell, objnames)
691  {
692  char *dbname = strVal(lfirst(cell));
693  Oid dbid;
694 
695  dbid = get_database_oid(dbname, false);
696  objects = lappend_oid(objects, dbid);
697  }
698  break;
699  case OBJECT_DOMAIN:
700  case OBJECT_TYPE:
701  foreach(cell, objnames)
702  {
703  List *typname = (List *) lfirst(cell);
704  Oid oid;
705 
707  objects = lappend_oid(objects, oid);
708  }
709  break;
710  case OBJECT_FUNCTION:
711  foreach(cell, objnames)
712  {
713  ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
714  Oid funcid;
715 
716  funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
717  objects = lappend_oid(objects, funcid);
718  }
719  break;
720  case OBJECT_LANGUAGE:
721  foreach(cell, objnames)
722  {
723  char *langname = strVal(lfirst(cell));
724  Oid oid;
725 
726  oid = get_language_oid(langname, false);
727  objects = lappend_oid(objects, oid);
728  }
729  break;
730  case OBJECT_LARGEOBJECT:
731  foreach(cell, objnames)
732  {
733  Oid lobjOid = oidparse(lfirst(cell));
734 
735  if (!LargeObjectExists(lobjOid))
736  ereport(ERROR,
737  (errcode(ERRCODE_UNDEFINED_OBJECT),
738  errmsg("large object %u does not exist",
739  lobjOid)));
740 
741  objects = lappend_oid(objects, lobjOid);
742  }
743  break;
744  case OBJECT_SCHEMA:
745  foreach(cell, objnames)
746  {
747  char *nspname = strVal(lfirst(cell));
748  Oid oid;
749 
750  oid = get_namespace_oid(nspname, false);
751  objects = lappend_oid(objects, oid);
752  }
753  break;
754  case OBJECT_PROCEDURE:
755  foreach(cell, objnames)
756  {
757  ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
758  Oid procid;
759 
760  procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
761  objects = lappend_oid(objects, procid);
762  }
763  break;
764  case OBJECT_ROUTINE:
765  foreach(cell, objnames)
766  {
767  ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
768  Oid routid;
769 
770  routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
771  objects = lappend_oid(objects, routid);
772  }
773  break;
774  case OBJECT_TABLESPACE:
775  foreach(cell, objnames)
776  {
777  char *spcname = strVal(lfirst(cell));
778  Oid spcoid;
779 
780  spcoid = get_tablespace_oid(spcname, false);
781  objects = lappend_oid(objects, spcoid);
782  }
783  break;
784  case OBJECT_FDW:
785  foreach(cell, objnames)
786  {
787  char *fdwname = strVal(lfirst(cell));
788  Oid fdwid = get_foreign_data_wrapper_oid(fdwname, false);
789 
790  objects = lappend_oid(objects, fdwid);
791  }
792  break;
794  foreach(cell, objnames)
795  {
796  char *srvname = strVal(lfirst(cell));
797  Oid srvid = get_foreign_server_oid(srvname, false);
798 
799  objects = lappend_oid(objects, srvid);
800  }
801  break;
803  foreach(cell, objnames)
804  {
805  /*
806  * In this code we represent a GUC by the OID of its entry in
807  * pg_parameter_acl, which we have to manufacture here if it
808  * doesn't exist yet. (That's a hack for sure, but it avoids
809  * messing with all the GRANT/REVOKE infrastructure that
810  * expects to use OIDs for object identities.) However, if
811  * this is a REVOKE, we can instead just ignore any GUCs that
812  * don't have such an entry, as they must not have any
813  * privileges needing removal.
814  */
815  char *parameter = strVal(lfirst(cell));
816  Oid parameterId = ParameterAclLookup(parameter, true);
817 
818  if (!OidIsValid(parameterId) && is_grant)
819  {
820  parameterId = ParameterAclCreate(parameter);
821 
822  /*
823  * Prevent error when processing duplicate objects, and
824  * make this new entry visible so that ExecGrant_Parameter
825  * can update it.
826  */
828  }
829  if (OidIsValid(parameterId))
830  objects = lappend_oid(objects, parameterId);
831  }
832  break;
833  default:
834  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
835  (int) objtype);
836  }
837 
838  return objects;
839 }
840 
841 /*
842  * objectsInSchemaToOids
843  *
844  * Find all objects of a given type in specified schemas, and make a list
845  * of their Oids. We check USAGE privilege on the schemas, but there is
846  * no privilege checking on the individual objects here.
847  */
848 static List *
850 {
851  List *objects = NIL;
852  ListCell *cell;
853 
854  foreach(cell, nspnames)
855  {
856  char *nspname = strVal(lfirst(cell));
857  Oid namespaceId;
858  List *objs;
859 
860  namespaceId = LookupExplicitNamespace(nspname, false);
861 
862  switch (objtype)
863  {
864  case OBJECT_TABLE:
865  objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
866  objects = list_concat(objects, objs);
867  objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
868  objects = list_concat(objects, objs);
869  objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
870  objects = list_concat(objects, objs);
871  objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
872  objects = list_concat(objects, objs);
873  objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
874  objects = list_concat(objects, objs);
875  break;
876  case OBJECT_SEQUENCE:
877  objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
878  objects = list_concat(objects, objs);
879  break;
880  case OBJECT_FUNCTION:
881  case OBJECT_PROCEDURE:
882  case OBJECT_ROUTINE:
883  {
884  ScanKeyData key[2];
885  int keycount;
886  Relation rel;
887  TableScanDesc scan;
888  HeapTuple tuple;
889 
890  keycount = 0;
891  ScanKeyInit(&key[keycount++],
892  Anum_pg_proc_pronamespace,
893  BTEqualStrategyNumber, F_OIDEQ,
894  ObjectIdGetDatum(namespaceId));
895 
896  if (objtype == OBJECT_FUNCTION)
897  /* includes aggregates and window functions */
898  ScanKeyInit(&key[keycount++],
899  Anum_pg_proc_prokind,
900  BTEqualStrategyNumber, F_CHARNE,
901  CharGetDatum(PROKIND_PROCEDURE));
902  else if (objtype == OBJECT_PROCEDURE)
903  ScanKeyInit(&key[keycount++],
904  Anum_pg_proc_prokind,
905  BTEqualStrategyNumber, F_CHAREQ,
906  CharGetDatum(PROKIND_PROCEDURE));
907 
908  rel = table_open(ProcedureRelationId, AccessShareLock);
909  scan = table_beginscan_catalog(rel, keycount, key);
910 
911  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
912  {
913  Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
914 
915  objects = lappend_oid(objects, oid);
916  }
917 
918  table_endscan(scan);
920  }
921  break;
922  default:
923  /* should not happen */
924  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
925  (int) objtype);
926  }
927  }
928 
929  return objects;
930 }
931 
932 /*
933  * getRelationsInNamespace
934  *
935  * Return Oid list of relations in given namespace filtered by relation kind
936  */
937 static List *
938 getRelationsInNamespace(Oid namespaceId, char relkind)
939 {
940  List *relations = NIL;
941  ScanKeyData key[2];
942  Relation rel;
943  TableScanDesc scan;
944  HeapTuple tuple;
945 
946  ScanKeyInit(&key[0],
947  Anum_pg_class_relnamespace,
948  BTEqualStrategyNumber, F_OIDEQ,
949  ObjectIdGetDatum(namespaceId));
950  ScanKeyInit(&key[1],
951  Anum_pg_class_relkind,
952  BTEqualStrategyNumber, F_CHAREQ,
953  CharGetDatum(relkind));
954 
955  rel = table_open(RelationRelationId, AccessShareLock);
956  scan = table_beginscan_catalog(rel, 2, key);
957 
958  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
959  {
960  Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
961 
962  relations = lappend_oid(relations, oid);
963  }
964 
965  table_endscan(scan);
967 
968  return relations;
969 }
970 
971 
972 /*
973  * ALTER DEFAULT PRIVILEGES statement
974  */
975 void
977 {
978  GrantStmt *action = stmt->action;
979  InternalDefaultACL iacls;
980  ListCell *cell;
981  List *rolespecs = NIL;
982  List *nspnames = NIL;
983  DefElem *drolespecs = NULL;
984  DefElem *dnspnames = NULL;
985  AclMode all_privileges;
986  const char *errormsg;
987 
988  /* Deconstruct the "options" part of the statement */
989  foreach(cell, stmt->options)
990  {
991  DefElem *defel = (DefElem *) lfirst(cell);
992 
993  if (strcmp(defel->defname, "schemas") == 0)
994  {
995  if (dnspnames)
996  errorConflictingDefElem(defel, pstate);
997  dnspnames = defel;
998  }
999  else if (strcmp(defel->defname, "roles") == 0)
1000  {
1001  if (drolespecs)
1002  errorConflictingDefElem(defel, pstate);
1003  drolespecs = defel;
1004  }
1005  else
1006  elog(ERROR, "option \"%s\" not recognized", defel->defname);
1007  }
1008 
1009  if (dnspnames)
1010  nspnames = (List *) dnspnames->arg;
1011  if (drolespecs)
1012  rolespecs = (List *) drolespecs->arg;
1013 
1014  /* Prepare the InternalDefaultACL representation of the statement */
1015  /* roleid to be filled below */
1016  /* nspid to be filled in SetDefaultACLsInSchemas */
1017  iacls.is_grant = action->is_grant;
1018  iacls.objtype = action->objtype;
1019  /* all_privs to be filled below */
1020  /* privileges to be filled below */
1021  iacls.grantees = NIL; /* filled below */
1022  iacls.grant_option = action->grant_option;
1023  iacls.behavior = action->behavior;
1024 
1025  /*
1026  * Convert the RoleSpec list into an Oid list. Note that at this point we
1027  * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
1028  * there shouldn't be any additional work needed to support this case.
1029  */
1030  foreach(cell, action->grantees)
1031  {
1032  RoleSpec *grantee = (RoleSpec *) lfirst(cell);
1033  Oid grantee_uid;
1034 
1035  switch (grantee->roletype)
1036  {
1037  case ROLESPEC_PUBLIC:
1038  grantee_uid = ACL_ID_PUBLIC;
1039  break;
1040  default:
1041  grantee_uid = get_rolespec_oid(grantee, false);
1042  break;
1043  }
1044  iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
1045  }
1046 
1047  /*
1048  * Convert action->privileges, a list of privilege strings, into an
1049  * AclMode bitmask.
1050  */
1051  switch (action->objtype)
1052  {
1053  case OBJECT_TABLE:
1054  all_privileges = ACL_ALL_RIGHTS_RELATION;
1055  errormsg = gettext_noop("invalid privilege type %s for relation");
1056  break;
1057  case OBJECT_SEQUENCE:
1058  all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1059  errormsg = gettext_noop("invalid privilege type %s for sequence");
1060  break;
1061  case OBJECT_FUNCTION:
1062  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1063  errormsg = gettext_noop("invalid privilege type %s for function");
1064  break;
1065  case OBJECT_PROCEDURE:
1066  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1067  errormsg = gettext_noop("invalid privilege type %s for procedure");
1068  break;
1069  case OBJECT_ROUTINE:
1070  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1071  errormsg = gettext_noop("invalid privilege type %s for routine");
1072  break;
1073  case OBJECT_TYPE:
1074  all_privileges = ACL_ALL_RIGHTS_TYPE;
1075  errormsg = gettext_noop("invalid privilege type %s for type");
1076  break;
1077  case OBJECT_SCHEMA:
1078  all_privileges = ACL_ALL_RIGHTS_SCHEMA;
1079  errormsg = gettext_noop("invalid privilege type %s for schema");
1080  break;
1081  default:
1082  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1083  (int) action->objtype);
1084  /* keep compiler quiet */
1085  all_privileges = ACL_NO_RIGHTS;
1086  errormsg = NULL;
1087  }
1088 
1089  if (action->privileges == NIL)
1090  {
1091  iacls.all_privs = true;
1092 
1093  /*
1094  * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1095  * depending on the object type
1096  */
1097  iacls.privileges = ACL_NO_RIGHTS;
1098  }
1099  else
1100  {
1101  iacls.all_privs = false;
1102  iacls.privileges = ACL_NO_RIGHTS;
1103 
1104  foreach(cell, action->privileges)
1105  {
1106  AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1107  AclMode priv;
1108 
1109  if (privnode->cols)
1110  ereport(ERROR,
1111  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1112  errmsg("default privileges cannot be set for columns")));
1113 
1114  if (privnode->priv_name == NULL) /* parser mistake? */
1115  elog(ERROR, "AccessPriv node must specify privilege");
1116  priv = string_to_privilege(privnode->priv_name);
1117 
1118  if (priv & ~((AclMode) all_privileges))
1119  ereport(ERROR,
1120  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1121  errmsg(errormsg, privilege_to_string(priv))));
1122 
1123  iacls.privileges |= priv;
1124  }
1125  }
1126 
1127  if (rolespecs == NIL)
1128  {
1129  /* Set permissions for myself */
1130  iacls.roleid = GetUserId();
1131 
1132  SetDefaultACLsInSchemas(&iacls, nspnames);
1133  }
1134  else
1135  {
1136  /* Look up the role OIDs and do permissions checks */
1137  ListCell *rolecell;
1138 
1139  foreach(rolecell, rolespecs)
1140  {
1141  RoleSpec *rolespec = lfirst(rolecell);
1142 
1143  iacls.roleid = get_rolespec_oid(rolespec, false);
1144 
1145  if (!has_privs_of_role(GetUserId(), iacls.roleid))
1146  ereport(ERROR,
1147  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1148  errmsg("permission denied to change default privileges")));
1149 
1150  SetDefaultACLsInSchemas(&iacls, nspnames);
1151  }
1152  }
1153 }
1154 
1155 /*
1156  * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1157  *
1158  * All fields of *iacls except nspid were filled already
1159  */
1160 static void
1162 {
1163  if (nspnames == NIL)
1164  {
1165  /* Set database-wide permissions if no schema was specified */
1166  iacls->nspid = InvalidOid;
1167 
1168  SetDefaultACL(iacls);
1169  }
1170  else
1171  {
1172  /* Look up the schema OIDs and set permissions for each one */
1173  ListCell *nspcell;
1174 
1175  foreach(nspcell, nspnames)
1176  {
1177  char *nspname = strVal(lfirst(nspcell));
1178 
1179  iacls->nspid = get_namespace_oid(nspname, false);
1180 
1181  /*
1182  * We used to insist that the target role have CREATE privileges
1183  * on the schema, since without that it wouldn't be able to create
1184  * an object for which these default privileges would apply.
1185  * However, this check proved to be more confusing than helpful,
1186  * and it also caused certain database states to not be
1187  * dumpable/restorable, since revoking CREATE doesn't cause
1188  * default privileges for the schema to go away. So now, we just
1189  * allow the ALTER; if the user lacks CREATE he'll find out when
1190  * he tries to create an object.
1191  */
1192 
1193  SetDefaultACL(iacls);
1194  }
1195  }
1196 }
1197 
1198 
1199 /*
1200  * Create or update a pg_default_acl entry
1201  */
1202 static void
1204 {
1205  AclMode this_privileges = iacls->privileges;
1206  char objtype;
1207  Relation rel;
1208  HeapTuple tuple;
1209  bool isNew;
1210  Acl *def_acl;
1211  Acl *old_acl;
1212  Acl *new_acl;
1213  HeapTuple newtuple;
1214  int noldmembers;
1215  int nnewmembers;
1216  Oid *oldmembers;
1217  Oid *newmembers;
1218 
1219  rel = table_open(DefaultAclRelationId, RowExclusiveLock);
1220 
1221  /*
1222  * The default for a global entry is the hard-wired default ACL for the
1223  * particular object type. The default for non-global entries is an empty
1224  * ACL. This must be so because global entries replace the hard-wired
1225  * defaults, while others are added on.
1226  */
1227  if (!OidIsValid(iacls->nspid))
1228  def_acl = acldefault(iacls->objtype, iacls->roleid);
1229  else
1230  def_acl = make_empty_acl();
1231 
1232  /*
1233  * Convert ACL object type to pg_default_acl object type and handle
1234  * all_privs option
1235  */
1236  switch (iacls->objtype)
1237  {
1238  case OBJECT_TABLE:
1239  objtype = DEFACLOBJ_RELATION;
1240  if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1241  this_privileges = ACL_ALL_RIGHTS_RELATION;
1242  break;
1243 
1244  case OBJECT_SEQUENCE:
1245  objtype = DEFACLOBJ_SEQUENCE;
1246  if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1247  this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1248  break;
1249 
1250  case OBJECT_FUNCTION:
1251  objtype = DEFACLOBJ_FUNCTION;
1252  if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1253  this_privileges = ACL_ALL_RIGHTS_FUNCTION;
1254  break;
1255 
1256  case OBJECT_TYPE:
1257  objtype = DEFACLOBJ_TYPE;
1258  if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1259  this_privileges = ACL_ALL_RIGHTS_TYPE;
1260  break;
1261 
1262  case OBJECT_SCHEMA:
1263  if (OidIsValid(iacls->nspid))
1264  ereport(ERROR,
1265  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1266  errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1267  objtype = DEFACLOBJ_NAMESPACE;
1268  if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1269  this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1270  break;
1271 
1272  default:
1273  elog(ERROR, "unrecognized object type: %d",
1274  (int) iacls->objtype);
1275  objtype = 0; /* keep compiler quiet */
1276  break;
1277  }
1278 
1279  /* Search for existing row for this object type in catalog */
1280  tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1281  ObjectIdGetDatum(iacls->roleid),
1282  ObjectIdGetDatum(iacls->nspid),
1283  CharGetDatum(objtype));
1284 
1285  if (HeapTupleIsValid(tuple))
1286  {
1287  Datum aclDatum;
1288  bool isNull;
1289 
1290  aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1291  Anum_pg_default_acl_defaclacl,
1292  &isNull);
1293  if (!isNull)
1294  old_acl = DatumGetAclPCopy(aclDatum);
1295  else
1296  old_acl = NULL; /* this case shouldn't happen, probably */
1297  isNew = false;
1298  }
1299  else
1300  {
1301  old_acl = NULL;
1302  isNew = true;
1303  }
1304 
1305  if (old_acl != NULL)
1306  {
1307  /*
1308  * We need the members of both old and new ACLs so we can correct the
1309  * shared dependency information. Collect data before
1310  * merge_acl_with_grant throws away old_acl.
1311  */
1312  noldmembers = aclmembers(old_acl, &oldmembers);
1313  }
1314  else
1315  {
1316  /* If no or null entry, start with the default ACL value */
1317  old_acl = aclcopy(def_acl);
1318  /* There are no old member roles according to the catalogs */
1319  noldmembers = 0;
1320  oldmembers = NULL;
1321  }
1322 
1323  /*
1324  * Generate new ACL. Grantor of rights is always the same as the target
1325  * role.
1326  */
1327  new_acl = merge_acl_with_grant(old_acl,
1328  iacls->is_grant,
1329  iacls->grant_option,
1330  iacls->behavior,
1331  iacls->grantees,
1332  this_privileges,
1333  iacls->roleid,
1334  iacls->roleid);
1335 
1336  /*
1337  * If the result is the same as the default value, we do not need an
1338  * explicit pg_default_acl entry, and should in fact remove the entry if
1339  * it exists. Must sort both arrays to compare properly.
1340  */
1341  aclitemsort(new_acl);
1342  aclitemsort(def_acl);
1343  if (aclequal(new_acl, def_acl))
1344  {
1345  /* delete old entry, if indeed there is one */
1346  if (!isNew)
1347  {
1348  ObjectAddress myself;
1349 
1350  /*
1351  * The dependency machinery will take care of removing all
1352  * associated dependency entries. We use DROP_RESTRICT since
1353  * there shouldn't be anything depending on this entry.
1354  */
1355  myself.classId = DefaultAclRelationId;
1356  myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1357  myself.objectSubId = 0;
1358 
1359  performDeletion(&myself, DROP_RESTRICT, 0);
1360  }
1361  }
1362  else
1363  {
1364  Datum values[Natts_pg_default_acl] = {0};
1365  bool nulls[Natts_pg_default_acl] = {0};
1366  bool replaces[Natts_pg_default_acl] = {0};
1367  Oid defAclOid;
1368 
1369  if (isNew)
1370  {
1371  /* insert new entry */
1372  defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1373  Anum_pg_default_acl_oid);
1374  values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1375  values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1376  values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1377  values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1378  values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1379 
1380  newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1381  CatalogTupleInsert(rel, newtuple);
1382  }
1383  else
1384  {
1385  defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1386 
1387  /* update existing entry */
1388  values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1389  replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1390 
1391  newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1392  values, nulls, replaces);
1393  CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1394  }
1395 
1396  /* these dependencies don't change in an update */
1397  if (isNew)
1398  {
1399  /* dependency on role */
1400  recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1401  iacls->roleid);
1402 
1403  /* dependency on namespace */
1404  if (OidIsValid(iacls->nspid))
1405  {
1406  ObjectAddress myself,
1407  referenced;
1408 
1409  myself.classId = DefaultAclRelationId;
1410  myself.objectId = defAclOid;
1411  myself.objectSubId = 0;
1412 
1413  referenced.classId = NamespaceRelationId;
1414  referenced.objectId = iacls->nspid;
1415  referenced.objectSubId = 0;
1416 
1417  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1418  }
1419  }
1420 
1421  /*
1422  * Update the shared dependency ACL info
1423  */
1424  nnewmembers = aclmembers(new_acl, &newmembers);
1425 
1426  updateAclDependencies(DefaultAclRelationId,
1427  defAclOid, 0,
1428  iacls->roleid,
1429  noldmembers, oldmembers,
1430  nnewmembers, newmembers);
1431 
1432  if (isNew)
1433  InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1434  else
1435  InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1436  }
1437 
1438  if (HeapTupleIsValid(tuple))
1439  ReleaseSysCache(tuple);
1440 
1442 
1443  /* prevent error when processing duplicate objects */
1445 }
1446 
1447 
1448 /*
1449  * RemoveRoleFromObjectACL
1450  *
1451  * Used by shdepDropOwned to remove mentions of a role in ACLs.
1452  *
1453  * Notice that this doesn't accept an objsubid parameter, which is a bit bogus
1454  * since the pg_shdepend record that caused us to call it certainly had one.
1455  * If, for example, pg_shdepend records the existence of a permission on
1456  * mytable.mycol, this function will effectively issue a REVOKE ALL ON TABLE
1457  * mytable. That gets the job done because (per SQL spec) such a REVOKE also
1458  * revokes per-column permissions. We could not recreate a situation where
1459  * the role has table-level but not column-level permissions; but it's okay
1460  * (for now anyway) because this is only used when we're dropping the role
1461  * and so all its permissions everywhere must go away. At worst it's a bit
1462  * inefficient if the role has column permissions on several columns of the
1463  * same table.
1464  */
1465 void
1466 RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1467 {
1468  if (classid == DefaultAclRelationId)
1469  {
1470  InternalDefaultACL iacls;
1471  Form_pg_default_acl pg_default_acl_tuple;
1472  Relation rel;
1473  ScanKeyData skey[1];
1474  SysScanDesc scan;
1475  HeapTuple tuple;
1476 
1477  /* first fetch info needed by SetDefaultACL */
1478  rel = table_open(DefaultAclRelationId, AccessShareLock);
1479 
1480  ScanKeyInit(&skey[0],
1481  Anum_pg_default_acl_oid,
1482  BTEqualStrategyNumber, F_OIDEQ,
1483  ObjectIdGetDatum(objid));
1484 
1485  scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1486  NULL, 1, skey);
1487 
1488  tuple = systable_getnext(scan);
1489 
1490  if (!HeapTupleIsValid(tuple))
1491  elog(ERROR, "could not find tuple for default ACL %u", objid);
1492 
1493  pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1494 
1495  iacls.roleid = pg_default_acl_tuple->defaclrole;
1496  iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1497 
1498  switch (pg_default_acl_tuple->defaclobjtype)
1499  {
1500  case DEFACLOBJ_RELATION:
1501  iacls.objtype = OBJECT_TABLE;
1502  break;
1503  case DEFACLOBJ_SEQUENCE:
1504  iacls.objtype = OBJECT_SEQUENCE;
1505  break;
1506  case DEFACLOBJ_FUNCTION:
1507  iacls.objtype = OBJECT_FUNCTION;
1508  break;
1509  case DEFACLOBJ_TYPE:
1510  iacls.objtype = OBJECT_TYPE;
1511  break;
1512  case DEFACLOBJ_NAMESPACE:
1513  iacls.objtype = OBJECT_SCHEMA;
1514  break;
1515  default:
1516  /* Shouldn't get here */
1517  elog(ERROR, "unexpected default ACL type: %d",
1518  (int) pg_default_acl_tuple->defaclobjtype);
1519  break;
1520  }
1521 
1522  systable_endscan(scan);
1524 
1525  iacls.is_grant = false;
1526  iacls.all_privs = true;
1527  iacls.privileges = ACL_NO_RIGHTS;
1528  iacls.grantees = list_make1_oid(roleid);
1529  iacls.grant_option = false;
1530  iacls.behavior = DROP_CASCADE;
1531 
1532  /* Do it */
1533  SetDefaultACL(&iacls);
1534  }
1535  else
1536  {
1537  InternalGrant istmt;
1538 
1539  switch (classid)
1540  {
1541  case RelationRelationId:
1542  /* it's OK to use TABLE for a sequence */
1543  istmt.objtype = OBJECT_TABLE;
1544  break;
1545  case DatabaseRelationId:
1546  istmt.objtype = OBJECT_DATABASE;
1547  break;
1548  case TypeRelationId:
1549  istmt.objtype = OBJECT_TYPE;
1550  break;
1551  case ProcedureRelationId:
1552  istmt.objtype = OBJECT_ROUTINE;
1553  break;
1554  case LanguageRelationId:
1555  istmt.objtype = OBJECT_LANGUAGE;
1556  break;
1557  case LargeObjectRelationId:
1558  istmt.objtype = OBJECT_LARGEOBJECT;
1559  break;
1560  case NamespaceRelationId:
1561  istmt.objtype = OBJECT_SCHEMA;
1562  break;
1563  case TableSpaceRelationId:
1564  istmt.objtype = OBJECT_TABLESPACE;
1565  break;
1566  case ForeignServerRelationId:
1568  break;
1569  case ForeignDataWrapperRelationId:
1570  istmt.objtype = OBJECT_FDW;
1571  break;
1572  case ParameterAclRelationId:
1573  istmt.objtype = OBJECT_PARAMETER_ACL;
1574  break;
1575  default:
1576  elog(ERROR, "unexpected object class %u", classid);
1577  break;
1578  }
1579  istmt.is_grant = false;
1580  istmt.objects = list_make1_oid(objid);
1581  istmt.all_privs = true;
1582  istmt.privileges = ACL_NO_RIGHTS;
1583  istmt.col_privs = NIL;
1584  istmt.grantees = list_make1_oid(roleid);
1585  istmt.grant_option = false;
1586  istmt.behavior = DROP_CASCADE;
1587 
1588  ExecGrantStmt_oids(&istmt);
1589  }
1590 }
1591 
1592 
1593 /*
1594  * expand_col_privileges
1595  *
1596  * OR the specified privilege(s) into per-column array entries for each
1597  * specified attribute. The per-column array is indexed starting at
1598  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1599  */
1600 static void
1601 expand_col_privileges(List *colnames, Oid table_oid,
1602  AclMode this_privileges,
1603  AclMode *col_privileges,
1604  int num_col_privileges)
1605 {
1606  ListCell *cell;
1607 
1608  foreach(cell, colnames)
1609  {
1610  char *colname = strVal(lfirst(cell));
1612 
1613  attnum = get_attnum(table_oid, colname);
1614  if (attnum == InvalidAttrNumber)
1615  ereport(ERROR,
1616  (errcode(ERRCODE_UNDEFINED_COLUMN),
1617  errmsg("column \"%s\" of relation \"%s\" does not exist",
1618  colname, get_rel_name(table_oid))));
1620  if (attnum <= 0 || attnum >= num_col_privileges)
1621  elog(ERROR, "column number out of range"); /* safety check */
1622  col_privileges[attnum] |= this_privileges;
1623  }
1624 }
1625 
1626 /*
1627  * expand_all_col_privileges
1628  *
1629  * OR the specified privilege(s) into per-column array entries for each valid
1630  * attribute of a relation. The per-column array is indexed starting at
1631  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1632  */
1633 static void
1635  AclMode this_privileges,
1636  AclMode *col_privileges,
1637  int num_col_privileges)
1638 {
1639  AttrNumber curr_att;
1640 
1641  Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1642  for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1643  curr_att <= classForm->relnatts;
1644  curr_att++)
1645  {
1646  HeapTuple attTuple;
1647  bool isdropped;
1648 
1649  if (curr_att == InvalidAttrNumber)
1650  continue;
1651 
1652  /* Views don't have any system columns at all */
1653  if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1654  continue;
1655 
1656  attTuple = SearchSysCache2(ATTNUM,
1657  ObjectIdGetDatum(table_oid),
1658  Int16GetDatum(curr_att));
1659  if (!HeapTupleIsValid(attTuple))
1660  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1661  curr_att, table_oid);
1662 
1663  isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1664 
1665  ReleaseSysCache(attTuple);
1666 
1667  /* ignore dropped columns */
1668  if (isdropped)
1669  continue;
1670 
1671  col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1672  }
1673 }
1674 
1675 /*
1676  * This processes attributes, but expects to be called from
1677  * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1678  */
1679 static void
1680 ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1681  AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1682  Relation attRelation, const Acl *old_rel_acl)
1683 {
1684  HeapTuple attr_tuple;
1685  Form_pg_attribute pg_attribute_tuple;
1686  Acl *old_acl;
1687  Acl *new_acl;
1688  Acl *merged_acl;
1689  Datum aclDatum;
1690  bool isNull;
1691  Oid grantorId;
1692  AclMode avail_goptions;
1693  bool need_update;
1694  HeapTuple newtuple;
1695  Datum values[Natts_pg_attribute] = {0};
1696  bool nulls[Natts_pg_attribute] = {0};
1697  bool replaces[Natts_pg_attribute] = {0};
1698  int noldmembers;
1699  int nnewmembers;
1700  Oid *oldmembers;
1701  Oid *newmembers;
1702 
1703  attr_tuple = SearchSysCache2(ATTNUM,
1704  ObjectIdGetDatum(relOid),
1706  if (!HeapTupleIsValid(attr_tuple))
1707  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1708  attnum, relOid);
1709  pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1710 
1711  /*
1712  * Get working copy of existing ACL. If there's no ACL, substitute the
1713  * proper default.
1714  */
1715  aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1716  &isNull);
1717  if (isNull)
1718  {
1719  old_acl = acldefault(OBJECT_COLUMN, ownerId);
1720  /* There are no old member roles according to the catalogs */
1721  noldmembers = 0;
1722  oldmembers = NULL;
1723  }
1724  else
1725  {
1726  old_acl = DatumGetAclPCopy(aclDatum);
1727  /* Get the roles mentioned in the existing ACL */
1728  noldmembers = aclmembers(old_acl, &oldmembers);
1729  }
1730 
1731  /*
1732  * In select_best_grantor we should consider existing table-level ACL bits
1733  * as well as the per-column ACL. Build a new ACL that is their
1734  * concatenation. (This is a bit cheap and dirty compared to merging them
1735  * properly with no duplications, but it's all we need here.)
1736  */
1737  merged_acl = aclconcat(old_rel_acl, old_acl);
1738 
1739  /* Determine ID to do the grant as, and available grant options */
1740  select_best_grantor(GetUserId(), col_privileges,
1741  merged_acl, ownerId,
1742  &grantorId, &avail_goptions);
1743 
1744  pfree(merged_acl);
1745 
1746  /*
1747  * Restrict the privileges to what we can actually grant, and emit the
1748  * standards-mandated warning and error messages. Note: we don't track
1749  * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1750  * each column; we just approximate it by whether all the possible
1751  * privileges are specified now. Since the all_privs flag only determines
1752  * whether a warning is issued, this seems close enough.
1753  */
1754  col_privileges =
1755  restrict_and_check_grant(istmt->is_grant, avail_goptions,
1756  (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1757  col_privileges,
1758  relOid, grantorId, OBJECT_COLUMN,
1759  relname, attnum,
1760  NameStr(pg_attribute_tuple->attname));
1761 
1762  /*
1763  * Generate new ACL.
1764  */
1765  new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1766  istmt->grant_option,
1767  istmt->behavior, istmt->grantees,
1768  col_privileges, grantorId,
1769  ownerId);
1770 
1771  /*
1772  * We need the members of both old and new ACLs so we can correct the
1773  * shared dependency information.
1774  */
1775  nnewmembers = aclmembers(new_acl, &newmembers);
1776 
1777  /* finished building new ACL value, now insert it */
1778 
1779  /*
1780  * If the updated ACL is empty, we can set attacl to null, and maybe even
1781  * avoid an update of the pg_attribute row. This is worth testing because
1782  * we'll come through here multiple times for any relation-level REVOKE,
1783  * even if there were never any column GRANTs. Note we are assuming that
1784  * the "default" ACL state for columns is empty.
1785  */
1786  if (ACL_NUM(new_acl) > 0)
1787  {
1788  values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1789  need_update = true;
1790  }
1791  else
1792  {
1793  nulls[Anum_pg_attribute_attacl - 1] = true;
1794  need_update = !isNull;
1795  }
1796  replaces[Anum_pg_attribute_attacl - 1] = true;
1797 
1798  if (need_update)
1799  {
1800  newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1801  values, nulls, replaces);
1802 
1803  CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1804 
1805  /* Update initial privileges for extensions */
1806  recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1807  ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1808 
1809  /* Update the shared dependency ACL info */
1810  updateAclDependencies(RelationRelationId, relOid, attnum,
1811  ownerId,
1812  noldmembers, oldmembers,
1813  nnewmembers, newmembers);
1814  }
1815 
1816  pfree(new_acl);
1817 
1818  ReleaseSysCache(attr_tuple);
1819 }
1820 
1821 /*
1822  * This processes both sequences and non-sequences.
1823  */
1824 static void
1826 {
1827  Relation relation;
1828  Relation attRelation;
1829  ListCell *cell;
1830 
1831  relation = table_open(RelationRelationId, RowExclusiveLock);
1832  attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1833 
1834  foreach(cell, istmt->objects)
1835  {
1836  Oid relOid = lfirst_oid(cell);
1837  Datum aclDatum;
1838  Form_pg_class pg_class_tuple;
1839  bool isNull;
1840  AclMode this_privileges;
1841  AclMode *col_privileges;
1842  int num_col_privileges;
1843  bool have_col_privileges;
1844  Acl *old_acl;
1845  Acl *old_rel_acl;
1846  int noldmembers;
1847  Oid *oldmembers;
1848  Oid ownerId;
1849  HeapTuple tuple;
1850  ListCell *cell_colprivs;
1851 
1852  tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relOid));
1853  if (!HeapTupleIsValid(tuple))
1854  elog(ERROR, "cache lookup failed for relation %u", relOid);
1855  pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1856 
1857  /* Not sensible to grant on an index */
1858  if (pg_class_tuple->relkind == RELKIND_INDEX ||
1859  pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1860  ereport(ERROR,
1861  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1862  errmsg("\"%s\" is an index",
1863  NameStr(pg_class_tuple->relname))));
1864 
1865  /* Composite types aren't tables either */
1866  if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1867  ereport(ERROR,
1868  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1869  errmsg("\"%s\" is a composite type",
1870  NameStr(pg_class_tuple->relname))));
1871 
1872  /* Used GRANT SEQUENCE on a non-sequence? */
1873  if (istmt->objtype == OBJECT_SEQUENCE &&
1874  pg_class_tuple->relkind != RELKIND_SEQUENCE)
1875  ereport(ERROR,
1876  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1877  errmsg("\"%s\" is not a sequence",
1878  NameStr(pg_class_tuple->relname))));
1879 
1880  /* Adjust the default permissions based on object type */
1881  if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1882  {
1883  if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1884  this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1885  else
1886  this_privileges = ACL_ALL_RIGHTS_RELATION;
1887  }
1888  else
1889  this_privileges = istmt->privileges;
1890 
1891  /*
1892  * The GRANT TABLE syntax can be used for sequences and non-sequences,
1893  * so we have to look at the relkind to determine the supported
1894  * permissions. The OR of table and sequence permissions were already
1895  * checked.
1896  */
1897  if (istmt->objtype == OBJECT_TABLE)
1898  {
1899  if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1900  {
1901  /*
1902  * For backward compatibility, just throw a warning for
1903  * invalid sequence permissions when using the non-sequence
1904  * GRANT syntax.
1905  */
1906  if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1907  {
1908  /*
1909  * Mention the object name because the user needs to know
1910  * which operations succeeded. This is required because
1911  * WARNING allows the command to continue.
1912  */
1913  ereport(WARNING,
1914  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1915  errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1916  NameStr(pg_class_tuple->relname))));
1917  this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1918  }
1919  }
1920  else
1921  {
1922  if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1923  {
1924  /*
1925  * USAGE is the only permission supported by sequences but
1926  * not by non-sequences. Don't mention the object name
1927  * because we didn't in the combined TABLE | SEQUENCE
1928  * check.
1929  */
1930  ereport(ERROR,
1931  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1932  errmsg("invalid privilege type %s for table",
1933  "USAGE")));
1934  }
1935  }
1936  }
1937 
1938  /*
1939  * Set up array in which we'll accumulate any column privilege bits
1940  * that need modification. The array is indexed such that entry [0]
1941  * corresponds to FirstLowInvalidHeapAttributeNumber.
1942  */
1943  num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1944  col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1945  have_col_privileges = false;
1946 
1947  /*
1948  * If we are revoking relation privileges that are also column
1949  * privileges, we must implicitly revoke them from each column too,
1950  * per SQL spec. (We don't need to implicitly add column privileges
1951  * during GRANT because the permissions-checking code always checks
1952  * both relation and per-column privileges.)
1953  */
1954  if (!istmt->is_grant &&
1955  (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1956  {
1957  expand_all_col_privileges(relOid, pg_class_tuple,
1958  this_privileges & ACL_ALL_RIGHTS_COLUMN,
1959  col_privileges,
1960  num_col_privileges);
1961  have_col_privileges = true;
1962  }
1963 
1964  /*
1965  * Get owner ID and working copy of existing ACL. If there's no ACL,
1966  * substitute the proper default.
1967  */
1968  ownerId = pg_class_tuple->relowner;
1969  aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1970  &isNull);
1971  if (isNull)
1972  {
1973  switch (pg_class_tuple->relkind)
1974  {
1975  case RELKIND_SEQUENCE:
1976  old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1977  break;
1978  default:
1979  old_acl = acldefault(OBJECT_TABLE, ownerId);
1980  break;
1981  }
1982  /* There are no old member roles according to the catalogs */
1983  noldmembers = 0;
1984  oldmembers = NULL;
1985  }
1986  else
1987  {
1988  old_acl = DatumGetAclPCopy(aclDatum);
1989  /* Get the roles mentioned in the existing ACL */
1990  noldmembers = aclmembers(old_acl, &oldmembers);
1991  }
1992 
1993  /* Need an extra copy of original rel ACL for column handling */
1994  old_rel_acl = aclcopy(old_acl);
1995 
1996  /*
1997  * Handle relation-level privileges, if any were specified
1998  */
1999  if (this_privileges != ACL_NO_RIGHTS)
2000  {
2001  AclMode avail_goptions;
2002  Acl *new_acl;
2003  Oid grantorId;
2004  HeapTuple newtuple;
2005  Datum values[Natts_pg_class] = {0};
2006  bool nulls[Natts_pg_class] = {0};
2007  bool replaces[Natts_pg_class] = {0};
2008  int nnewmembers;
2009  Oid *newmembers;
2010  ObjectType objtype;
2011 
2012  /* Determine ID to do the grant as, and available grant options */
2013  select_best_grantor(GetUserId(), this_privileges,
2014  old_acl, ownerId,
2015  &grantorId, &avail_goptions);
2016 
2017  switch (pg_class_tuple->relkind)
2018  {
2019  case RELKIND_SEQUENCE:
2020  objtype = OBJECT_SEQUENCE;
2021  break;
2022  default:
2023  objtype = OBJECT_TABLE;
2024  break;
2025  }
2026 
2027  /*
2028  * Restrict the privileges to what we can actually grant, and emit
2029  * the standards-mandated warning and error messages.
2030  */
2031  this_privileges =
2032  restrict_and_check_grant(istmt->is_grant, avail_goptions,
2033  istmt->all_privs, this_privileges,
2034  relOid, grantorId, objtype,
2035  NameStr(pg_class_tuple->relname),
2036  0, NULL);
2037 
2038  /*
2039  * Generate new ACL.
2040  */
2041  new_acl = merge_acl_with_grant(old_acl,
2042  istmt->is_grant,
2043  istmt->grant_option,
2044  istmt->behavior,
2045  istmt->grantees,
2046  this_privileges,
2047  grantorId,
2048  ownerId);
2049 
2050  /*
2051  * We need the members of both old and new ACLs so we can correct
2052  * the shared dependency information.
2053  */
2054  nnewmembers = aclmembers(new_acl, &newmembers);
2055 
2056  /* finished building new ACL value, now insert it */
2057  replaces[Anum_pg_class_relacl - 1] = true;
2058  values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
2059 
2060  newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2061  values, nulls, replaces);
2062 
2063  CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2064  UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2065 
2066  /* Update initial privileges for extensions */
2067  recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2068 
2069  /* Update the shared dependency ACL info */
2070  updateAclDependencies(RelationRelationId, relOid, 0,
2071  ownerId,
2072  noldmembers, oldmembers,
2073  nnewmembers, newmembers);
2074 
2075  pfree(new_acl);
2076  }
2077  else
2078  UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2079 
2080  /*
2081  * Handle column-level privileges, if any were specified or implied.
2082  * We first expand the user-specified column privileges into the
2083  * array, and then iterate over all nonempty array entries.
2084  */
2085  foreach(cell_colprivs, istmt->col_privs)
2086  {
2087  AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2088 
2089  if (col_privs->priv_name == NULL)
2090  this_privileges = ACL_ALL_RIGHTS_COLUMN;
2091  else
2092  this_privileges = string_to_privilege(col_privs->priv_name);
2093 
2094  if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2095  ereport(ERROR,
2096  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2097  errmsg("invalid privilege type %s for column",
2098  privilege_to_string(this_privileges))));
2099 
2100  if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2101  this_privileges & ~((AclMode) ACL_SELECT))
2102  {
2103  /*
2104  * The only column privilege allowed on sequences is SELECT.
2105  * This is a warning not error because we do it that way for
2106  * relation-level privileges.
2107  */
2108  ereport(WARNING,
2109  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2110  errmsg("sequence \"%s\" only supports SELECT column privileges",
2111  NameStr(pg_class_tuple->relname))));
2112 
2113  this_privileges &= (AclMode) ACL_SELECT;
2114  }
2115 
2116  expand_col_privileges(col_privs->cols, relOid,
2117  this_privileges,
2118  col_privileges,
2119  num_col_privileges);
2120  have_col_privileges = true;
2121  }
2122 
2123  if (have_col_privileges)
2124  {
2125  AttrNumber i;
2126 
2127  for (i = 0; i < num_col_privileges; i++)
2128  {
2129  if (col_privileges[i] == ACL_NO_RIGHTS)
2130  continue;
2131  ExecGrant_Attribute(istmt,
2132  relOid,
2133  NameStr(pg_class_tuple->relname),
2135  ownerId,
2136  col_privileges[i],
2137  attRelation,
2138  old_rel_acl);
2139  }
2140  }
2141 
2142  pfree(old_rel_acl);
2143  pfree(col_privileges);
2144 
2145  ReleaseSysCache(tuple);
2146 
2147  /* prevent error when processing duplicate objects */
2149  }
2150 
2151  table_close(attRelation, RowExclusiveLock);
2152  table_close(relation, RowExclusiveLock);
2153 }
2154 
2155 static void
2156 ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
2157  void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
2158 {
2159  int cacheid;
2160  Relation relation;
2161  ListCell *cell;
2162 
2163  if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2164  istmt->privileges = default_privs;
2165 
2166  cacheid = get_object_catcache_oid(classid);
2167 
2168  relation = table_open(classid, RowExclusiveLock);
2169 
2170  foreach(cell, istmt->objects)
2171  {
2172  Oid objectid = lfirst_oid(cell);
2173  Datum aclDatum;
2174  Datum nameDatum;
2175  bool isNull;
2176  AclMode avail_goptions;
2177  AclMode this_privileges;
2178  Acl *old_acl;
2179  Acl *new_acl;
2180  Oid grantorId;
2181  Oid ownerId;
2182  HeapTuple tuple;
2183  HeapTuple newtuple;
2184  Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2185  bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2186  bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2187  int noldmembers;
2188  int nnewmembers;
2189  Oid *oldmembers;
2190  Oid *newmembers;
2191 
2192  tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid));
2193  if (!HeapTupleIsValid(tuple))
2194  elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2195 
2196  /*
2197  * Additional object-type-specific checks
2198  */
2199  if (object_check)
2200  object_check(istmt, tuple);
2201 
2202  /*
2203  * Get owner ID and working copy of existing ACL. If there's no ACL,
2204  * substitute the proper default.
2205  */
2206  ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2207  tuple,
2208  get_object_attnum_owner(classid)));
2209  aclDatum = SysCacheGetAttr(cacheid,
2210  tuple,
2211  get_object_attnum_acl(classid),
2212  &isNull);
2213  if (isNull)
2214  {
2215  old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2216  /* There are no old member roles according to the catalogs */
2217  noldmembers = 0;
2218  oldmembers = NULL;
2219  }
2220  else
2221  {
2222  old_acl = DatumGetAclPCopy(aclDatum);
2223  /* Get the roles mentioned in the existing ACL */
2224  noldmembers = aclmembers(old_acl, &oldmembers);
2225  }
2226 
2227  /* Determine ID to do the grant as, and available grant options */
2229  old_acl, ownerId,
2230  &grantorId, &avail_goptions);
2231 
2232  nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2233  get_object_attnum_name(classid));
2234 
2235  /*
2236  * Restrict the privileges to what we can actually grant, and emit the
2237  * standards-mandated warning and error messages.
2238  */
2239  this_privileges =
2240  restrict_and_check_grant(istmt->is_grant, avail_goptions,
2241  istmt->all_privs, istmt->privileges,
2242  objectid, grantorId, get_object_type(classid, objectid),
2243  NameStr(*DatumGetName(nameDatum)),
2244  0, NULL);
2245 
2246  /*
2247  * Generate new ACL.
2248  */
2249  new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2250  istmt->grant_option, istmt->behavior,
2251  istmt->grantees, this_privileges,
2252  grantorId, ownerId);
2253 
2254  /*
2255  * We need the members of both old and new ACLs so we can correct the
2256  * shared dependency information.
2257  */
2258  nnewmembers = aclmembers(new_acl, &newmembers);
2259 
2260  /* finished building new ACL value, now insert it */
2261  replaces[get_object_attnum_acl(classid) - 1] = true;
2262  values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2263 
2264  newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2265  nulls, replaces);
2266 
2267  CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2268  UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2269 
2270  /* Update initial privileges for extensions */
2271  recordExtensionInitPriv(objectid, classid, 0, new_acl);
2272 
2273  /* Update the shared dependency ACL info */
2274  updateAclDependencies(classid,
2275  objectid, 0,
2276  ownerId,
2277  noldmembers, oldmembers,
2278  nnewmembers, newmembers);
2279 
2280  ReleaseSysCache(tuple);
2281 
2282  pfree(new_acl);
2283 
2284  /* prevent error when processing duplicate objects */
2286  }
2287 
2288  table_close(relation, RowExclusiveLock);
2289 }
2290 
2291 static void
2293 {
2294  Form_pg_language pg_language_tuple;
2295 
2296  pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2297 
2298  if (!pg_language_tuple->lanpltrusted)
2299  ereport(ERROR,
2300  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2301  errmsg("language \"%s\" is not trusted",
2302  NameStr(pg_language_tuple->lanname)),
2303  errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2304  "because only superusers can use untrusted languages.")));
2305 }
2306 
2307 static void
2309 {
2310  Relation relation;
2311  ListCell *cell;
2312 
2313  if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2315 
2316  relation = table_open(LargeObjectMetadataRelationId,
2318 
2319  foreach(cell, istmt->objects)
2320  {
2321  Oid loid = lfirst_oid(cell);
2322  Form_pg_largeobject_metadata form_lo_meta;
2323  char loname[NAMEDATALEN];
2324  Datum aclDatum;
2325  bool isNull;
2326  AclMode avail_goptions;
2327  AclMode this_privileges;
2328  Acl *old_acl;
2329  Acl *new_acl;
2330  Oid grantorId;
2331  Oid ownerId;
2332  HeapTuple newtuple;
2333  Datum values[Natts_pg_largeobject_metadata] = {0};
2334  bool nulls[Natts_pg_largeobject_metadata] = {0};
2335  bool replaces[Natts_pg_largeobject_metadata] = {0};
2336  int noldmembers;
2337  int nnewmembers;
2338  Oid *oldmembers;
2339  Oid *newmembers;
2340  ScanKeyData entry[1];
2341  SysScanDesc scan;
2342  HeapTuple tuple;
2343 
2344  /* There's no syscache for pg_largeobject_metadata */
2345  ScanKeyInit(&entry[0],
2346  Anum_pg_largeobject_metadata_oid,
2347  BTEqualStrategyNumber, F_OIDEQ,
2348  ObjectIdGetDatum(loid));
2349 
2350  scan = systable_beginscan(relation,
2351  LargeObjectMetadataOidIndexId, true,
2352  NULL, 1, entry);
2353 
2354  tuple = systable_getnext(scan);
2355  if (!HeapTupleIsValid(tuple))
2356  elog(ERROR, "could not find tuple for large object %u", loid);
2357 
2358  form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2359 
2360  /*
2361  * Get owner ID and working copy of existing ACL. If there's no ACL,
2362  * substitute the proper default.
2363  */
2364  ownerId = form_lo_meta->lomowner;
2365  aclDatum = heap_getattr(tuple,
2366  Anum_pg_largeobject_metadata_lomacl,
2367  RelationGetDescr(relation), &isNull);
2368  if (isNull)
2369  {
2370  old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2371  /* There are no old member roles according to the catalogs */
2372  noldmembers = 0;
2373  oldmembers = NULL;
2374  }
2375  else
2376  {
2377  old_acl = DatumGetAclPCopy(aclDatum);
2378  /* Get the roles mentioned in the existing ACL */
2379  noldmembers = aclmembers(old_acl, &oldmembers);
2380  }
2381 
2382  /* Determine ID to do the grant as, and available grant options */
2384  old_acl, ownerId,
2385  &grantorId, &avail_goptions);
2386 
2387  /*
2388  * Restrict the privileges to what we can actually grant, and emit the
2389  * standards-mandated warning and error messages.
2390  */
2391  snprintf(loname, sizeof(loname), "large object %u", loid);
2392  this_privileges =
2393  restrict_and_check_grant(istmt->is_grant, avail_goptions,
2394  istmt->all_privs, istmt->privileges,
2395  loid, grantorId, OBJECT_LARGEOBJECT,
2396  loname, 0, NULL);
2397 
2398  /*
2399  * Generate new ACL.
2400  */
2401  new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2402  istmt->grant_option, istmt->behavior,
2403  istmt->grantees, this_privileges,
2404  grantorId, ownerId);
2405 
2406  /*
2407  * We need the members of both old and new ACLs so we can correct the
2408  * shared dependency information.
2409  */
2410  nnewmembers = aclmembers(new_acl, &newmembers);
2411 
2412  /* finished building new ACL value, now insert it */
2413  replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2414  values[Anum_pg_largeobject_metadata_lomacl - 1]
2415  = PointerGetDatum(new_acl);
2416 
2417  newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2418  values, nulls, replaces);
2419 
2420  CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2421 
2422  /* Update initial privileges for extensions */
2423  recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2424 
2425  /* Update the shared dependency ACL info */
2426  updateAclDependencies(LargeObjectRelationId,
2427  form_lo_meta->oid, 0,
2428  ownerId,
2429  noldmembers, oldmembers,
2430  nnewmembers, newmembers);
2431 
2432  systable_endscan(scan);
2433 
2434  pfree(new_acl);
2435 
2436  /* prevent error when processing duplicate objects */
2438  }
2439 
2440  table_close(relation, RowExclusiveLock);
2441 }
2442 
2443 static void
2445 {
2446  Form_pg_type pg_type_tuple;
2447 
2448  pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2449 
2450  /* Disallow GRANT on dependent types */
2451  if (IsTrueArrayType(pg_type_tuple))
2452  ereport(ERROR,
2453  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2454  errmsg("cannot set privileges of array types"),
2455  errhint("Set the privileges of the element type instead.")));
2456  if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2457  ereport(ERROR,
2458  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2459  errmsg("cannot set privileges of multirange types"),
2460  errhint("Set the privileges of the range type instead.")));
2461 
2462  /* Used GRANT DOMAIN on a non-domain? */
2463  if (istmt->objtype == OBJECT_DOMAIN &&
2464  pg_type_tuple->typtype != TYPTYPE_DOMAIN)
2465  ereport(ERROR,
2466  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2467  errmsg("\"%s\" is not a domain",
2468  NameStr(pg_type_tuple->typname))));
2469 }
2470 
2471 static void
2473 {
2474  Relation relation;
2475  ListCell *cell;
2476 
2477  if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2479 
2480  relation = table_open(ParameterAclRelationId, RowExclusiveLock);
2481 
2482  foreach(cell, istmt->objects)
2483  {
2484  Oid parameterId = lfirst_oid(cell);
2485  Datum nameDatum;
2486  const char *parname;
2487  Datum aclDatum;
2488  bool isNull;
2489  AclMode avail_goptions;
2490  AclMode this_privileges;
2491  Acl *old_acl;
2492  Acl *new_acl;
2493  Oid grantorId;
2494  Oid ownerId;
2495  HeapTuple tuple;
2496  int noldmembers;
2497  int nnewmembers;
2498  Oid *oldmembers;
2499  Oid *newmembers;
2500 
2501  tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
2502  if (!HeapTupleIsValid(tuple))
2503  elog(ERROR, "cache lookup failed for parameter ACL %u",
2504  parameterId);
2505 
2506  /* We'll need the GUC's name */
2507  nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
2508  Anum_pg_parameter_acl_parname);
2509  parname = TextDatumGetCString(nameDatum);
2510 
2511  /* Treat all parameters as belonging to the bootstrap superuser. */
2512  ownerId = BOOTSTRAP_SUPERUSERID;
2513 
2514  /*
2515  * Get working copy of existing ACL. If there's no ACL, substitute the
2516  * proper default.
2517  */
2518  aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
2519  Anum_pg_parameter_acl_paracl,
2520  &isNull);
2521 
2522  if (isNull)
2523  {
2524  old_acl = acldefault(istmt->objtype, ownerId);
2525  /* There are no old member roles according to the catalogs */
2526  noldmembers = 0;
2527  oldmembers = NULL;
2528  }
2529  else
2530  {
2531  old_acl = DatumGetAclPCopy(aclDatum);
2532  /* Get the roles mentioned in the existing ACL */
2533  noldmembers = aclmembers(old_acl, &oldmembers);
2534  }
2535 
2536  /* Determine ID to do the grant as, and available grant options */
2538  old_acl, ownerId,
2539  &grantorId, &avail_goptions);
2540 
2541  /*
2542  * Restrict the privileges to what we can actually grant, and emit the
2543  * standards-mandated warning and error messages.
2544  */
2545  this_privileges =
2546  restrict_and_check_grant(istmt->is_grant, avail_goptions,
2547  istmt->all_privs, istmt->privileges,
2548  parameterId, grantorId,
2550  parname,
2551  0, NULL);
2552 
2553  /*
2554  * Generate new ACL.
2555  */
2556  new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2557  istmt->grant_option, istmt->behavior,
2558  istmt->grantees, this_privileges,
2559  grantorId, ownerId);
2560 
2561  /*
2562  * We need the members of both old and new ACLs so we can correct the
2563  * shared dependency information.
2564  */
2565  nnewmembers = aclmembers(new_acl, &newmembers);
2566 
2567  /*
2568  * If the new ACL is equal to the default, we don't need the catalog
2569  * entry any longer. Delete it rather than updating it, to avoid
2570  * leaving a degenerate entry.
2571  */
2572  if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
2573  {
2574  CatalogTupleDelete(relation, &tuple->t_self);
2575  }
2576  else
2577  {
2578  /* finished building new ACL value, now insert it */
2579  HeapTuple newtuple;
2580  Datum values[Natts_pg_parameter_acl] = {0};
2581  bool nulls[Natts_pg_parameter_acl] = {0};
2582  bool replaces[Natts_pg_parameter_acl] = {0};
2583 
2584  replaces[Anum_pg_parameter_acl_paracl - 1] = true;
2585  values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
2586 
2587  newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2588  values, nulls, replaces);
2589 
2590  CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2591  }
2592 
2593  /* Update initial privileges for extensions */
2594  recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
2595  new_acl);
2596 
2597  /* Update the shared dependency ACL info */
2598  updateAclDependencies(ParameterAclRelationId, parameterId, 0,
2599  ownerId,
2600  noldmembers, oldmembers,
2601  nnewmembers, newmembers);
2602 
2603  ReleaseSysCache(tuple);
2604  pfree(new_acl);
2605 
2606  /* prevent error when processing duplicate objects */
2608  }
2609 
2610  table_close(relation, RowExclusiveLock);
2611 }
2612 
2613 
2614 static AclMode
2615 string_to_privilege(const char *privname)
2616 {
2617  if (strcmp(privname, "insert") == 0)
2618  return ACL_INSERT;
2619  if (strcmp(privname, "select") == 0)
2620  return ACL_SELECT;
2621  if (strcmp(privname, "update") == 0)
2622  return ACL_UPDATE;
2623  if (strcmp(privname, "delete") == 0)
2624  return ACL_DELETE;
2625  if (strcmp(privname, "truncate") == 0)
2626  return ACL_TRUNCATE;
2627  if (strcmp(privname, "references") == 0)
2628  return ACL_REFERENCES;
2629  if (strcmp(privname, "trigger") == 0)
2630  return ACL_TRIGGER;
2631  if (strcmp(privname, "execute") == 0)
2632  return ACL_EXECUTE;
2633  if (strcmp(privname, "usage") == 0)
2634  return ACL_USAGE;
2635  if (strcmp(privname, "create") == 0)
2636  return ACL_CREATE;
2637  if (strcmp(privname, "temporary") == 0)
2638  return ACL_CREATE_TEMP;
2639  if (strcmp(privname, "temp") == 0)
2640  return ACL_CREATE_TEMP;
2641  if (strcmp(privname, "connect") == 0)
2642  return ACL_CONNECT;
2643  if (strcmp(privname, "set") == 0)
2644  return ACL_SET;
2645  if (strcmp(privname, "alter system") == 0)
2646  return ACL_ALTER_SYSTEM;
2647  if (strcmp(privname, "maintain") == 0)
2648  return ACL_MAINTAIN;
2649  ereport(ERROR,
2650  (errcode(ERRCODE_SYNTAX_ERROR),
2651  errmsg("unrecognized privilege type \"%s\"", privname)));
2652  return 0; /* appease compiler */
2653 }
2654 
2655 static const char *
2657 {
2658  switch (privilege)
2659  {
2660  case ACL_INSERT:
2661  return "INSERT";
2662  case ACL_SELECT:
2663  return "SELECT";
2664  case ACL_UPDATE:
2665  return "UPDATE";
2666  case ACL_DELETE:
2667  return "DELETE";
2668  case ACL_TRUNCATE:
2669  return "TRUNCATE";
2670  case ACL_REFERENCES:
2671  return "REFERENCES";
2672  case ACL_TRIGGER:
2673  return "TRIGGER";
2674  case ACL_EXECUTE:
2675  return "EXECUTE";
2676  case ACL_USAGE:
2677  return "USAGE";
2678  case ACL_CREATE:
2679  return "CREATE";
2680  case ACL_CREATE_TEMP:
2681  return "TEMP";
2682  case ACL_CONNECT:
2683  return "CONNECT";
2684  case ACL_SET:
2685  return "SET";
2686  case ACL_ALTER_SYSTEM:
2687  return "ALTER SYSTEM";
2688  case ACL_MAINTAIN:
2689  return "MAINTAIN";
2690  default:
2691  elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2692  }
2693  return NULL; /* appease compiler */
2694 }
2695 
2696 /*
2697  * Standardized reporting of aclcheck permissions failures.
2698  *
2699  * Note: we do not double-quote the %s's below, because many callers
2700  * supply strings that might be already quoted.
2701  */
2702 void
2704  const char *objectname)
2705 {
2706  switch (aclerr)
2707  {
2708  case ACLCHECK_OK:
2709  /* no error, so return to caller */
2710  break;
2711  case ACLCHECK_NO_PRIV:
2712  {
2713  const char *msg = "???";
2714 
2715  switch (objtype)
2716  {
2717  case OBJECT_AGGREGATE:
2718  msg = gettext_noop("permission denied for aggregate %s");
2719  break;
2720  case OBJECT_COLLATION:
2721  msg = gettext_noop("permission denied for collation %s");
2722  break;
2723  case OBJECT_COLUMN:
2724  msg = gettext_noop("permission denied for column %s");
2725  break;
2726  case OBJECT_CONVERSION:
2727  msg = gettext_noop("permission denied for conversion %s");
2728  break;
2729  case OBJECT_DATABASE:
2730  msg = gettext_noop("permission denied for database %s");
2731  break;
2732  case OBJECT_DOMAIN:
2733  msg = gettext_noop("permission denied for domain %s");
2734  break;
2735  case OBJECT_EVENT_TRIGGER:
2736  msg = gettext_noop("permission denied for event trigger %s");
2737  break;
2738  case OBJECT_EXTENSION:
2739  msg = gettext_noop("permission denied for extension %s");
2740  break;
2741  case OBJECT_FDW:
2742  msg = gettext_noop("permission denied for foreign-data wrapper %s");
2743  break;
2744  case OBJECT_FOREIGN_SERVER:
2745  msg = gettext_noop("permission denied for foreign server %s");
2746  break;
2747  case OBJECT_FOREIGN_TABLE:
2748  msg = gettext_noop("permission denied for foreign table %s");
2749  break;
2750  case OBJECT_FUNCTION:
2751  msg = gettext_noop("permission denied for function %s");
2752  break;
2753  case OBJECT_INDEX:
2754  msg = gettext_noop("permission denied for index %s");
2755  break;
2756  case OBJECT_LANGUAGE:
2757  msg = gettext_noop("permission denied for language %s");
2758  break;
2759  case OBJECT_LARGEOBJECT:
2760  msg = gettext_noop("permission denied for large object %s");
2761  break;
2762  case OBJECT_MATVIEW:
2763  msg = gettext_noop("permission denied for materialized view %s");
2764  break;
2765  case OBJECT_OPCLASS:
2766  msg = gettext_noop("permission denied for operator class %s");
2767  break;
2768  case OBJECT_OPERATOR:
2769  msg = gettext_noop("permission denied for operator %s");
2770  break;
2771  case OBJECT_OPFAMILY:
2772  msg = gettext_noop("permission denied for operator family %s");
2773  break;
2774  case OBJECT_PARAMETER_ACL:
2775  msg = gettext_noop("permission denied for parameter %s");
2776  break;
2777  case OBJECT_POLICY:
2778  msg = gettext_noop("permission denied for policy %s");
2779  break;
2780  case OBJECT_PROCEDURE:
2781  msg = gettext_noop("permission denied for procedure %s");
2782  break;
2783  case OBJECT_PUBLICATION:
2784  msg = gettext_noop("permission denied for publication %s");
2785  break;
2786  case OBJECT_ROUTINE:
2787  msg = gettext_noop("permission denied for routine %s");
2788  break;
2789  case OBJECT_SCHEMA:
2790  msg = gettext_noop("permission denied for schema %s");
2791  break;
2792  case OBJECT_SEQUENCE:
2793  msg = gettext_noop("permission denied for sequence %s");
2794  break;
2795  case OBJECT_STATISTIC_EXT:
2796  msg = gettext_noop("permission denied for statistics object %s");
2797  break;
2798  case OBJECT_SUBSCRIPTION:
2799  msg = gettext_noop("permission denied for subscription %s");
2800  break;
2801  case OBJECT_TABLE:
2802  msg = gettext_noop("permission denied for table %s");
2803  break;
2804  case OBJECT_TABLESPACE:
2805  msg = gettext_noop("permission denied for tablespace %s");
2806  break;
2808  msg = gettext_noop("permission denied for text search configuration %s");
2809  break;
2810  case OBJECT_TSDICTIONARY:
2811  msg = gettext_noop("permission denied for text search dictionary %s");
2812  break;
2813  case OBJECT_TYPE:
2814  msg = gettext_noop("permission denied for type %s");
2815  break;
2816  case OBJECT_VIEW:
2817  msg = gettext_noop("permission denied for view %s");
2818  break;
2819  /* these currently aren't used */
2820  case OBJECT_ACCESS_METHOD:
2821  case OBJECT_AMOP:
2822  case OBJECT_AMPROC:
2823  case OBJECT_ATTRIBUTE:
2824  case OBJECT_CAST:
2825  case OBJECT_DEFAULT:
2826  case OBJECT_DEFACL:
2827  case OBJECT_DOMCONSTRAINT:
2830  case OBJECT_ROLE:
2831  case OBJECT_RULE:
2832  case OBJECT_TABCONSTRAINT:
2833  case OBJECT_TRANSFORM:
2834  case OBJECT_TRIGGER:
2835  case OBJECT_TSPARSER:
2836  case OBJECT_TSTEMPLATE:
2837  case OBJECT_USER_MAPPING:
2838  elog(ERROR, "unsupported object type: %d", objtype);
2839  }
2840 
2841  ereport(ERROR,
2842  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2843  errmsg(msg, objectname)));
2844  break;
2845  }
2846  case ACLCHECK_NOT_OWNER:
2847  {
2848  const char *msg = "???";
2849 
2850  switch (objtype)
2851  {
2852  case OBJECT_AGGREGATE:
2853  msg = gettext_noop("must be owner of aggregate %s");
2854  break;
2855  case OBJECT_COLLATION:
2856  msg = gettext_noop("must be owner of collation %s");
2857  break;
2858  case OBJECT_CONVERSION:
2859  msg = gettext_noop("must be owner of conversion %s");
2860  break;
2861  case OBJECT_DATABASE:
2862  msg = gettext_noop("must be owner of database %s");
2863  break;
2864  case OBJECT_DOMAIN:
2865  msg = gettext_noop("must be owner of domain %s");
2866  break;
2867  case OBJECT_EVENT_TRIGGER:
2868  msg = gettext_noop("must be owner of event trigger %s");
2869  break;
2870  case OBJECT_EXTENSION:
2871  msg = gettext_noop("must be owner of extension %s");
2872  break;
2873  case OBJECT_FDW:
2874  msg = gettext_noop("must be owner of foreign-data wrapper %s");
2875  break;
2876  case OBJECT_FOREIGN_SERVER:
2877  msg = gettext_noop("must be owner of foreign server %s");
2878  break;
2879  case OBJECT_FOREIGN_TABLE:
2880  msg = gettext_noop("must be owner of foreign table %s");
2881  break;
2882  case OBJECT_FUNCTION:
2883  msg = gettext_noop("must be owner of function %s");
2884  break;
2885  case OBJECT_INDEX:
2886  msg = gettext_noop("must be owner of index %s");
2887  break;
2888  case OBJECT_LANGUAGE:
2889  msg = gettext_noop("must be owner of language %s");
2890  break;
2891  case OBJECT_LARGEOBJECT:
2892  msg = gettext_noop("must be owner of large object %s");
2893  break;
2894  case OBJECT_MATVIEW:
2895  msg = gettext_noop("must be owner of materialized view %s");
2896  break;
2897  case OBJECT_OPCLASS:
2898  msg = gettext_noop("must be owner of operator class %s");
2899  break;
2900  case OBJECT_OPERATOR:
2901  msg = gettext_noop("must be owner of operator %s");
2902  break;
2903  case OBJECT_OPFAMILY:
2904  msg = gettext_noop("must be owner of operator family %s");
2905  break;
2906  case OBJECT_PROCEDURE:
2907  msg = gettext_noop("must be owner of procedure %s");
2908  break;
2909  case OBJECT_PUBLICATION:
2910  msg = gettext_noop("must be owner of publication %s");
2911  break;
2912  case OBJECT_ROUTINE:
2913  msg = gettext_noop("must be owner of routine %s");
2914  break;
2915  case OBJECT_SEQUENCE:
2916  msg = gettext_noop("must be owner of sequence %s");
2917  break;
2918  case OBJECT_SUBSCRIPTION:
2919  msg = gettext_noop("must be owner of subscription %s");
2920  break;
2921  case OBJECT_TABLE:
2922  msg = gettext_noop("must be owner of table %s");
2923  break;
2924  case OBJECT_TYPE:
2925  msg = gettext_noop("must be owner of type %s");
2926  break;
2927  case OBJECT_VIEW:
2928  msg = gettext_noop("must be owner of view %s");
2929  break;
2930  case OBJECT_SCHEMA:
2931  msg = gettext_noop("must be owner of schema %s");
2932  break;
2933  case OBJECT_STATISTIC_EXT:
2934  msg = gettext_noop("must be owner of statistics object %s");
2935  break;
2936  case OBJECT_TABLESPACE:
2937  msg = gettext_noop("must be owner of tablespace %s");
2938  break;
2940  msg = gettext_noop("must be owner of text search configuration %s");
2941  break;
2942  case OBJECT_TSDICTIONARY:
2943  msg = gettext_noop("must be owner of text search dictionary %s");
2944  break;
2945 
2946  /*
2947  * Special cases: For these, the error message talks
2948  * about "relation", because that's where the
2949  * ownership is attached. See also
2950  * check_object_ownership().
2951  */
2952  case OBJECT_COLUMN:
2953  case OBJECT_POLICY:
2954  case OBJECT_RULE:
2955  case OBJECT_TABCONSTRAINT:
2956  case OBJECT_TRIGGER:
2957  msg = gettext_noop("must be owner of relation %s");
2958  break;
2959  /* these currently aren't used */
2960  case OBJECT_ACCESS_METHOD:
2961  case OBJECT_AMOP:
2962  case OBJECT_AMPROC:
2963  case OBJECT_ATTRIBUTE:
2964  case OBJECT_CAST:
2965  case OBJECT_DEFAULT:
2966  case OBJECT_DEFACL:
2967  case OBJECT_DOMCONSTRAINT:
2968  case OBJECT_PARAMETER_ACL:
2971  case OBJECT_ROLE:
2972  case OBJECT_TRANSFORM:
2973  case OBJECT_TSPARSER:
2974  case OBJECT_TSTEMPLATE:
2975  case OBJECT_USER_MAPPING:
2976  elog(ERROR, "unsupported object type: %d", objtype);
2977  }
2978 
2979  ereport(ERROR,
2980  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2981  errmsg(msg, objectname)));
2982  break;
2983  }
2984  default:
2985  elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2986  break;
2987  }
2988 }
2989 
2990 
2991 void
2993  const char *objectname, const char *colname)
2994 {
2995  switch (aclerr)
2996  {
2997  case ACLCHECK_OK:
2998  /* no error, so return to caller */
2999  break;
3000  case ACLCHECK_NO_PRIV:
3001  ereport(ERROR,
3002  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3003  errmsg("permission denied for column \"%s\" of relation \"%s\"",
3004  colname, objectname)));
3005  break;
3006  case ACLCHECK_NOT_OWNER:
3007  /* relation msg is OK since columns don't have separate owners */
3008  aclcheck_error(aclerr, objtype, objectname);
3009  break;
3010  default:
3011  elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3012  break;
3013  }
3014 }
3015 
3016 
3017 /*
3018  * Special common handling for types: use element type instead of array type,
3019  * and format nicely
3020  */
3021 void
3023 {
3024  Oid element_type = get_element_type(typeOid);
3025 
3026  aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
3027 }
3028 
3029 
3030 /*
3031  * Relay for the various pg_*_mask routines depending on object kind
3032  */
3033 static AclMode
3034 pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
3035  AclMode mask, AclMaskHow how)
3036 {
3037  switch (objtype)
3038  {
3039  case OBJECT_COLUMN:
3040  return
3041  pg_class_aclmask(object_oid, roleid, mask, how) |
3042  pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
3043  case OBJECT_TABLE:
3044  case OBJECT_SEQUENCE:
3045  return pg_class_aclmask(object_oid, roleid, mask, how);
3046  case OBJECT_DATABASE:
3047  return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
3048  case OBJECT_FUNCTION:
3049  return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
3050  case OBJECT_LANGUAGE:
3051  return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
3052  case OBJECT_LARGEOBJECT:
3053  return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3054  mask, how, NULL);
3055  case OBJECT_PARAMETER_ACL:
3056  return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
3057  case OBJECT_SCHEMA:
3058  return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
3059  case OBJECT_STATISTIC_EXT:
3060  elog(ERROR, "grantable rights not supported for statistics objects");
3061  /* not reached, but keep compiler quiet */
3062  return ACL_NO_RIGHTS;
3063  case OBJECT_TABLESPACE:
3064  return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3065  case OBJECT_FDW:
3066  return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3067  case OBJECT_FOREIGN_SERVER:
3068  return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3069  case OBJECT_EVENT_TRIGGER:
3070  elog(ERROR, "grantable rights not supported for event triggers");
3071  /* not reached, but keep compiler quiet */
3072  return ACL_NO_RIGHTS;
3073  case OBJECT_TYPE:
3074  return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3075  default:
3076  elog(ERROR, "unrecognized object type: %d",
3077  (int) objtype);
3078  /* not reached, but keep compiler quiet */
3079  return ACL_NO_RIGHTS;
3080  }
3081 }
3082 
3083 
3084 /* ****************************************************************
3085  * Exported routines for examining a user's privileges for various objects
3086  *
3087  * See aclmask() for a description of the common API for these functions.
3088  *
3089  * Note: we give lookup failure the full ereport treatment because the
3090  * has_xxx_privilege() family of functions allow users to pass any random
3091  * OID to these functions.
3092  * ****************************************************************
3093  */
3094 
3095 /*
3096  * Generic routine for examining a user's privileges for an object
3097  */
3098 static AclMode
3099 object_aclmask(Oid classid, Oid objectid, Oid roleid,
3100  AclMode mask, AclMaskHow how)
3101 {
3102  return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3103 }
3104 
3105 /*
3106  * Generic routine for examining a user's privileges for an object,
3107  * with is_missing
3108  */
3109 static AclMode
3110 object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
3111  AclMode mask, AclMaskHow how,
3112  bool *is_missing)
3113 {
3114  int cacheid;
3115  AclMode result;
3116  HeapTuple tuple;
3117  Datum aclDatum;
3118  bool isNull;
3119  Acl *acl;
3120  Oid ownerId;
3121 
3122  /* Special cases */
3123  switch (classid)
3124  {
3125  case NamespaceRelationId:
3126  return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
3127  is_missing);
3128  case TypeRelationId:
3129  return pg_type_aclmask_ext(objectid, roleid, mask, how,
3130  is_missing);
3131  }
3132 
3133  /* Even more special cases */
3134  Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3135  Assert(classid != LargeObjectMetadataRelationId); /* should use
3136  * pg_largeobject_acl* */
3137 
3138  /* Superusers bypass all permission checking. */
3139  if (superuser_arg(roleid))
3140  return mask;
3141 
3142  /*
3143  * Get the object's ACL from its catalog
3144  */
3145 
3146  cacheid = get_object_catcache_oid(classid);
3147 
3148  tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3149  if (!HeapTupleIsValid(tuple))
3150  {
3151  if (is_missing != NULL)
3152  {
3153  /* return "no privileges" instead of throwing an error */
3154  *is_missing = true;
3155  return 0;
3156  }
3157  else
3158  ereport(ERROR,
3159  (errcode(ERRCODE_UNDEFINED_OBJECT),
3160  errmsg("%s with OID %u does not exist",
3161  get_object_class_descr(classid), objectid)));
3162  }
3163 
3164  ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3165  tuple,
3166  get_object_attnum_owner(classid)));
3167 
3168  aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3169  &isNull);
3170  if (isNull)
3171  {
3172  /* No ACL, so build default ACL */
3173  acl = acldefault(get_object_type(classid, objectid), ownerId);
3174  aclDatum = (Datum) 0;
3175  }
3176  else
3177  {
3178  /* detoast ACL if necessary */
3179  acl = DatumGetAclP(aclDatum);
3180  }
3181 
3182  result = aclmask(acl, roleid, ownerId, mask, how);
3183 
3184  /* if we have a detoasted copy, free it */
3185  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3186  pfree(acl);
3187 
3188  ReleaseSysCache(tuple);
3189 
3190  return result;
3191 }
3192 
3193 /*
3194  * Routine for examining a user's privileges for a column
3195  *
3196  * Note: this considers only privileges granted specifically on the column.
3197  * It is caller's responsibility to take relation-level privileges into account
3198  * as appropriate. (For the same reason, we have no special case for
3199  * superuser-ness here.)
3200  */
3201 static AclMode
3203  AclMode mask, AclMaskHow how)
3204 {
3205  return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3206  mask, how, NULL);
3207 }
3208 
3209 /*
3210  * Routine for examining a user's privileges for a column, with is_missing
3211  */
3212 static AclMode
3214  AclMode mask, AclMaskHow how, bool *is_missing)
3215 {
3216  AclMode result;
3217  HeapTuple classTuple;
3218  HeapTuple attTuple;
3219  Form_pg_class classForm;
3220  Form_pg_attribute attributeForm;
3221  Datum aclDatum;
3222  bool isNull;
3223  Acl *acl;
3224  Oid ownerId;
3225 
3226  /*
3227  * First, get the column's ACL from its pg_attribute entry
3228  */
3229  attTuple = SearchSysCache2(ATTNUM,
3230  ObjectIdGetDatum(table_oid),
3232  if (!HeapTupleIsValid(attTuple))
3233  {
3234  if (is_missing != NULL)
3235  {
3236  /* return "no privileges" instead of throwing an error */
3237  *is_missing = true;
3238  return 0;
3239  }
3240  else
3241  ereport(ERROR,
3242  (errcode(ERRCODE_UNDEFINED_COLUMN),
3243  errmsg("attribute %d of relation with OID %u does not exist",
3244  attnum, table_oid)));
3245  }
3246 
3247  attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3248 
3249  /* Check dropped columns, too */
3250  if (attributeForm->attisdropped)
3251  {
3252  if (is_missing != NULL)
3253  {
3254  /* return "no privileges" instead of throwing an error */
3255  *is_missing = true;
3256  ReleaseSysCache(attTuple);
3257  return 0;
3258  }
3259  else
3260  ereport(ERROR,
3261  (errcode(ERRCODE_UNDEFINED_COLUMN),
3262  errmsg("attribute %d of relation with OID %u does not exist",
3263  attnum, table_oid)));
3264  }
3265 
3266  aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3267  &isNull);
3268 
3269  /*
3270  * Here we hard-wire knowledge that the default ACL for a column grants no
3271  * privileges, so that we can fall out quickly in the very common case
3272  * where attacl is null.
3273  */
3274  if (isNull)
3275  {
3276  ReleaseSysCache(attTuple);
3277  return 0;
3278  }
3279 
3280  /*
3281  * Must get the relation's ownerId from pg_class. Since we already found
3282  * a pg_attribute entry, the only likely reason for this to fail is that a
3283  * concurrent DROP of the relation committed since then (which could only
3284  * happen if we don't have lock on the relation). Treat that similarly to
3285  * not finding the attribute entry.
3286  */
3287  classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3288  if (!HeapTupleIsValid(classTuple))
3289  {
3290  ReleaseSysCache(attTuple);
3291  if (is_missing != NULL)
3292  {
3293  /* return "no privileges" instead of throwing an error */
3294  *is_missing = true;
3295  return 0;
3296  }
3297  else
3298  ereport(ERROR,
3300  errmsg("relation with OID %u does not exist",
3301  table_oid)));
3302  }
3303  classForm = (Form_pg_class) GETSTRUCT(classTuple);
3304 
3305  ownerId = classForm->relowner;
3306 
3307  ReleaseSysCache(classTuple);
3308 
3309  /* detoast column's ACL if necessary */
3310  acl = DatumGetAclP(aclDatum);
3311 
3312  result = aclmask(acl, roleid, ownerId, mask, how);
3313 
3314  /* if we have a detoasted copy, free it */
3315  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3316  pfree(acl);
3317 
3318  ReleaseSysCache(attTuple);
3319 
3320  return result;
3321 }
3322 
3323 /*
3324  * Exported routine for examining a user's privileges for a table
3325  */
3326 AclMode
3327 pg_class_aclmask(Oid table_oid, Oid roleid,
3328  AclMode mask, AclMaskHow how)
3329 {
3330  return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3331 }
3332 
3333 /*
3334  * Routine for examining a user's privileges for a table, with is_missing
3335  */
3336 static AclMode
3337 pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
3338  AclMaskHow how, bool *is_missing)
3339 {
3340  AclMode result;
3341  HeapTuple tuple;
3342  Form_pg_class classForm;
3343  Datum aclDatum;
3344  bool isNull;
3345  Acl *acl;
3346  Oid ownerId;
3347 
3348  /*
3349  * Must get the relation's tuple from pg_class
3350  */
3351  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3352  if (!HeapTupleIsValid(tuple))
3353  {
3354  if (is_missing != NULL)
3355  {
3356  /* return "no privileges" instead of throwing an error */
3357  *is_missing = true;
3358  return 0;
3359  }
3360  else
3361  ereport(ERROR,
3363  errmsg("relation with OID %u does not exist",
3364  table_oid)));
3365  }
3366 
3367  classForm = (Form_pg_class) GETSTRUCT(tuple);
3368 
3369  /*
3370  * Deny anyone permission to update a system catalog unless
3371  * pg_authid.rolsuper is set.
3372  *
3373  * As of 7.4 we have some updatable system views; those shouldn't be
3374  * protected in this way. Assume the view rules can take care of
3375  * themselves. ACL_USAGE is if we ever have system sequences.
3376  */
3377  if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3378  IsSystemClass(table_oid, classForm) &&
3379  classForm->relkind != RELKIND_VIEW &&
3380  !superuser_arg(roleid))
3382 
3383  /*
3384  * Otherwise, superusers bypass all permission-checking.
3385  */
3386  if (superuser_arg(roleid))
3387  {
3388  ReleaseSysCache(tuple);
3389  return mask;
3390  }
3391 
3392  /*
3393  * Normal case: get the relation's ACL from pg_class
3394  */
3395  ownerId = classForm->relowner;
3396 
3397  aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3398  &isNull);
3399  if (isNull)
3400  {
3401  /* No ACL, so build default ACL */
3402  switch (classForm->relkind)
3403  {
3404  case RELKIND_SEQUENCE:
3405  acl = acldefault(OBJECT_SEQUENCE, ownerId);
3406  break;
3407  default:
3408  acl = acldefault(OBJECT_TABLE, ownerId);
3409  break;
3410  }
3411  aclDatum = (Datum) 0;
3412  }
3413  else
3414  {
3415  /* detoast rel's ACL if necessary */
3416  acl = DatumGetAclP(aclDatum);
3417  }
3418 
3419  result = aclmask(acl, roleid, ownerId, mask, how);
3420 
3421  /* if we have a detoasted copy, free it */
3422  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3423  pfree(acl);
3424 
3425  ReleaseSysCache(tuple);
3426 
3427  /*
3428  * Check if ACL_SELECT is being checked and, if so, and not set already as
3429  * part of the result, then check if the user is a member of the
3430  * pg_read_all_data role, which allows read access to all relations.
3431  */
3432  if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
3433  has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
3434  result |= ACL_SELECT;
3435 
3436  /*
3437  * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3438  * so, and not set already as part of the result, then check if the user
3439  * is a member of the pg_write_all_data role, which allows
3440  * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3441  * which requires superuser, see above).
3442  */
3443  if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
3444  !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
3445  has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
3446  result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
3447 
3448  /*
3449  * Check if ACL_MAINTAIN is being checked and, if so, and not already set
3450  * as part of the result, then check if the user is a member of the
3451  * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
3452  * MATERIALIZED VIEW, REINDEX, and LOCK TABLE on all relations.
3453  */
3454  if (mask & ACL_MAINTAIN &&
3455  !(result & ACL_MAINTAIN) &&
3456  has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
3457  result |= ACL_MAINTAIN;
3458 
3459  return result;
3460 }
3461 
3462 /*
3463  * Routine for examining a user's privileges for a configuration
3464  * parameter (GUC), identified by GUC name.
3465  */
3466 static AclMode
3467 pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
3468 {
3469  AclMode result;
3470  char *parname;
3471  text *partext;
3472  HeapTuple tuple;
3473 
3474  /* Superusers bypass all permission checking. */
3475  if (superuser_arg(roleid))
3476  return mask;
3477 
3478  /* Convert name to the form it should have in pg_parameter_acl... */
3480  partext = cstring_to_text(parname);
3481 
3482  /* ... and look it up */
3483  tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3484 
3485  if (!HeapTupleIsValid(tuple))
3486  {
3487  /* If no entry, GUC has no permissions for non-superusers */
3488  result = ACL_NO_RIGHTS;
3489  }
3490  else
3491  {
3492  Datum aclDatum;
3493  bool isNull;
3494  Acl *acl;
3495 
3496  aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3497  Anum_pg_parameter_acl_paracl,
3498  &isNull);
3499  if (isNull)
3500  {
3501  /* No ACL, so build default ACL */
3502  acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3503  aclDatum = (Datum) 0;
3504  }
3505  else
3506  {
3507  /* detoast ACL if necessary */
3508  acl = DatumGetAclP(aclDatum);
3509  }
3510 
3511  result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3512 
3513  /* if we have a detoasted copy, free it */
3514  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3515  pfree(acl);
3516 
3517  ReleaseSysCache(tuple);
3518  }
3519 
3520  pfree(parname);
3521  pfree(partext);
3522 
3523  return result;
3524 }
3525 
3526 /*
3527  * Routine for examining a user's privileges for a configuration
3528  * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
3529  */
3530 static AclMode
3532 {
3533  AclMode result;
3534  HeapTuple tuple;
3535  Datum aclDatum;
3536  bool isNull;
3537  Acl *acl;
3538 
3539  /* Superusers bypass all permission checking. */
3540  if (superuser_arg(roleid))
3541  return mask;
3542 
3543  /* Get the ACL from pg_parameter_acl */
3544  tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3545  if (!HeapTupleIsValid(tuple))
3546  ereport(ERROR,
3547  (errcode(ERRCODE_UNDEFINED_OBJECT),
3548  errmsg("parameter ACL with OID %u does not exist",
3549  acl_oid)));
3550 
3551  aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3552  Anum_pg_parameter_acl_paracl,
3553  &isNull);
3554  if (isNull)
3555  {
3556  /* No ACL, so build default ACL */
3557  acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3558  aclDatum = (Datum) 0;
3559  }
3560  else
3561  {
3562  /* detoast ACL if necessary */
3563  acl = DatumGetAclP(aclDatum);
3564  }
3565 
3566  result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3567 
3568  /* if we have a detoasted copy, free it */
3569  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3570  pfree(acl);
3571 
3572  ReleaseSysCache(tuple);
3573 
3574  return result;
3575 }
3576 
3577 /*
3578  * Routine for examining a user's privileges for a largeobject
3579  *
3580  * When a large object is opened for reading, it is opened relative to the
3581  * caller's snapshot, but when it is opened for writing, a current
3582  * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
3583  * takes a snapshot argument so that the permissions check can be made
3584  * relative to the same snapshot that will be used to read the underlying
3585  * data. The caller will actually pass NULL for an instantaneous MVCC
3586  * snapshot, since all we do with the snapshot argument is pass it through
3587  * to systable_beginscan().
3588  */
3589 static AclMode
3591  AclMode mask, AclMaskHow how,
3592  Snapshot snapshot)
3593 {
3594  AclMode result;
3595  Relation pg_lo_meta;
3596  ScanKeyData entry[1];
3597  SysScanDesc scan;
3598  HeapTuple tuple;
3599  Datum aclDatum;
3600  bool isNull;
3601  Acl *acl;
3602  Oid ownerId;
3603 
3604  /* Superusers bypass all permission checking. */
3605  if (superuser_arg(roleid))
3606  return mask;
3607 
3608  /*
3609  * Get the largeobject's ACL from pg_largeobject_metadata
3610  */
3611  pg_lo_meta = table_open(LargeObjectMetadataRelationId,
3612  AccessShareLock);
3613 
3614  ScanKeyInit(&entry[0],
3615  Anum_pg_largeobject_metadata_oid,
3616  BTEqualStrategyNumber, F_OIDEQ,
3617  ObjectIdGetDatum(lobj_oid));
3618 
3619  scan = systable_beginscan(pg_lo_meta,
3620  LargeObjectMetadataOidIndexId, true,
3621  snapshot, 1, entry);
3622 
3623  tuple = systable_getnext(scan);
3624  if (!HeapTupleIsValid(tuple))
3625  ereport(ERROR,
3626  (errcode(ERRCODE_UNDEFINED_OBJECT),
3627  errmsg("large object %u does not exist", lobj_oid)));
3628 
3629  ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
3630 
3631  aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
3632  RelationGetDescr(pg_lo_meta), &isNull);
3633 
3634  if (isNull)
3635  {
3636  /* No ACL, so build default ACL */
3637  acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
3638  aclDatum = (Datum) 0;
3639  }
3640  else
3641  {
3642  /* detoast ACL if necessary */
3643  acl = DatumGetAclP(aclDatum);
3644  }
3645 
3646  result = aclmask(acl, roleid, ownerId, mask, how);
3647 
3648  /* if we have a detoasted copy, free it */
3649  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3650  pfree(acl);
3651 
3652  systable_endscan(scan);
3653 
3654  table_close(pg_lo_meta, AccessShareLock);
3655 
3656  return result;
3657 }
3658 
3659 /*
3660  * Routine for examining a user's privileges for a namespace, with is_missing
3661  */
3662 static AclMode
3664  AclMode mask, AclMaskHow how,
3665  bool *is_missing)
3666 {
3667  AclMode result;
3668  HeapTuple tuple;
3669  Datum aclDatum;
3670  bool isNull;
3671  Acl *acl;
3672  Oid ownerId;
3673 
3674  /* Superusers bypass all permission checking. */
3675  if (superuser_arg(roleid))
3676  return mask;
3677 
3678  /*
3679  * If we have been assigned this namespace as a temp namespace, check to
3680  * make sure we have CREATE TEMP permission on the database, and if so act
3681  * as though we have all standard (but not GRANT OPTION) permissions on
3682  * the namespace. If we don't have CREATE TEMP, act as though we have
3683  * only USAGE (and not CREATE) rights.
3684  *
3685  * This may seem redundant given the check in InitTempTableNamespace, but
3686  * it really isn't since current user ID may have changed since then. The
3687  * upshot of this behavior is that a SECURITY DEFINER function can create
3688  * temp tables that can then be accessed (if permission is granted) by
3689  * code in the same session that doesn't have permissions to create temp
3690  * tables.
3691  *
3692  * XXX Would it be safe to ereport a special error message as
3693  * InitTempTableNamespace does? Returning zero here means we'll get a
3694  * generic "permission denied for schema pg_temp_N" message, which is not
3695  * remarkably user-friendly.
3696  */
3697  if (isTempNamespace(nsp_oid))
3698  {
3699  if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
3700  ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
3701  return mask & ACL_ALL_RIGHTS_SCHEMA;
3702  else
3703  return mask & ACL_USAGE;
3704  }
3705 
3706  /*
3707  * Get the schema's ACL from pg_namespace
3708  */
3709  tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
3710  if (!HeapTupleIsValid(tuple))
3711  {
3712  if (is_missing != NULL)
3713  {
3714  /* return "no privileges" instead of throwing an error */
3715  *is_missing = true;
3716  return 0;
3717  }
3718  else
3719  ereport(ERROR,
3720  (errcode(ERRCODE_UNDEFINED_SCHEMA),
3721  errmsg("schema with OID %u does not exist", nsp_oid)));
3722  }
3723 
3724  ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3725 
3726  aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
3727  &isNull);
3728  if (isNull)
3729  {
3730  /* No ACL, so build default ACL */
3731  acl = acldefault(OBJECT_SCHEMA, ownerId);
3732  aclDatum = (Datum) 0;
3733  }
3734  else
3735  {
3736  /* detoast ACL if necessary */
3737  acl = DatumGetAclP(aclDatum);
3738  }
3739 
3740  result = aclmask(acl, roleid, ownerId, mask, how);
3741 
3742  /* if we have a detoasted copy, free it */
3743  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3744  pfree(acl);
3745 
3746  ReleaseSysCache(tuple);
3747 
3748  /*
3749  * Check if ACL_USAGE is being checked and, if so, and not set already as
3750  * part of the result, then check if the user is a member of the
3751  * pg_read_all_data or pg_write_all_data roles, which allow usage access
3752  * to all schemas.
3753  */
3754  if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
3755  (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
3756  has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
3757  result |= ACL_USAGE;
3758  return result;
3759 }
3760 
3761 /*
3762  * Routine for examining a user's privileges for a type, with is_missing
3763  */
3764 static AclMode
3765 pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
3766  bool *is_missing)
3767 {
3768  AclMode result;
3769  HeapTuple tuple;
3770  Form_pg_type typeForm;
3771  Datum aclDatum;
3772  bool isNull;
3773  Acl *acl;
3774  Oid ownerId;
3775 
3776  /* Bypass permission checks for superusers */
3777  if (superuser_arg(roleid))
3778  return mask;
3779 
3780  /*
3781  * Must get the type's tuple from pg_type
3782  */
3783  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3784  if (!HeapTupleIsValid(tuple))
3785  {
3786  if (is_missing != NULL)
3787  {
3788  /* return "no privileges" instead of throwing an error */
3789  *is_missing = true;
3790  return 0;
3791  }
3792  else
3793  ereport(ERROR,
3794  (errcode(ERRCODE_UNDEFINED_OBJECT),
3795  errmsg("type with OID %u does not exist",
3796  type_oid)));
3797  }
3798  typeForm = (Form_pg_type) GETSTRUCT(tuple);
3799 
3800  /*
3801  * "True" array types don't manage permissions of their own; consult the
3802  * element type instead.
3803  */
3804  if (IsTrueArrayType(typeForm))
3805  {
3806  Oid elttype_oid = typeForm->typelem;
3807 
3808  ReleaseSysCache(tuple);
3809 
3810  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3811  if (!HeapTupleIsValid(tuple))
3812  {
3813  if (is_missing != NULL)
3814  {
3815  /* return "no privileges" instead of throwing an error */
3816  *is_missing = true;
3817  return 0;
3818  }
3819  else
3820  ereport(ERROR,
3821  (errcode(ERRCODE_UNDEFINED_OBJECT),
3822  errmsg("type with OID %u does not exist",
3823  elttype_oid)));
3824  }
3825  typeForm = (Form_pg_type) GETSTRUCT(tuple);
3826  }
3827 
3828  /*
3829  * Likewise, multirange types don't manage their own permissions; consult
3830  * the associated range type. (Note we must do this after the array step
3831  * to get the right answer for arrays of multiranges.)
3832  */
3833  if (typeForm->typtype == TYPTYPE_MULTIRANGE)
3834  {
3835  Oid rangetype = get_multirange_range(typeForm->oid);
3836 
3837  ReleaseSysCache(tuple);
3838 
3839  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
3840  if (!HeapTupleIsValid(tuple))
3841  {
3842  if (is_missing != NULL)
3843  {
3844  /* return "no privileges" instead of throwing an error */
3845  *is_missing = true;
3846  return 0;
3847  }
3848  else
3849  ereport(ERROR,
3850  (errcode(ERRCODE_UNDEFINED_OBJECT),
3851  errmsg("type with OID %u does not exist",
3852  rangetype)));
3853  }
3854  typeForm = (Form_pg_type) GETSTRUCT(tuple);
3855  }
3856 
3857  /*
3858  * Now get the type's owner and ACL from the tuple
3859  */
3860  ownerId = typeForm->typowner;
3861 
3862  aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3863  Anum_pg_type_typacl, &isNull);
3864  if (isNull)
3865  {
3866  /* No ACL, so build default ACL */
3867  acl = acldefault(OBJECT_TYPE, ownerId);
3868  aclDatum = (Datum) 0;
3869  }
3870  else
3871  {
3872  /* detoast rel's ACL if necessary */
3873  acl = DatumGetAclP(aclDatum);
3874  }
3875 
3876  result = aclmask(acl, roleid, ownerId, mask, how);
3877 
3878  /* if we have a detoasted copy, free it */
3879  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3880  pfree(acl);
3881 
3882  ReleaseSysCache(tuple);
3883 
3884  return result;
3885 }
3886 
3887 /*
3888  * Exported generic routine for checking a user's access privileges to an object
3889  */
3890 AclResult
3891 object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
3892 {
3893  return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3894 }
3895 
3896 /*
3897  * Exported generic routine for checking a user's access privileges to an
3898  * object, with is_missing
3899  */
3900 AclResult
3901 object_aclcheck_ext(Oid classid, Oid objectid,
3902  Oid roleid, AclMode mode,
3903  bool *is_missing)
3904 {
3905  if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
3906  is_missing) != 0)
3907  return ACLCHECK_OK;
3908  else
3909  return ACLCHECK_NO_PRIV;
3910 }
3911 
3912 /*
3913  * Exported routine for checking a user's access privileges to a column
3914  *
3915  * Returns ACLCHECK_OK if the user has any of the privileges identified by
3916  * 'mode'; otherwise returns a suitable error code (in practice, always
3917  * ACLCHECK_NO_PRIV).
3918  *
3919  * As with pg_attribute_aclmask, only privileges granted directly on the
3920  * column are considered here.
3921  */
3922 AclResult
3924  Oid roleid, AclMode mode)
3925 {
3926  return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3927 }
3928 
3929 
3930 /*
3931  * Exported routine for checking a user's access privileges to a column,
3932  * with is_missing
3933  */
3934 AclResult
3936  Oid roleid, AclMode mode, bool *is_missing)
3937 {
3938  if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3939  ACLMASK_ANY, is_missing) != 0)
3940  return ACLCHECK_OK;
3941  else
3942  return ACLCHECK_NO_PRIV;
3943 }
3944 
3945 /*
3946  * Exported routine for checking a user's access privileges to any/all columns
3947  *
3948  * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
3949  * privileges identified by 'mode' on any non-dropped column in the relation;
3950  * otherwise returns a suitable error code (in practice, always
3951  * ACLCHECK_NO_PRIV).
3952  *
3953  * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
3954  * privileges identified by 'mode' on each non-dropped column in the relation
3955  * (and there must be at least one such column); otherwise returns a suitable
3956  * error code (in practice, always ACLCHECK_NO_PRIV).
3957  *
3958  * As with pg_attribute_aclmask, only privileges granted directly on the
3959  * column(s) are considered here.
3960  *
3961  * Note: system columns are not considered here; there are cases where that
3962  * might be appropriate but there are also cases where it wouldn't.
3963  */
3964 AclResult
3966  AclMaskHow how)
3967 {
3968  return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3969 }
3970 
3971 /*
3972  * Exported routine for checking a user's access privileges to any/all columns,
3973  * with is_missing
3974  */
3975 AclResult
3977  AclMode mode, AclMaskHow how,
3978  bool *is_missing)
3979 {
3980  AclResult result;
3981  HeapTuple classTuple;
3982  Form_pg_class classForm;
3983  Oid ownerId;
3984  AttrNumber nattrs;
3985  AttrNumber curr_att;
3986 
3987  /*
3988  * Must fetch pg_class row to get owner ID and number of attributes.
3989  */
3990  classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3991  if (!HeapTupleIsValid(classTuple))
3992  {
3993  if (is_missing != NULL)
3994  {
3995  /* return "no privileges" instead of throwing an error */
3996  *is_missing = true;
3997  return ACLCHECK_NO_PRIV;
3998  }
3999  else
4000  ereport(ERROR,
4002  errmsg("relation with OID %u does not exist",
4003  table_oid)));
4004  }
4005  classForm = (Form_pg_class) GETSTRUCT(classTuple);
4006 
4007  ownerId = classForm->relowner;
4008  nattrs = classForm->relnatts;
4009 
4010  ReleaseSysCache(classTuple);
4011 
4012  /*
4013  * Initialize result in case there are no non-dropped columns. We want to
4014  * report failure in such cases for either value of 'how'.
4015  */
4016  result = ACLCHECK_NO_PRIV;
4017 
4018  for (curr_att = 1; curr_att <= nattrs; curr_att++)
4019  {
4020  HeapTuple attTuple;
4021  Datum aclDatum;
4022  bool isNull;
4023  Acl *acl;
4024  AclMode attmask;
4025 
4026  attTuple = SearchSysCache2(ATTNUM,
4027  ObjectIdGetDatum(table_oid),
4028  Int16GetDatum(curr_att));
4029 
4030  /*
4031  * Lookup failure probably indicates that the table was just dropped,
4032  * but we'll treat it the same as a dropped column rather than
4033  * throwing error.
4034  */
4035  if (!HeapTupleIsValid(attTuple))
4036  continue;
4037 
4038  /* ignore dropped columns */
4039  if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4040  {
4041  ReleaseSysCache(attTuple);
4042  continue;
4043  }
4044 
4045  aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
4046  &isNull);
4047 
4048  /*
4049  * Here we hard-wire knowledge that the default ACL for a column
4050  * grants no privileges, so that we can fall out quickly in the very
4051  * common case where attacl is null.
4052  */
4053  if (isNull)
4054  attmask = 0;
4055  else
4056  {
4057  /* detoast column's ACL if necessary */
4058  acl = DatumGetAclP(aclDatum);
4059 
4060  attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
4061 
4062  /* if we have a detoasted copy, free it */
4063  if ((Pointer) acl != DatumGetPointer(aclDatum))
4064  pfree(acl);
4065  }
4066 
4067  ReleaseSysCache(attTuple);
4068 
4069  if (attmask != 0)
4070  {
4071  result = ACLCHECK_OK;
4072  if (how == ACLMASK_ANY)
4073  break; /* succeed on any success */
4074  }
4075  else
4076  {
4077  result = ACLCHECK_NO_PRIV;
4078  if (how == ACLMASK_ALL)
4079  break; /* fail on any failure */
4080  }
4081  }
4082 
4083  return result;
4084 }
4085 
4086 /*
4087  * Exported routine for checking a user's access privileges to a table
4088  *
4089  * Returns ACLCHECK_OK if the user has any of the privileges identified by
4090  * 'mode'; otherwise returns a suitable error code (in practice, always
4091  * ACLCHECK_NO_PRIV).
4092  */
4093 AclResult
4094 pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
4095 {
4096  return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
4097 }
4098 
4099 /*
4100  * Exported routine for checking a user's access privileges to a table,
4101  * with is_missing
4102  */
4103 AclResult
4104 pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
4105  AclMode mode, bool *is_missing)
4106 {
4107  if (pg_class_aclmask_ext(table_oid, roleid, mode,
4108  ACLMASK_ANY, is_missing) != 0)
4109  return ACLCHECK_OK;
4110  else
4111  return ACLCHECK_NO_PRIV;
4112 }
4113 
4114 /*
4115  * Exported routine for checking a user's access privileges to a configuration
4116  * parameter (GUC), identified by GUC name.
4117  */
4118 AclResult
4120 {
4121  if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4122  return ACLCHECK_OK;
4123  else
4124  return ACLCHECK_NO_PRIV;
4125 }
4126 
4127 /*
4128  * Exported routine for checking a user's access privileges to a largeobject
4129  */
4130 AclResult
4132  Snapshot snapshot)
4133 {
4134  if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4135  ACLMASK_ANY, snapshot) != 0)
4136  return ACLCHECK_OK;
4137  else
4138  return ACLCHECK_NO_PRIV;
4139 }
4140 
4141 /*
4142  * Generic ownership check for an object
4143  */
4144 bool
4145 object_ownercheck(Oid classid, Oid objectid, Oid roleid)
4146 {
4147  int cacheid;
4148  Oid ownerId;
4149 
4150  /* Superusers bypass all permission checking. */
4151  if (superuser_arg(roleid))
4152  return true;
4153 
4154  /* For large objects, the catalog to consult is pg_largeobject_metadata */
4155  if (classid == LargeObjectRelationId)
4156  classid = LargeObjectMetadataRelationId;
4157 
4158  cacheid = get_object_catcache_oid(classid);
4159  if (cacheid != -1)
4160  {
4161  /* we can get the object's tuple from the syscache */
4162  HeapTuple tuple;
4163 
4164  tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4165  if (!HeapTupleIsValid(tuple))
4166  ereport(ERROR,
4167  (errcode(ERRCODE_UNDEFINED_OBJECT),
4168  errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
4169 
4170  ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4171  tuple,
4172  get_object_attnum_owner(classid)));
4173  ReleaseSysCache(tuple);
4174  }
4175  else
4176  {
4177  /* for catalogs without an appropriate syscache */
4178  Relation rel;
4179  ScanKeyData entry[1];
4180  SysScanDesc scan;
4181  HeapTuple tuple;
4182  bool isnull;
4183 
4184  rel = table_open(classid, AccessShareLock);
4185 
4186  ScanKeyInit(&entry[0],
4187  get_object_attnum_oid(classid),
4188  BTEqualStrategyNumber, F_OIDEQ,
4189  ObjectIdGetDatum(objectid));
4190 
4191  scan = systable_beginscan(rel,
4192  get_object_oid_index(classid), true,
4193  NULL, 1, entry);
4194 
4195  tuple = systable_getnext(scan);
4196  if (!HeapTupleIsValid(tuple))
4197  ereport(ERROR,
4198  (errcode(ERRCODE_UNDEFINED_OBJECT),
4199  errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
4200 
4201  ownerId = DatumGetObjectId(heap_getattr(tuple,
4202  get_object_attnum_owner(classid),
4203  RelationGetDescr(rel),
4204  &isnull));
4205  Assert(!isnull);
4206 
4207  systable_endscan(scan);
4209  }
4210 
4211  return has_privs_of_role(roleid, ownerId);
4212 }
4213 
4214 /*
4215  * Check whether specified role has CREATEROLE privilege (or is a superuser)
4216  *
4217  * Note: roles do not have owners per se; instead we use this test in
4218  * places where an ownership-like permissions test is needed for a role.
4219  * Be sure to apply it to the role trying to do the operation, not the
4220  * role being operated on! Also note that this generally should not be
4221  * considered enough privilege if the target role is a superuser.
4222  * (We don't handle that consideration here because we want to give a
4223  * separate error message for such cases, so the caller has to deal with it.)
4224  */
4225 bool
4227 {
4228  bool result = false;
4229  HeapTuple utup;
4230 
4231  /* Superusers bypass all permission checking. */
4232  if (superuser_arg(roleid))
4233  return true;
4234 
4235  utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4236  if (HeapTupleIsValid(utup))
4237  {
4238  result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4239  ReleaseSysCache(utup);
4240  }
4241  return result;
4242 }
4243 
4244 bool
4246 {
4247  bool result = false;
4248  HeapTuple utup;
4249 
4250  /* Superusers bypass all permission checking. */
4251  if (superuser_arg(roleid))
4252  return true;
4253 
4254  utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4255  if (HeapTupleIsValid(utup))
4256  {
4257  result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4258  ReleaseSysCache(utup);
4259  }
4260  return result;
4261 }
4262 
4263 /*
4264  * Fetch pg_default_acl entry for given role, namespace and object type
4265  * (object type must be given in pg_default_acl's encoding).
4266  * Returns NULL if no such entry.
4267  */
4268 static Acl *
4269 get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
4270 {
4271  Acl *result = NULL;
4272  HeapTuple tuple;
4273 
4274  tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4275  ObjectIdGetDatum(roleId),
4276  ObjectIdGetDatum(nsp_oid),
4277  CharGetDatum(objtype));
4278 
4279  if (HeapTupleIsValid(tuple))
4280  {
4281  Datum aclDatum;
4282  bool isNull;
4283 
4284  aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4285  Anum_pg_default_acl_defaclacl,
4286  &isNull);
4287  if (!isNull)
4288  result = DatumGetAclPCopy(aclDatum);
4289  ReleaseSysCache(tuple);
4290  }
4291 
4292  return result;
4293 }
4294 
4295 /*
4296  * Get default permissions for newly created object within given schema
4297  *
4298  * Returns NULL if built-in system defaults should be used.
4299  *
4300  * If the result is not NULL, caller must call recordDependencyOnNewAcl
4301  * once the OID of the new object is known.
4302  */
4303 Acl *
4304 get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
4305 {
4306  Acl *result;
4307  Acl *glob_acl;
4308  Acl *schema_acl;
4309  Acl *def_acl;
4310  char defaclobjtype;
4311 
4312  /*
4313  * Use NULL during bootstrap, since pg_default_acl probably isn't there
4314  * yet.
4315  */
4317  return NULL;
4318 
4319  /* Check if object type is supported in pg_default_acl */
4320  switch (objtype)
4321  {
4322  case OBJECT_TABLE:
4323  defaclobjtype = DEFACLOBJ_RELATION;
4324  break;
4325 
4326  case OBJECT_SEQUENCE:
4327  defaclobjtype = DEFACLOBJ_SEQUENCE;
4328  break;
4329 
4330  case OBJECT_FUNCTION:
4331  defaclobjtype = DEFACLOBJ_FUNCTION;
4332  break;
4333 
4334  case OBJECT_TYPE:
4335  defaclobjtype = DEFACLOBJ_TYPE;
4336  break;
4337 
4338  case OBJECT_SCHEMA:
4339  defaclobjtype = DEFACLOBJ_NAMESPACE;
4340  break;
4341 
4342  default:
4343  return NULL;
4344  }
4345 
4346  /* Look up the relevant pg_default_acl entries */
4347  glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4348  schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4349 
4350  /* Quick out if neither entry exists */
4351  if (glob_acl == NULL && schema_acl == NULL)
4352  return NULL;
4353 
4354  /* We need to know the hard-wired default value, too */
4355  def_acl = acldefault(objtype, ownerId);
4356 
4357  /* If there's no global entry, substitute the hard-wired default */
4358  if (glob_acl == NULL)
4359  glob_acl = def_acl;
4360 
4361  /* Merge in any per-schema privileges */
4362  result = aclmerge(glob_acl, schema_acl, ownerId);
4363 
4364  /*
4365  * For efficiency, we want to return NULL if the result equals default.
4366  * This requires sorting both arrays to get an accurate comparison.
4367  */
4368  aclitemsort(result);
4369  aclitemsort(def_acl);
4370  if (aclequal(result, def_acl))
4371  result = NULL;
4372 
4373  return result;
4374 }
4375 
4376 /*
4377  * Record dependencies on roles mentioned in a new object's ACL.
4378  */
4379 void
4380 recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
4381  Oid ownerId, Acl *acl)
4382 {
4383  int nmembers;
4384  Oid *members;
4385 
4386  /* Nothing to do if ACL is defaulted */
4387  if (acl == NULL)
4388  return;
4389 
4390  /* Extract roles mentioned in ACL */
4391  nmembers = aclmembers(acl, &members);
4392 
4393  /* Update the shared dependency ACL info */
4394  updateAclDependencies(classId, objectId, objsubId,
4395  ownerId,
4396  0, NULL,
4397  nmembers, members);
4398 }
4399 
4400 /*
4401  * Record initial privileges for the top-level object passed in.
4402  *
4403  * For the object passed in, this will record its ACL (if any) and the ACLs of
4404  * any sub-objects (eg: columns) into pg_init_privs.
4405  */
4406 void
4407 recordExtObjInitPriv(Oid objoid, Oid classoid)
4408 {
4409  /*
4410  * pg_class / pg_attribute
4411  *
4412  * If this is a relation then we need to see if there are any sub-objects
4413  * (eg: columns) for it and, if so, be sure to call
4414  * recordExtensionInitPrivWorker() for each one.
4415  */
4416  if (classoid == RelationRelationId)
4417  {
4418  Form_pg_class pg_class_tuple;
4419  Datum aclDatum;
4420  bool isNull;
4421  HeapTuple tuple;
4422 
4423  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4424  if (!HeapTupleIsValid(tuple))
4425  elog(ERROR, "cache lookup failed for relation %u", objoid);
4426  pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4427 
4428  /*
4429  * Indexes don't have permissions, neither do the pg_class rows for
4430  * composite types. (These cases are unreachable given the
4431  * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4432  */
4433  if (pg_class_tuple->relkind == RELKIND_INDEX ||
4434  pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4435  pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4436  {
4437  ReleaseSysCache(tuple);
4438  return;
4439  }
4440 
4441  /*
4442  * If this isn't a sequence then it's possibly going to have
4443  * column-level ACLs associated with it.
4444  */
4445  if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4446  {
4447  AttrNumber curr_att;
4448  AttrNumber nattrs = pg_class_tuple->relnatts;
4449 
4450  for (curr_att = 1; curr_att <= nattrs; curr_att++)
4451  {
4452  HeapTuple attTuple;
4453  Datum attaclDatum;
4454 
4455  attTuple = SearchSysCache2(ATTNUM,
4456  ObjectIdGetDatum(objoid),
4457  Int16GetDatum(curr_att));
4458 
4459  if (!HeapTupleIsValid(attTuple))
4460  continue;
4461 
4462  /* ignore dropped columns */
4463  if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4464  {
4465  ReleaseSysCache(attTuple);
4466  continue;
4467  }
4468 
4469  attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4470  Anum_pg_attribute_attacl,
4471  &isNull);
4472 
4473  /* no need to do anything for a NULL ACL */
4474  if (isNull)
4475  {
4476  ReleaseSysCache(attTuple);
4477  continue;
4478  }
4479 
4480  recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4481  DatumGetAclP(attaclDatum));
4482 
4483  ReleaseSysCache(attTuple);
4484  }
4485  }
4486 
4487  aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4488  &isNull);
4489 
4490  /* Add the record, if any, for the top-level object */
4491  if (!isNull)
4492  recordExtensionInitPrivWorker(objoid, classoid, 0,
4493  DatumGetAclP(aclDatum));
4494 
4495  ReleaseSysCache(tuple);
4496  }
4497  else if (classoid == LargeObjectRelationId)
4498  {
4499  /* For large objects, we must consult pg_largeobject_metadata */
4500  Datum aclDatum;
4501  bool isNull;
4502  HeapTuple tuple;
4503  ScanKeyData entry[1];
4504  SysScanDesc scan;
4505  Relation relation;
4506 
4507  /*
4508  * Note: this is dead code, given that we don't allow large objects to
4509  * be made extension members. But it seems worth carrying in case
4510  * some future caller of this function has need for it.
4511  */
4512  relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4513 
4514  /* There's no syscache for pg_largeobject_metadata */
4515  ScanKeyInit(&entry[0],
4516  Anum_pg_largeobject_metadata_oid,
4517  BTEqualStrategyNumber, F_OIDEQ,
4518  ObjectIdGetDatum(objoid));
4519 
4520  scan = systable_beginscan(relation,
4521  LargeObjectMetadataOidIndexId, true,
4522  NULL, 1, entry);
4523 
4524  tuple = systable_getnext(scan);
4525  if (!HeapTupleIsValid(tuple))
4526  elog(ERROR, "could not find tuple for large object %u", objoid);
4527 
4528  aclDatum = heap_getattr(tuple,
4529  Anum_pg_largeobject_metadata_lomacl,
4530  RelationGetDescr(relation), &isNull);
4531 
4532  /* Add the record, if any, for the top-level object */
4533  if (!isNull)
4534  recordExtensionInitPrivWorker(objoid, classoid, 0,
4535  DatumGetAclP(aclDatum));
4536 
4537  systable_endscan(scan);
4538  }
4539  /* This will error on unsupported classoid. */
4540  else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4541  {
4542  int cacheid;
4543  Datum aclDatum;
4544  bool isNull;
4545  HeapTuple tuple;
4546 
4547  cacheid = get_object_catcache_oid(classoid);
4548  tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
4549  if (!HeapTupleIsValid(tuple))
4550  elog(ERROR, "cache lookup failed for %s %u",
4551  get_object_class_descr(classoid), objoid);
4552 
4553  aclDatum = SysCacheGetAttr(cacheid, tuple,
4554  get_object_attnum_acl(classoid),
4555  &isNull);
4556 
4557  /* Add the record, if any, for the top-level object */
4558  if (!isNull)
4559  recordExtensionInitPrivWorker(objoid, classoid, 0,
4560  DatumGetAclP(aclDatum));
4561 
4562  ReleaseSysCache(tuple);
4563  }
4564 }
4565 
4566 /*
4567  * For the object passed in, remove its ACL and the ACLs of any object subIds
4568  * from pg_init_privs (via recordExtensionInitPrivWorker()).
4569  */
4570 void
4571 removeExtObjInitPriv(Oid objoid, Oid classoid)
4572 {
4573  /*
4574  * If this is a relation then we need to see if there are any sub-objects
4575  * (eg: columns) for it and, if so, be sure to call
4576  * recordExtensionInitPrivWorker() for each one.
4577  */
4578  if (classoid == RelationRelationId)
4579  {
4580  Form_pg_class pg_class_tuple;
4581  HeapTuple tuple;
4582 
4583  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4584  if (!HeapTupleIsValid(tuple))
4585  elog(ERROR, "cache lookup failed for relation %u", objoid);
4586  pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4587 
4588  /*
4589  * Indexes don't have permissions, neither do the pg_class rows for
4590  * composite types. (These cases are unreachable given the
4591  * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4592  */
4593  if (pg_class_tuple->relkind == RELKIND_INDEX ||
4594  pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4595  pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4596  {
4597  ReleaseSysCache(tuple);
4598  return;
4599  }
4600 
4601  /*
4602  * If this isn't a sequence then it's possibly going to have
4603  * column-level ACLs associated with it.
4604  */
4605  if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4606  {
4607  AttrNumber curr_att;
4608  AttrNumber nattrs = pg_class_tuple->relnatts;
4609 
4610  for (curr_att = 1; curr_att <= nattrs; curr_att++)
4611  {
4612  HeapTuple attTuple;
4613 
4614  attTuple = SearchSysCache2(ATTNUM,
4615  ObjectIdGetDatum(objoid),
4616  Int16GetDatum(curr_att));
4617 
4618  if (!HeapTupleIsValid(attTuple))
4619  continue;
4620 
4621  /* when removing, remove all entries, even dropped columns */
4622 
4623  recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4624 
4625  ReleaseSysCache(attTuple);
4626  }
4627  }
4628 
4629  ReleaseSysCache(tuple);
4630  }
4631 
4632  /* Remove the record, if any, for the top-level object */
4633  recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
4634 }
4635 
4636 /*
4637  * Record initial ACL for an extension object
4638  *
4639  * Can be called at any time, we check if 'creating_extension' is set and, if
4640  * not, exit immediately.
4641  *
4642  * Pass in the object OID, the OID of the class (the OID of the table which
4643  * the object is defined in) and the 'sub' id of the object (objsubid), if
4644  * any. If there is no 'sub' id (they are currently only used for columns of
4645  * tables) then pass in '0'. Finally, pass in the complete ACL to store.
4646  *
4647  * If an ACL already exists for this object/sub-object then we will replace
4648  * it with what is passed in.
4649  *
4650  * Passing in NULL for 'new_acl' will result in the entry for the object being
4651  * removed, if one is found.
4652  */
4653 static void
4654 recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
4655 {
4656  /*
4657  * Generally, we only record the initial privileges when an extension is
4658  * being created, but because we don't actually use CREATE EXTENSION
4659  * during binary upgrades with pg_upgrade, there is a variable to let us
4660  * know that the GRANT and REVOKE statements being issued, while this
4661  * variable is true, are for the initial privileges of the extension
4662  * object and therefore we need to record them.
4663  */
4665  return;
4666 
4667  recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4668 }
4669 
4670 /*
4671  * Record initial ACL for an extension object, worker.
4672  *
4673  * This will perform a wholesale replacement of the entire ACL for the object
4674  * passed in, therefore be sure to pass in the complete new ACL to use.
4675  *
4676  * Generally speaking, do *not* use this function directly but instead use
4677  * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
4678  * This function does *not* check if 'creating_extension' is set as it is also
4679  * used when an object is added to or removed from an extension via ALTER
4680  * EXTENSION ... ADD/DROP.
4681  */
4682 static void
4683 recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
4684  Acl *new_acl)
4685 {
4686  Relation relation;
4687  ScanKeyData key[3];
4688  SysScanDesc scan;
4689  HeapTuple tuple;
4690  HeapTuple oldtuple;
4691  int noldmembers;
4692  int nnewmembers;
4693  Oid *oldmembers;
4694  Oid *newmembers;
4695 
4696  /* We'll need the role membership of the new ACL. */
4697  nnewmembers = aclmembers(new_acl, &newmembers);
4698 
4699  /* Search pg_init_privs for an existing entry. */
4700  relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4701 
4702  ScanKeyInit(&key[0],
4703  Anum_pg_init_privs_objoid,
4704  BTEqualStrategyNumber, F_OIDEQ,
4705  ObjectIdGetDatum(objoid));
4706  ScanKeyInit(&key[1],
4707  Anum_pg_init_privs_classoid,
4708  BTEqualStrategyNumber, F_OIDEQ,
4709  ObjectIdGetDatum(classoid));
4710  ScanKeyInit(&key[2],
4711  Anum_pg_init_privs_objsubid,
4712  BTEqualStrategyNumber, F_INT4EQ,
4713  Int32GetDatum(objsubid));
4714 
4715  scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4716  NULL, 3, key);
4717 
4718  /* There should exist only one entry or none. */
4719  oldtuple = systable_getnext(scan);
4720 
4721  /* If we find an entry, update it with the latest ACL. */
4722  if (HeapTupleIsValid(oldtuple))
4723  {
4724  Datum values[Natts_pg_init_privs] = {0};
4725  bool nulls[Natts_pg_init_privs] = {0};
4726  bool replace[Natts_pg_init_privs] = {0};
4727  Datum oldAclDatum;
4728  bool isNull;
4729  Acl *old_acl;
4730 
4731  /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
4732  oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4733  RelationGetDescr(relation), &isNull);
4734  Assert(!isNull);
4735  old_acl = DatumGetAclP(oldAclDatum);
4736  noldmembers = aclmembers(old_acl, &oldmembers);
4737 
4738  updateInitAclDependencies(classoid, objoid, objsubid,
4739  noldmembers, oldmembers,
4740  nnewmembers, newmembers);
4741 
4742  /* If we have a new ACL to set, then update the row with it. */
4743  if (new_acl && ACL_NUM(new_acl) != 0)
4744  {
4745  values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4746  replace[Anum_pg_init_privs_initprivs - 1] = true;
4747 
4748  oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4749  values, nulls, replace);
4750 
4751  CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4752  }
4753  else
4754  {
4755  /* new_acl is NULL/empty, so delete the entry we found. */
4756  CatalogTupleDelete(relation, &oldtuple->t_self);
4757  }
4758  }
4759  else
4760  {
4761  Datum values[Natts_pg_init_privs] = {0};
4762  bool nulls[Natts_pg_init_privs] = {0};
4763 
4764  /*
4765  * Only add a new entry if the new ACL is non-NULL.
4766  *
4767  * If we are passed in a NULL ACL and no entry exists, we can just
4768  * fall through and do nothing.
4769  */
4770  if (new_acl && ACL_NUM(new_acl) != 0)
4771  {
4772  /* No entry found, so add it. */
4773  values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4774  values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4775  values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4776 
4777  /* This function only handles initial privileges of extensions */
4778  values[Anum_pg_init_privs_privtype - 1] =
4780 
4781  values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4782 
4783  tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4784 
4785  CatalogTupleInsert(relation, tuple);
4786 
4787  /* Update pg_shdepend, too. */
4788  noldmembers = 0;
4789  oldmembers = NULL;
4790 
4791  updateInitAclDependencies(classoid, objoid, objsubid,
4792  noldmembers, oldmembers,
4793  nnewmembers, newmembers);
4794  }
4795  }
4796 
4797  systable_endscan(scan);
4798 
4799  /* prevent error when processing objects multiple times */
4801 
4802  table_close(relation, RowExclusiveLock);
4803 }
4804 
4805 /*
4806  * ReplaceRoleInInitPriv
4807  *
4808  * Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
4809  */
4810 void
4811 ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
4812  Oid classid, Oid objid, int32 objsubid)
4813 {
4814  Relation rel;
4815  ScanKeyData key[3];
4816  SysScanDesc scan;
4817  HeapTuple oldtuple;
4818  Datum oldAclDatum;
4819  bool isNull;
4820  Acl *old_acl;
4821  Acl *new_acl;
4822  HeapTuple newtuple;
4823  int noldmembers;
4824  int nnewmembers;
4825  Oid *oldmembers;
4826  Oid *newmembers;
4827 
4828  /* Search for existing pg_init_privs entry for the target object. */
4829  rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4830 
4831  ScanKeyInit(&key[0],
4832  Anum_pg_init_privs_objoid,
4833  BTEqualStrategyNumber, F_OIDEQ,
4834  ObjectIdGetDatum(objid));
4835  ScanKeyInit(&key[1],
4836  Anum_pg_init_privs_classoid,
4837  BTEqualStrategyNumber, F_OIDEQ,
4838  ObjectIdGetDatum(classid));
4839  ScanKeyInit(&key[2],
4840  Anum_pg_init_privs_objsubid,
4841  BTEqualStrategyNumber, F_INT4EQ,
4842  Int32GetDatum(objsubid));
4843 
4844  scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4845  NULL, 3, key);
4846 
4847  /* There should exist only one entry or none. */
4848  oldtuple = systable_getnext(scan);
4849 
4850  if (!HeapTupleIsValid(oldtuple))
4851  {
4852  /*
4853  * Hmm, why are we here if there's no entry? But pack up and go away
4854  * quietly.
4855  */
4856  systable_endscan(scan);
4858  return;
4859  }
4860 
4861  /* Get a writable copy of the existing ACL. */
4862  oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4863  RelationGetDescr(rel), &isNull);
4864  Assert(!isNull);
4865  old_acl = DatumGetAclPCopy(oldAclDatum);
4866 
4867  /*
4868  * Generate new ACL. This usage of aclnewowner is a bit off-label when
4869  * oldroleid isn't the owner; but it does the job fine.
4870  */
4871  new_acl = aclnewowner(old_acl, oldroleid, newroleid);
4872 
4873  /*
4874  * If we end with an empty ACL, delete the pg_init_privs entry. (That
4875  * probably can't happen here, but we may as well cover the case.)
4876  */
4877  if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4878  {
4879  CatalogTupleDelete(rel, &oldtuple->t_self);
4880  }
4881  else
4882  {
4883  Datum values[Natts_pg_init_privs] = {0};
4884  bool nulls[Natts_pg_init_privs] = {0};
4885  bool replaces[Natts_pg_init_privs] = {0};
4886 
4887  /* Update existing entry. */
4888  values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4889  replaces[Anum_pg_init_privs_initprivs - 1] = true;
4890 
4891  newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4892  values, nulls, replaces);
4893  CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4894  }
4895 
4896  /*
4897  * Update the shared dependency ACL info.
4898  */
4899  noldmembers = aclmembers(old_acl, &oldmembers);
4900  nnewmembers = aclmembers(new_acl, &newmembers);
4901 
4902  updateInitAclDependencies(classid, objid, objsubid,
4903  noldmembers, oldmembers,
4904  nnewmembers, newmembers);
4905 
4906  systable_endscan(scan);
4907 
4908  /* prevent error when processing objects multiple times */
4910 
4912 }
4913 
4914 /*
4915  * RemoveRoleFromInitPriv
4916  *
4917  * Used by shdepDropOwned to remove mentions of a role in pg_init_privs.
4918  */
4919 void
4920 RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
4921 {
4922  Relation rel;
4923  ScanKeyData key[3];
4924  SysScanDesc scan;
4925  HeapTuple oldtuple;
4926  int cacheid;
4927  HeapTuple objtuple;
4928  Oid ownerId;
4929  Datum oldAclDatum;
4930  bool isNull;
4931  Acl *old_acl;
4932  Acl *new_acl;
4933  HeapTuple newtuple;
4934  int noldmembers;
4935  int nnewmembers;
4936  Oid *oldmembers;
4937  Oid *newmembers;
4938 
4939  /* Search for existing pg_init_privs entry for the target object. */
4940  rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4941 
4942  ScanKeyInit(&key[0],
4943  Anum_pg_init_privs_objoid,
4944  BTEqualStrategyNumber, F_OIDEQ,
4945  ObjectIdGetDatum(objid));
4946  ScanKeyInit(&key[1],
4947  Anum_pg_init_privs_classoid,
4948  BTEqualStrategyNumber, F_OIDEQ,
4949  ObjectIdGetDatum(classid));
4950  ScanKeyInit(&key[2],
4951  Anum_pg_init_privs_objsubid,
4952  BTEqualStrategyNumber, F_INT4EQ,
4953  Int32GetDatum(objsubid));
4954 
4955  scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4956  NULL, 3, key);
4957 
4958  /* There should exist only one entry or none. */
4959  oldtuple = systable_getnext(scan);
4960 
4961  if (!HeapTupleIsValid(oldtuple))
4962  {
4963  /*
4964  * Hmm, why are we here if there's no entry? But pack up and go away
4965  * quietly.
4966  */
4967  systable_endscan(scan);
4969  return;
4970  }
4971 
4972  /* Get a writable copy of the existing ACL. */
4973  oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4974  RelationGetDescr(rel), &isNull);
4975  Assert(!isNull);
4976  old_acl = DatumGetAclPCopy(oldAclDatum);
4977 
4978  /*
4979  * We need the members of both old and new ACLs so we can correct the
4980  * shared dependency information. Collect data before
4981  * merge_acl_with_grant throws away old_acl.
4982  */
4983  noldmembers = aclmembers(old_acl, &oldmembers);
4984 
4985  /* Must find out the owner's OID the hard way. */
4986  cacheid = get_object_catcache_oid(classid);
4987  objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
4988  if (!HeapTupleIsValid(objtuple))
4989  elog(ERROR, "cache lookup failed for %s %u",
4990  get_object_class_descr(classid), objid);
4991 
4992  ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4993  objtuple,
4994  get_object_attnum_owner(classid)));
4995  ReleaseSysCache(objtuple);
4996 
4997  /*
4998  * Generate new ACL. Grantor of rights is always the same as the owner.
4999  */
5000  if (old_acl != NULL)
5001  new_acl = merge_acl_with_grant(old_acl,
5002  false, /* is_grant */
5003  false, /* grant_option */
5004  DROP_RESTRICT,
5005  list_make1_oid(roleid),
5007  ownerId,
5008  ownerId);
5009  else
5010  new_acl = NULL; /* this case shouldn't happen, probably */
5011 
5012  /* If we end with an empty ACL, delete the pg_init_privs entry. */
5013  if (new_acl == NULL || ACL_NUM(new_acl) == 0)
5014  {
5015  CatalogTupleDelete(rel, &oldtuple->t_self);
5016  }
5017  else
5018  {
5019  Datum values[Natts_pg_init_privs] = {0};
5020  bool nulls[Natts_pg_init_privs] = {0};
5021  bool replaces[Natts_pg_init_privs] = {0};
5022 
5023  /* Update existing entry. */
5024  values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
5025  replaces[Anum_pg_init_privs_initprivs - 1] = true;
5026 
5027  newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
5028  values, nulls, replaces);
5029  CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
5030  }
5031 
5032  /*
5033  * Update the shared dependency ACL info.
5034  */
5035  nnewmembers = aclmembers(new_acl, &newmembers);
5036 
5037  updateInitAclDependencies(classid, objid, objsubid,
5038  noldmembers, oldmembers,
5039  nnewmembers, newmembers);
5040 
5041  systable_endscan(scan);
5042 
5043  /* prevent error when processing objects multiple times */
5045 
5047 }
Acl * aclupdate(const Acl *old_acl, const AclItem *mod_aip, int modechg, Oid ownerId, DropBehavior behavior)
Definition: acl.c:976
bool aclequal(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:543
void select_best_grantor(Oid roleId, AclMode privileges, const Acl *acl, Oid ownerId, Oid *grantorId, AclMode *grantOptions)
Definition: acl.c:5478
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5268
int aclmembers(const Acl *acl, Oid **roleids)
Definition: acl.c:1524
Acl * aclconcat(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:461
Acl * aclcopy(const Acl *orig_acl)
Definition: acl.c:441
void aclitemsort(Acl *acl)
Definition: acl.c:529
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1372
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition: acl.c:787
Acl * make_empty_acl(void)
Definition: acl.c:432
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1103
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5588
Acl * aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
Definition: acl.c:485
#define ACLITEM_ALL_PRIV_BITS
Definition: acl.h:87
#define ACL_ALL_RIGHTS_FOREIGN_SERVER
Definition: acl.h:164
#define ACL_ALL_RIGHTS_TABLESPACE
Definition: acl.h:170
AclResult
Definition: acl.h:182
@ ACLCHECK_NO_PRIV
Definition: acl.h:184
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
#define ACL_ALL_RIGHTS_PARAMETER_ACL
Definition: acl.h:168
#define ACL_ALL_RIGHTS_SCHEMA
Definition: acl.h:169
#define DatumGetAclP(X)
Definition: acl.h:120
#define ACL_MODECHG_DEL
Definition: acl.h:130
#define ACL_ALL_RIGHTS_SEQUENCE
Definition: acl.h:161
#define ACL_ALL_RIGHTS_DATABASE
Definition: acl.h:162
#define ACL_MODECHG_ADD
Definition: acl.h:129
#define ACL_ALL_RIGHTS_COLUMN
Definition: acl.h:159
#define ACL_OPTION_TO_PRIVS(privs)
Definition: acl.h:71
#define ACL_ALL_RIGHTS_FUNCTION
Definition: acl.h:165
#define ACL_ALL_RIGHTS_LANGUAGE
Definition: acl.h:166
#define ACL_ALL_RIGHTS_TYPE
Definition: acl.h:171
#define ACL_ALL_RIGHTS_FDW
Definition: acl.h:163
#define ACLITEM_SET_PRIVS_GOPTIONS(item, privs, goptions)
Definition: acl.h:82
#define ACL_NUM(ACL)
Definition: acl.h:108
#define DatumGetAclPCopy(X)
Definition: acl.h:121
#define ACL_ALL_RIGHTS_RELATION
Definition: acl.h:160
#define ACL_ID_PUBLIC
Definition: acl.h:46
#define ACL_ALL_RIGHTS_LARGEOBJECT
Definition: acl.h:167
AclMaskHow
Definition: acl.h:175
@ ACLMASK_ANY
Definition: acl.h:177
@ ACLMASK_ALL
Definition: acl.h:176
#define ACL_GRANT_OPTION_FOR(privs)
Definition: acl.h:70
static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3213
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3901
void ExecuteGrantStmt(GrantStmt *stmt)
Definition: aclchk.c:392
AclResult pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, Snapshot snapshot)
Definition: aclchk.c:4131
static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
Definition: aclchk.c:1634
void RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4920
static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4654
static void expand_col_privileges(List *colnames, Oid table_oid, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
Definition: aclchk.c:1601
bool has_bypassrls_privilege(Oid roleid)
Definition: aclchk.c:4245
AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:4104
void aclcheck_error_col(AclResult aclerr, ObjectType objtype, const char *objectname, const char *colname)
Definition: aclchk.c:2992
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3976
void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, Acl *acl)
Definition: aclchk.c:4380
static void ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, AttrNumber attnum, Oid ownerId, AclMode col_privileges, Relation attRelation, const Acl *old_rel_acl)
Definition: aclchk.c:1680
static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2444
void ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
Definition: aclchk.c:976
static void ExecGrantStmt_oids(InternalGrant *istmt)
Definition: aclchk.c:602
static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, AclMode mask, AclMaskHow how, Snapshot snapshot)
Definition: aclchk.c:3590
static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3202
static List * objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
Definition: aclchk.c:669
static Acl * merge_acl_with_grant(Acl *old_acl, bool is_grant, bool grant_option, DropBehavior behavior, List *grantees, AclMode privileges, Oid grantorId, Oid ownerId)
Definition: aclchk.c:182
static AclMode pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3467
AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
Definition: aclchk.c:3965
static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3531
static void SetDefaultACL(InternalDefaultACL *iacls)
Definition: aclchk.c:1203
static List * objectsInSchemaToOids(ObjectType objtype, List *nspnames)
Definition: aclchk.c:849
AclResult pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
Definition: aclchk.c:4119
void ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4811
static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
Definition: aclchk.c:2156
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:4407
static List * getRelationsInNamespace(Oid namespaceId, char relkind)
Definition: aclchk.c:938
static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3337
static AclMode string_to_privilege(const char *privname)
Definition: aclchk.c:2615
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2703
static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3099
static void ExecGrant_Largeobject(InternalGrant *istmt)
Definition: aclchk.c:2308
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3923
static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, AclMode privileges, Oid objectId, Oid grantorId, ObjectType objtype, const char *objname, AttrNumber att_number, const char *colname)
Definition: aclchk.c:241
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3891
Acl * get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
Definition: aclchk.c:4304
static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4683
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4145
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3935
static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3663
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
Definition: aclchk.c:1161
AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3327
static void ExecGrant_Parameter(InternalGrant *istmt)
Definition: aclchk.c:2472
static const char * privilege_to_string(AclMode privilege)
Definition: aclchk.c:2656
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3022
bool has_createrole_privilege(Oid roleid)
Definition: aclchk.c:4226
static Acl * get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
Definition: aclchk.c:4269
static void ExecGrant_Relation(InternalGrant *istmt)
Definition: aclchk.c:1825
static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3765
bool binary_upgrade_record_init_privs
Definition: aclchk.c:110
void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
Definition: aclchk.c:1466
static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2292
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4094
static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3034
static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3110
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:4571
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
static Datum values[MAXATTR]
Definition: bootstrap.c:150
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:749
signed int int32
Definition: c.h:497
#define gettext_noop(x)
Definition: c.h:1199
char * Pointer
Definition: c.h:486
#define Assert(condition)
Definition: c.h:861
#define OidIsValid(objectId)
Definition: c.h:778
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:85
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3140
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:384
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
@ DEPENDENCY_AUTO
Definition: dependency.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
bool EventTriggerSupportsObjectType(ObjectType obtype)
void EventTriggerCollectGrant(InternalGrant *istmt)
bool creating_extension
Definition: extension.c:72
#define palloc0_array(type, count)
Definition: fe_memutils.h:65
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:704
Oid get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok)
Definition: foreign.c:681
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
Oid MyDatabaseId
Definition: globals.c:93
char * convert_GUC_name_for_parameter_acl(const char *name)
Definition: guc.c:1373
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1243
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
int j
Definition: isn.c:74
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:595
#define NoLock
Definition: lockdefs.h:34
#define AccessShareLock
Definition: lockdefs.h:36
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2759
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3483
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:458
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:451
Oid GetUserId(void)
Definition: miscinit.c:514
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3385
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3649
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3535
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
AttrNumber get_object_attnum_owner(Oid class_id)
AttrNumber get_object_attnum_oid(Oid class_id)
AttrNumber get_object_attnum_name(Oid class_id)
AttrNumber get_object_attnum_acl(Oid class_id)
int get_object_catcache_oid(Oid class_id)
Oid get_object_oid_index(Oid class_id)
ObjectType get_object_type(Oid class_id, Oid object_id)
const char * get_object_class_descr(Oid class_id)
Oid oidparse(Node *node)
Definition: oid.c:235
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2206
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:400
#define ACL_CREATE_TEMP
Definition: parsenodes.h:86
#define ACL_SET
Definition: parsenodes.h:88
#define ACL_DELETE
Definition: parsenodes.h:79
uint64 AclMode
Definition: parsenodes.h:74
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define ACL_INSERT
Definition: parsenodes.h:76
#define ACL_NO_RIGHTS
Definition: parsenodes.h:92
#define ACL_UPDATE
Definition: parsenodes.h:78
DropBehavior
Definition: parsenodes.h:2329
@ DROP_CASCADE
Definition: parsenodes.h:2331
@ DROP_RESTRICT
Definition: parsenodes.h:2330
ObjectType
Definition: parsenodes.h:2256
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2271
@ OBJECT_FDW
Definition: parsenodes.h:2273
@ OBJECT_TSPARSER
Definition: parsenodes.h:2304
@ OBJECT_COLLATION
Definition: parsenodes.h:2264
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2307
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2257
@ OBJECT_OPCLASS
Definition: parsenodes.h:2281
@ OBJECT_DEFACL
Definition: parsenodes.h:2268
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2258
@ OBJECT_MATVIEW
Definition: parsenodes.h:2280
@ OBJECT_SCHEMA
Definition: parsenodes.h:2293
@ OBJECT_POLICY
Definition: parsenodes.h:2285
@ OBJECT_OPERATOR
Definition: parsenodes.h:2282
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2275
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2302
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2283
@ OBJECT_DOMAIN
Definition: parsenodes.h:2269
@ OBJECT_COLUMN
Definition: parsenodes.h:2263
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2299
@ OBJECT_ROLE
Definition: parsenodes.h:2290
@ OBJECT_ROUTINE
Definition: parsenodes.h:2291
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2279
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2288
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2286
@ OBJECT_EXTENSION
Definition: parsenodes.h:2272
@ OBJECT_INDEX
Definition: parsenodes.h:2277
@ OBJECT_DEFAULT
Definition: parsenodes.h:2267
@ OBJECT_DATABASE
Definition: parsenodes.h:2266
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2294
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2305
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2278
@ OBJECT_AMOP
Definition: parsenodes.h:2259
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2289
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2274
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2303
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2261
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2287
@ OBJECT_RULE
Definition: parsenodes.h:2292
@ OBJECT_CONVERSION
Definition: parsenodes.h:2265
@ OBJECT_AMPROC
Definition: parsenodes.h:2260
@ OBJECT_TABLE
Definition: parsenodes.h:2298
@ OBJECT_VIEW
Definition: parsenodes.h:2308
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2284
@ OBJECT_TYPE
Definition: parsenodes.h:2306
@ OBJECT_FUNCTION
Definition: parsenodes.h:2276
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2297
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2270
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2295
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2296
@ OBJECT_CAST
Definition: parsenodes.h:2262
@ OBJECT_TRIGGER
Definition: parsenodes.h:2301
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2300
@ ACL_TARGET_OBJECT
Definition: parsenodes.h:2485
@ ACL_TARGET_ALL_IN_SCHEMA
Definition: parsenodes.h:2486
#define ACL_CONNECT
Definition: parsenodes.h:87
#define ACL_ALTER_SYSTEM
Definition: parsenodes.h:89
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define ACL_SELECT
Definition: parsenodes.h:77
#define ACL_TRUNCATE
Definition: parsenodes.h:80
#define ACL_EXECUTE
Definition: parsenodes.h:83
#define ACL_CREATE
Definition: parsenodes.h:85
#define ACL_TRIGGER
Definition: parsenodes.h:82
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
bool rolcreaterole
Definition: pg_authid.h:37
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
bool rolbypassrls
Definition: pg_authid.h:41
static PgChecksumMode mode
Definition: pg_checksums.c:56
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define NAMEDATALEN
FormData_pg_default_acl * Form_pg_default_acl
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
@ INITPRIVS_EXTENSION
Definition: pg_init_privs.h:80
FormData_pg_language * Form_pg_language
Definition: pg_language.h:65
bool LargeObjectExists(Oid loid)
FormData_pg_largeobject_metadata * Form_pg_largeobject_metadata
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define lfirst_oid(lc)
Definition: pg_list.h:174
FormData_pg_namespace * Form_pg_namespace
Definition: pg_namespace.h:52
Oid ParameterAclLookup(const char *parameter, bool missing_ok)
Oid ParameterAclCreate(const char *parameter)
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:491
void updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:512
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
NameData typname
Definition: pg_type.h:41
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
#define snprintf
Definition: port.h:238
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Name DatumGetName(Datum X)
Definition: postgres.h:360
uintptr_t Datum
Definition: postgres.h:64
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
Oid get_language_oid(const char *langname, bool missing_ok)
Definition: proclang.c:226
#define RelationGetDescr(relation)
Definition: rel.h:531
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:28
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char * dbname
Definition: streamutil.c:52
Definition:<