PostgreSQL Source Code  git master
acl.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * acl.c
4  * Basic access control list data structures manipulation routines.
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/utils/adt/acl.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <ctype.h>
18 
19 #include "access/htup_details.h"
20 #include "catalog/catalog.h"
21 #include "catalog/namespace.h"
23 #include "catalog/pg_authid.h"
24 #include "catalog/pg_class.h"
25 #include "catalog/pg_database.h"
28 #include "catalog/pg_language.h"
29 #include "catalog/pg_largeobject.h"
30 #include "catalog/pg_namespace.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_tablespace.h"
33 #include "catalog/pg_type.h"
34 #include "commands/dbcommands.h"
35 #include "commands/proclang.h"
36 #include "commands/tablespace.h"
37 #include "common/hashfn.h"
38 #include "foreign/foreign.h"
39 #include "funcapi.h"
40 #include "lib/bloomfilter.h"
41 #include "lib/qunique.h"
42 #include "miscadmin.h"
43 #include "storage/large_object.h"
44 #include "utils/acl.h"
45 #include "utils/array.h"
46 #include "utils/builtins.h"
47 #include "utils/catcache.h"
48 #include "utils/inval.h"
49 #include "utils/lsyscache.h"
50 #include "utils/memutils.h"
51 #include "utils/snapmgr.h"
52 #include "utils/syscache.h"
53 #include "utils/varlena.h"
54 
55 typedef struct
56 {
57  const char *name;
59 } priv_map;
60 
61 /*
62  * We frequently need to test whether a given role is a member of some other
63  * role. In most of these tests the "given role" is the same, namely the
64  * active current user. So we can optimize it by keeping cached lists of all
65  * the roles the "given role" is a member of, directly or indirectly.
66  *
67  * Possibly this mechanism should be generalized to allow caching membership
68  * info for multiple roles?
69  *
70  * Each element of cached_roles is an OID list of constituent roles for the
71  * corresponding element of cached_role (always including the cached_role
72  * itself). There's a separate cache for each RoleRecurseType, with the
73  * corresponding semantics.
74  */
76 {
77  ROLERECURSE_MEMBERS = 0, /* recurse unconditionally */
78  ROLERECURSE_PRIVS = 1, /* recurse through inheritable grants */
79  ROLERECURSE_SETROLE = 2 /* recurse through grants with set_option */
80 };
82 static List *cached_roles[] = {NIL, NIL, NIL};
84 
85 /*
86  * If the list of roles gathered by roles_is_member_of() grows larger than the
87  * below threshold, a Bloom filter is created to speed up list membership
88  * checks. This threshold is set arbitrarily high to avoid the overhead of
89  * creating the Bloom filter until it seems likely to provide a net benefit.
90  */
91 #define ROLES_LIST_BLOOM_THRESHOLD 1024
92 
93 static const char *getid(const char *s, char *n, Node *escontext);
94 static void putid(char *p, const char *s);
95 static Acl *allocacl(int n);
96 static void check_acl(const Acl *acl);
97 static const char *aclparse(const char *s, AclItem *aip, Node *escontext);
98 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
99 static int aclitemComparator(const void *arg1, const void *arg2);
100 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
101  Oid ownerId);
102 static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
103  Oid ownerId, DropBehavior behavior);
104 
105 static AclMode convert_any_priv_string(text *priv_type_text,
106  const priv_map *privileges);
107 
108 static Oid convert_table_name(text *tablename);
109 static AclMode convert_table_priv_string(text *priv_type_text);
110 static AclMode convert_sequence_priv_string(text *priv_type_text);
111 static AttrNumber convert_column_name(Oid tableoid, text *column);
112 static AclMode convert_column_priv_string(text *priv_type_text);
113 static Oid convert_database_name(text *databasename);
114 static AclMode convert_database_priv_string(text *priv_type_text);
117 static Oid convert_function_name(text *functionname);
118 static AclMode convert_function_priv_string(text *priv_type_text);
119 static Oid convert_language_name(text *languagename);
120 static AclMode convert_language_priv_string(text *priv_type_text);
121 static Oid convert_schema_name(text *schemaname);
122 static AclMode convert_schema_priv_string(text *priv_type_text);
123 static Oid convert_server_name(text *servername);
124 static AclMode convert_server_priv_string(text *priv_type_text);
125 static Oid convert_tablespace_name(text *tablespacename);
126 static AclMode convert_tablespace_priv_string(text *priv_type_text);
127 static Oid convert_type_name(text *typename);
128 static AclMode convert_type_priv_string(text *priv_type_text);
129 static AclMode convert_parameter_priv_string(text *priv_text);
130 static AclMode convert_largeobject_priv_string(text *priv_text);
131 static AclMode convert_role_priv_string(text *priv_type_text);
132 static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
133 
134 static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
135 
136 
137 /*
138  * getid
139  * Consumes the first alphanumeric string (identifier) found in string
140  * 's', ignoring any leading white space. If it finds a double quote
141  * it returns the word inside the quotes.
142  *
143  * RETURNS:
144  * the string position in 's' that points to the next non-space character
145  * in 's', after any quotes. Also:
146  * - loads the identifier into 'n'. (If no identifier is found, 'n'
147  * contains an empty string.) 'n' must be NAMEDATALEN bytes.
148  *
149  * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
150  * in which case we log the error there and return NULL.
151  */
152 static const char *
153 getid(const char *s, char *n, Node *escontext)
154 {
155  int len = 0;
156  bool in_quotes = false;
157 
158  Assert(s && n);
159 
160  while (isspace((unsigned char) *s))
161  s++;
162  /* This code had better match what putid() does, below */
163  for (;
164  *s != '\0' &&
165  (isalnum((unsigned char) *s) ||
166  *s == '_' ||
167  *s == '"' ||
168  in_quotes);
169  s++)
170  {
171  if (*s == '"')
172  {
173  /* safe to look at next char (could be '\0' though) */
174  if (*(s + 1) != '"')
175  {
176  in_quotes = !in_quotes;
177  continue;
178  }
179  /* it's an escaped double quote; skip the escaping char */
180  s++;
181  }
182 
183  /* Add the character to the string */
184  if (len >= NAMEDATALEN - 1)
185  ereturn(escontext, NULL,
186  (errcode(ERRCODE_NAME_TOO_LONG),
187  errmsg("identifier too long"),
188  errdetail("Identifier must be less than %d characters.",
189  NAMEDATALEN)));
190 
191  n[len++] = *s;
192  }
193  n[len] = '\0';
194  while (isspace((unsigned char) *s))
195  s++;
196  return s;
197 }
198 
199 /*
200  * Write a role name at *p, adding double quotes if needed.
201  * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
202  * This needs to be kept in sync with dequoteAclUserName in pg_dump/dumputils.c
203  */
204 static void
205 putid(char *p, const char *s)
206 {
207  const char *src;
208  bool safe = true;
209 
210  for (src = s; *src; src++)
211  {
212  /* This test had better match what getid() does, above */
213  if (!isalnum((unsigned char) *src) && *src != '_')
214  {
215  safe = false;
216  break;
217  }
218  }
219  if (!safe)
220  *p++ = '"';
221  for (src = s; *src; src++)
222  {
223  /* A double quote character in a username is encoded as "" */
224  if (*src == '"')
225  *p++ = '"';
226  *p++ = *src;
227  }
228  if (!safe)
229  *p++ = '"';
230  *p = '\0';
231 }
232 
233 /*
234  * aclparse
235  * Consumes and parses an ACL specification of the form:
236  * [group|user] [A-Za-z0-9]*=[rwaR]*
237  * from string 's', ignoring any leading white space or white space
238  * between the optional id type keyword (group|user) and the actual
239  * ACL specification.
240  *
241  * The group|user decoration is unnecessary in the roles world,
242  * but we still accept it for backward compatibility.
243  *
244  * This routine is called by the parser as well as aclitemin(), hence
245  * the added generality.
246  *
247  * RETURNS:
248  * the string position in 's' immediately following the ACL
249  * specification. Also:
250  * - loads the structure pointed to by 'aip' with the appropriate
251  * UID/GID, id type identifier and mode type values.
252  *
253  * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
254  * in which case we log the error there and return NULL.
255  */
256 static const char *
257 aclparse(const char *s, AclItem *aip, Node *escontext)
258 {
259  AclMode privs,
260  goption,
261  read;
262  char name[NAMEDATALEN];
263  char name2[NAMEDATALEN];
264 
265  Assert(s && aip);
266 
267  s = getid(s, name, escontext);
268  if (s == NULL)
269  return NULL;
270  if (*s != '=')
271  {
272  /* we just read a keyword, not a name */
273  if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
274  ereturn(escontext, NULL,
275  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
276  errmsg("unrecognized key word: \"%s\"", name),
277  errhint("ACL key word must be \"group\" or \"user\".")));
278  /* move s to the name beyond the keyword */
279  s = getid(s, name, escontext);
280  if (s == NULL)
281  return NULL;
282  if (name[0] == '\0')
283  ereturn(escontext, NULL,
284  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
285  errmsg("missing name"),
286  errhint("A name must follow the \"group\" or \"user\" key word.")));
287  }
288 
289  if (*s != '=')
290  ereturn(escontext, NULL,
291  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
292  errmsg("missing \"=\" sign")));
293 
294  privs = goption = ACL_NO_RIGHTS;
295 
296  for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
297  {
298  switch (*s)
299  {
300  case '*':
301  goption |= read;
302  break;
303  case ACL_INSERT_CHR:
304  read = ACL_INSERT;
305  break;
306  case ACL_SELECT_CHR:
307  read = ACL_SELECT;
308  break;
309  case ACL_UPDATE_CHR:
310  read = ACL_UPDATE;
311  break;
312  case ACL_DELETE_CHR:
313  read = ACL_DELETE;
314  break;
315  case ACL_TRUNCATE_CHR:
316  read = ACL_TRUNCATE;
317  break;
318  case ACL_REFERENCES_CHR:
320  break;
321  case ACL_TRIGGER_CHR:
322  read = ACL_TRIGGER;
323  break;
324  case ACL_EXECUTE_CHR:
325  read = ACL_EXECUTE;
326  break;
327  case ACL_USAGE_CHR:
328  read = ACL_USAGE;
329  break;
330  case ACL_CREATE_CHR:
331  read = ACL_CREATE;
332  break;
333  case ACL_CREATE_TEMP_CHR:
335  break;
336  case ACL_CONNECT_CHR:
337  read = ACL_CONNECT;
338  break;
339  case ACL_SET_CHR:
340  read = ACL_SET;
341  break;
344  break;
345  case ACL_MAINTAIN_CHR:
346  read = ACL_MAINTAIN;
347  break;
348  default:
349  ereturn(escontext, NULL,
350  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
351  errmsg("invalid mode character: must be one of \"%s\"",
353  }
354 
355  privs |= read;
356  }
357 
358  if (name[0] == '\0')
359  aip->ai_grantee = ACL_ID_PUBLIC;
360  else
361  {
362  aip->ai_grantee = get_role_oid(name, true);
363  if (!OidIsValid(aip->ai_grantee))
364  ereturn(escontext, NULL,
365  (errcode(ERRCODE_UNDEFINED_OBJECT),
366  errmsg("role \"%s\" does not exist", name)));
367  }
368 
369  /*
370  * XXX Allow a degree of backward compatibility by defaulting the grantor
371  * to the superuser.
372  */
373  if (*s == '/')
374  {
375  s = getid(s + 1, name2, escontext);
376  if (s == NULL)
377  return NULL;
378  if (name2[0] == '\0')
379  ereturn(escontext, NULL,
380  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
381  errmsg("a name must follow the \"/\" sign")));
382  aip->ai_grantor = get_role_oid(name2, true);
383  if (!OidIsValid(aip->ai_grantor))
384  ereturn(escontext, NULL,
385  (errcode(ERRCODE_UNDEFINED_OBJECT),
386  errmsg("role \"%s\" does not exist", name2)));
387  }
388  else
389  {
390  aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
392  (errcode(ERRCODE_INVALID_GRANTOR),
393  errmsg("defaulting grantor to user ID %u",
394  BOOTSTRAP_SUPERUSERID)));
395  }
396 
397  ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
398 
399  return s;
400 }
401 
402 /*
403  * allocacl
404  * Allocates storage for a new Acl with 'n' entries.
405  *
406  * RETURNS:
407  * the new Acl
408  */
409 static Acl *
410 allocacl(int n)
411 {
412  Acl *new_acl;
413  Size size;
414 
415  if (n < 0)
416  elog(ERROR, "invalid size: %d", n);
417  size = ACL_N_SIZE(n);
418  new_acl = (Acl *) palloc0(size);
419  SET_VARSIZE(new_acl, size);
420  new_acl->ndim = 1;
421  new_acl->dataoffset = 0; /* we never put in any nulls */
422  new_acl->elemtype = ACLITEMOID;
423  ARR_LBOUND(new_acl)[0] = 1;
424  ARR_DIMS(new_acl)[0] = n;
425  return new_acl;
426 }
427 
428 /*
429  * Create a zero-entry ACL
430  */
431 Acl *
433 {
434  return allocacl(0);
435 }
436 
437 /*
438  * Copy an ACL
439  */
440 Acl *
441 aclcopy(const Acl *orig_acl)
442 {
443  Acl *result_acl;
444 
445  result_acl = allocacl(ACL_NUM(orig_acl));
446 
447  memcpy(ACL_DAT(result_acl),
448  ACL_DAT(orig_acl),
449  ACL_NUM(orig_acl) * sizeof(AclItem));
450 
451  return result_acl;
452 }
453 
454 /*
455  * Concatenate two ACLs
456  *
457  * This is a bit cheesy, since we may produce an ACL with redundant entries.
458  * Be careful what the result is used for!
459  */
460 Acl *
461 aclconcat(const Acl *left_acl, const Acl *right_acl)
462 {
463  Acl *result_acl;
464 
465  result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
466 
467  memcpy(ACL_DAT(result_acl),
468  ACL_DAT(left_acl),
469  ACL_NUM(left_acl) * sizeof(AclItem));
470 
471  memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
472  ACL_DAT(right_acl),
473  ACL_NUM(right_acl) * sizeof(AclItem));
474 
475  return result_acl;
476 }
477 
478 /*
479  * Merge two ACLs
480  *
481  * This produces a properly merged ACL with no redundant entries.
482  * Returns NULL on NULL input.
483  */
484 Acl *
485 aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
486 {
487  Acl *result_acl;
488  AclItem *aip;
489  int i,
490  num;
491 
492  /* Check for cases where one or both are empty/null */
493  if (left_acl == NULL || ACL_NUM(left_acl) == 0)
494  {
495  if (right_acl == NULL || ACL_NUM(right_acl) == 0)
496  return NULL;
497  else
498  return aclcopy(right_acl);
499  }
500  else
501  {
502  if (right_acl == NULL || ACL_NUM(right_acl) == 0)
503  return aclcopy(left_acl);
504  }
505 
506  /* Merge them the hard way, one item at a time */
507  result_acl = aclcopy(left_acl);
508 
509  aip = ACL_DAT(right_acl);
510  num = ACL_NUM(right_acl);
511 
512  for (i = 0; i < num; i++, aip++)
513  {
514  Acl *tmp_acl;
515 
516  tmp_acl = aclupdate(result_acl, aip, ACL_MODECHG_ADD,
517  ownerId, DROP_RESTRICT);
518  pfree(result_acl);
519  result_acl = tmp_acl;
520  }
521 
522  return result_acl;
523 }
524 
525 /*
526  * Sort the items in an ACL (into an arbitrary but consistent order)
527  */
528 void
530 {
531  if (acl != NULL && ACL_NUM(acl) > 1)
532  qsort(ACL_DAT(acl), ACL_NUM(acl), sizeof(AclItem), aclitemComparator);
533 }
534 
535 /*
536  * Check if two ACLs are exactly equal
537  *
538  * This will not detect equality if the two arrays contain the same items
539  * in different orders. To handle that case, sort both inputs first,
540  * using aclitemsort().
541  */
542 bool
543 aclequal(const Acl *left_acl, const Acl *right_acl)
544 {
545  /* Check for cases where one or both are empty/null */
546  if (left_acl == NULL || ACL_NUM(left_acl) == 0)
547  {
548  if (right_acl == NULL || ACL_NUM(right_acl) == 0)
549  return true;
550  else
551  return false;
552  }
553  else
554  {
555  if (right_acl == NULL || ACL_NUM(right_acl) == 0)
556  return false;
557  }
558 
559  if (ACL_NUM(left_acl) != ACL_NUM(right_acl))
560  return false;
561 
562  if (memcmp(ACL_DAT(left_acl),
563  ACL_DAT(right_acl),
564  ACL_NUM(left_acl) * sizeof(AclItem)) == 0)
565  return true;
566 
567  return false;
568 }
569 
570 /*
571  * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
572  */
573 static void
574 check_acl(const Acl *acl)
575 {
576  if (ARR_ELEMTYPE(acl) != ACLITEMOID)
577  ereport(ERROR,
578  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
579  errmsg("ACL array contains wrong data type")));
580  if (ARR_NDIM(acl) != 1)
581  ereport(ERROR,
582  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
583  errmsg("ACL arrays must be one-dimensional")));
584  if (ARR_HASNULL(acl))
585  ereport(ERROR,
586  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
587  errmsg("ACL arrays must not contain null values")));
588 }
589 
590 /*
591  * aclitemin
592  * Allocates storage for, and fills in, a new AclItem given a string
593  * 's' that contains an ACL specification. See aclparse for details.
594  *
595  * RETURNS:
596  * the new AclItem
597  */
598 Datum
600 {
601  const char *s = PG_GETARG_CSTRING(0);
602  Node *escontext = fcinfo->context;
603  AclItem *aip;
604 
605  aip = (AclItem *) palloc(sizeof(AclItem));
606 
607  s = aclparse(s, aip, escontext);
608  if (s == NULL)
609  PG_RETURN_NULL();
610 
611  while (isspace((unsigned char) *s))
612  ++s;
613  if (*s)
614  ereturn(escontext, (Datum) 0,
615  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
616  errmsg("extra garbage at the end of the ACL specification")));
617 
618  PG_RETURN_ACLITEM_P(aip);
619 }
620 
621 /*
622  * aclitemout
623  * Allocates storage for, and fills in, a new null-delimited string
624  * containing a formatted ACL specification. See aclparse for details.
625  *
626  * RETURNS:
627  * the new string
628  */
629 Datum
631 {
632  AclItem *aip = PG_GETARG_ACLITEM_P(0);
633  char *p;
634  char *out;
635  HeapTuple htup;
636  unsigned i;
637 
638  out = palloc(strlen("=/") +
639  2 * N_ACL_RIGHTS +
640  2 * (2 * NAMEDATALEN + 2) +
641  1);
642 
643  p = out;
644  *p = '\0';
645 
646  if (aip->ai_grantee != ACL_ID_PUBLIC)
647  {
648  htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantee));
649  if (HeapTupleIsValid(htup))
650  {
651  putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
652  ReleaseSysCache(htup);
653  }
654  else
655  {
656  /* Generate numeric OID if we don't find an entry */
657  sprintf(p, "%u", aip->ai_grantee);
658  }
659  }
660  while (*p)
661  ++p;
662 
663  *p++ = '=';
664 
665  for (i = 0; i < N_ACL_RIGHTS; ++i)
666  {
667  if (ACLITEM_GET_PRIVS(*aip) & (UINT64CONST(1) << i))
668  *p++ = ACL_ALL_RIGHTS_STR[i];
669  if (ACLITEM_GET_GOPTIONS(*aip) & (UINT64CONST(1) << i))
670  *p++ = '*';
671  }
672 
673  *p++ = '/';
674  *p = '\0';
675 
676  htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantor));
677  if (HeapTupleIsValid(htup))
678  {
679  putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
680  ReleaseSysCache(htup);
681  }
682  else
683  {
684  /* Generate numeric OID if we don't find an entry */
685  sprintf(p, "%u", aip->ai_grantor);
686  }
687 
688  PG_RETURN_CSTRING(out);
689 }
690 
691 /*
692  * aclitem_match
693  * Two AclItems are considered to match iff they have the same
694  * grantee and grantor; the privileges are ignored.
695  */
696 static bool
698 {
699  return a1->ai_grantee == a2->ai_grantee &&
700  a1->ai_grantor == a2->ai_grantor;
701 }
702 
703 /*
704  * aclitemComparator
705  * qsort comparison function for AclItems
706  */
707 static int
708 aclitemComparator(const void *arg1, const void *arg2)
709 {
710  const AclItem *a1 = (const AclItem *) arg1;
711  const AclItem *a2 = (const AclItem *) arg2;
712 
713  if (a1->ai_grantee > a2->ai_grantee)
714  return 1;
715  if (a1->ai_grantee < a2->ai_grantee)
716  return -1;
717  if (a1->ai_grantor > a2->ai_grantor)
718  return 1;
719  if (a1->ai_grantor < a2->ai_grantor)
720  return -1;
721  if (a1->ai_privs > a2->ai_privs)
722  return 1;
723  if (a1->ai_privs < a2->ai_privs)
724  return -1;
725  return 0;
726 }
727 
728 /*
729  * aclitem equality operator
730  */
731 Datum
733 {
736  bool result;
737 
738  result = a1->ai_privs == a2->ai_privs &&
739  a1->ai_grantee == a2->ai_grantee &&
740  a1->ai_grantor == a2->ai_grantor;
741  PG_RETURN_BOOL(result);
742 }
743 
744 /*
745  * aclitem hash function
746  *
747  * We make aclitems hashable not so much because anyone is likely to hash
748  * them, as because we want array equality to work on aclitem arrays, and
749  * with the typcache mechanism we must have a hash or btree opclass.
750  */
751 Datum
753 {
755 
756  /* not very bright, but avoids any issue of padding in struct */
757  PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
758 }
759 
760 /*
761  * 64-bit hash function for aclitem.
762  *
763  * Similar to hash_aclitem, but accepts a seed and returns a uint64 value.
764  */
765 Datum
767 {
769  uint64 seed = PG_GETARG_INT64(1);
770  uint32 sum = (uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor);
771 
772  return (seed == 0) ? UInt64GetDatum(sum) : hash_uint32_extended(sum, seed);
773 }
774 
775 /*
776  * acldefault() --- create an ACL describing default access permissions
777  *
778  * Change this routine if you want to alter the default access policy for
779  * newly-created objects (or any object with a NULL acl entry). When
780  * you make a change here, don't forget to update the GRANT man page,
781  * which explains all the default permissions.
782  *
783  * Note that these are the hard-wired "defaults" that are used in the
784  * absence of any pg_default_acl entry.
785  */
786 Acl *
787 acldefault(ObjectType objtype, Oid ownerId)
788 {
789  AclMode world_default;
790  AclMode owner_default;
791  int nacl;
792  Acl *acl;
793  AclItem *aip;
794 
795  switch (objtype)
796  {
797  case OBJECT_COLUMN:
798  /* by default, columns have no extra privileges */
799  world_default = ACL_NO_RIGHTS;
800  owner_default = ACL_NO_RIGHTS;
801  break;
802  case OBJECT_TABLE:
803  world_default = ACL_NO_RIGHTS;
804  owner_default = ACL_ALL_RIGHTS_RELATION;
805  break;
806  case OBJECT_SEQUENCE:
807  world_default = ACL_NO_RIGHTS;
808  owner_default = ACL_ALL_RIGHTS_SEQUENCE;
809  break;
810  case OBJECT_DATABASE:
811  /* for backwards compatibility, grant some rights by default */
812  world_default = ACL_CREATE_TEMP | ACL_CONNECT;
813  owner_default = ACL_ALL_RIGHTS_DATABASE;
814  break;
815  case OBJECT_FUNCTION:
816  /* Grant EXECUTE by default, for now */
817  world_default = ACL_EXECUTE;
818  owner_default = ACL_ALL_RIGHTS_FUNCTION;
819  break;
820  case OBJECT_LANGUAGE:
821  /* Grant USAGE by default, for now */
822  world_default = ACL_USAGE;
823  owner_default = ACL_ALL_RIGHTS_LANGUAGE;
824  break;
825  case OBJECT_LARGEOBJECT:
826  world_default = ACL_NO_RIGHTS;
827  owner_default = ACL_ALL_RIGHTS_LARGEOBJECT;
828  break;
829  case OBJECT_SCHEMA:
830  world_default = ACL_NO_RIGHTS;
831  owner_default = ACL_ALL_RIGHTS_SCHEMA;
832  break;
833  case OBJECT_TABLESPACE:
834  world_default = ACL_NO_RIGHTS;
835  owner_default = ACL_ALL_RIGHTS_TABLESPACE;
836  break;
837  case OBJECT_FDW:
838  world_default = ACL_NO_RIGHTS;
839  owner_default = ACL_ALL_RIGHTS_FDW;
840  break;
842  world_default = ACL_NO_RIGHTS;
843  owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
844  break;
845  case OBJECT_DOMAIN:
846  case OBJECT_TYPE:
847  world_default = ACL_USAGE;
848  owner_default = ACL_ALL_RIGHTS_TYPE;
849  break;
851  world_default = ACL_NO_RIGHTS;
852  owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
853  break;
854  default:
855  elog(ERROR, "unrecognized object type: %d", (int) objtype);
856  world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
857  owner_default = ACL_NO_RIGHTS;
858  break;
859  }
860 
861  nacl = 0;
862  if (world_default != ACL_NO_RIGHTS)
863  nacl++;
864  if (owner_default != ACL_NO_RIGHTS)
865  nacl++;
866 
867  acl = allocacl(nacl);
868  aip = ACL_DAT(acl);
869 
870  if (world_default != ACL_NO_RIGHTS)
871  {
872  aip->ai_grantee = ACL_ID_PUBLIC;
873  aip->ai_grantor = ownerId;
874  ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
875  aip++;
876  }
877 
878  /*
879  * Note that the owner's entry shows all ordinary privileges but no grant
880  * options. This is because his grant options come "from the system" and
881  * not from his own efforts. (The SQL spec says that the owner's rights
882  * come from a "_SYSTEM" authid.) However, we do consider that the
883  * owner's ordinary privileges are self-granted; this lets him revoke
884  * them. We implement the owner's grant options without any explicit
885  * "_SYSTEM"-like ACL entry, by internally special-casing the owner
886  * wherever we are testing grant options.
887  */
888  if (owner_default != ACL_NO_RIGHTS)
889  {
890  aip->ai_grantee = ownerId;
891  aip->ai_grantor = ownerId;
892  ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
893  }
894 
895  return acl;
896 }
897 
898 
899 /*
900  * SQL-accessible version of acldefault(). Hackish mapping from "char" type to
901  * OBJECT_* values.
902  */
903 Datum
905 {
906  char objtypec = PG_GETARG_CHAR(0);
907  Oid owner = PG_GETARG_OID(1);
908  ObjectType objtype = 0;
909 
910  switch (objtypec)
911  {
912  case 'c':
913  objtype = OBJECT_COLUMN;
914  break;
915  case 'r':
916  objtype = OBJECT_TABLE;
917  break;
918  case 's':
919  objtype = OBJECT_SEQUENCE;
920  break;
921  case 'd':
922  objtype = OBJECT_DATABASE;
923  break;
924  case 'f':
925  objtype = OBJECT_FUNCTION;
926  break;
927  case 'l':
928  objtype = OBJECT_LANGUAGE;
929  break;
930  case 'L':
931  objtype = OBJECT_LARGEOBJECT;
932  break;
933  case 'n':
934  objtype = OBJECT_SCHEMA;
935  break;
936  case 'p':
937  objtype = OBJECT_PARAMETER_ACL;
938  break;
939  case 't':
940  objtype = OBJECT_TABLESPACE;
941  break;
942  case 'F':
943  objtype = OBJECT_FDW;
944  break;
945  case 'S':
946  objtype = OBJECT_FOREIGN_SERVER;
947  break;
948  case 'T':
949  objtype = OBJECT_TYPE;
950  break;
951  default:
952  elog(ERROR, "unrecognized object type abbreviation: %c", objtypec);
953  }
954 
955  PG_RETURN_ACL_P(acldefault(objtype, owner));
956 }
957 
958 
959 /*
960  * Update an ACL array to add or remove specified privileges.
961  *
962  * old_acl: the input ACL array
963  * mod_aip: defines the privileges to be added, removed, or substituted
964  * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
965  * ownerId: Oid of object owner
966  * behavior: RESTRICT or CASCADE behavior for recursive removal
967  *
968  * ownerid and behavior are only relevant when the update operation specifies
969  * deletion of grant options.
970  *
971  * The result is a modified copy; the input object is not changed.
972  *
973  * NB: caller is responsible for having detoasted the input ACL, if needed.
974  */
975 Acl *
976 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
977  int modechg, Oid ownerId, DropBehavior behavior)
978 {
979  Acl *new_acl = NULL;
980  AclItem *old_aip,
981  *new_aip = NULL;
982  AclMode old_rights,
983  old_goptions,
984  new_rights,
985  new_goptions;
986  int dst,
987  num;
988 
989  /* Caller probably already checked old_acl, but be safe */
990  check_acl(old_acl);
991 
992  /* If granting grant options, check for circularity */
993  if (modechg != ACL_MODECHG_DEL &&
994  ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
995  check_circularity(old_acl, mod_aip, ownerId);
996 
997  num = ACL_NUM(old_acl);
998  old_aip = ACL_DAT(old_acl);
999 
1000  /*
1001  * Search the ACL for an existing entry for this grantee and grantor. If
1002  * one exists, just modify the entry in-place (well, in the same position,
1003  * since we actually return a copy); otherwise, insert the new entry at
1004  * the end.
1005  */
1006 
1007  for (dst = 0; dst < num; ++dst)
1008  {
1009  if (aclitem_match(mod_aip, old_aip + dst))
1010  {
1011  /* found a match, so modify existing item */
1012  new_acl = allocacl(num);
1013  new_aip = ACL_DAT(new_acl);
1014  memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
1015  break;
1016  }
1017  }
1018 
1019  if (dst == num)
1020  {
1021  /* need to append a new item */
1022  new_acl = allocacl(num + 1);
1023  new_aip = ACL_DAT(new_acl);
1024  memcpy(new_aip, old_aip, num * sizeof(AclItem));
1025 
1026  /* initialize the new entry with no permissions */
1027  new_aip[dst].ai_grantee = mod_aip->ai_grantee;
1028  new_aip[dst].ai_grantor = mod_aip->ai_grantor;
1029  ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
1031  num++; /* set num to the size of new_acl */
1032  }
1033 
1034  old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
1035  old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
1036 
1037  /* apply the specified permissions change */
1038  switch (modechg)
1039  {
1040  case ACL_MODECHG_ADD:
1041  ACLITEM_SET_RIGHTS(new_aip[dst],
1042  old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
1043  break;
1044  case ACL_MODECHG_DEL:
1045  ACLITEM_SET_RIGHTS(new_aip[dst],
1046  old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
1047  break;
1048  case ACL_MODECHG_EQL:
1049  ACLITEM_SET_RIGHTS(new_aip[dst],
1050  ACLITEM_GET_RIGHTS(*mod_aip));
1051  break;
1052  }
1053 
1054  new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
1055  new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
1056 
1057  /*
1058  * If the adjusted entry has no permissions, delete it from the list.
1059  */
1060  if (new_rights == ACL_NO_RIGHTS)
1061  {
1062  memmove(new_aip + dst,
1063  new_aip + dst + 1,
1064  (num - dst - 1) * sizeof(AclItem));
1065  /* Adjust array size to be 'num - 1' items */
1066  ARR_DIMS(new_acl)[0] = num - 1;
1067  SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
1068  }
1069 
1070  /*
1071  * Remove abandoned privileges (cascading revoke). Currently we can only
1072  * handle this when the grantee is not PUBLIC.
1073  */
1074  if ((old_goptions & ~new_goptions) != 0)
1075  {
1076  Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
1077  new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
1078  (old_goptions & ~new_goptions),
1079  ownerId, behavior);
1080  }
1081 
1082  return new_acl;
1083 }
1084 
1085 /*
1086  * Update an ACL array to reflect a change of owner to the parent object
1087  *
1088  * old_acl: the input ACL array (must not be NULL)
1089  * oldOwnerId: Oid of the old object owner
1090  * newOwnerId: Oid of the new object owner
1091  *
1092  * The result is a modified copy; the input object is not changed.
1093  *
1094  * NB: caller is responsible for having detoasted the input ACL, if needed.
1095  *
1096  * Note: the name of this function is a bit of a misnomer, since it will
1097  * happily make the specified role substitution whether the old role is
1098  * really the owner of the parent object or merely mentioned in its ACL.
1099  * But the vast majority of callers use it in connection with ALTER OWNER
1100  * operations, so we'll keep the name.
1101  */
1102 Acl *
1103 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
1104 {
1105  Acl *new_acl;
1106  AclItem *new_aip;
1107  AclItem *old_aip;
1108  AclItem *dst_aip;
1109  AclItem *src_aip;
1110  AclItem *targ_aip;
1111  bool newpresent = false;
1112  int dst,
1113  src,
1114  targ,
1115  num;
1116 
1117  check_acl(old_acl);
1118 
1119  /*
1120  * Make a copy of the given ACL, substituting new owner ID for old
1121  * wherever it appears as either grantor or grantee. Also note if the new
1122  * owner ID is already present.
1123  */
1124  num = ACL_NUM(old_acl);
1125  old_aip = ACL_DAT(old_acl);
1126  new_acl = allocacl(num);
1127  new_aip = ACL_DAT(new_acl);
1128  memcpy(new_aip, old_aip, num * sizeof(AclItem));
1129  for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
1130  {
1131  if (dst_aip->ai_grantor == oldOwnerId)
1132  dst_aip->ai_grantor = newOwnerId;
1133  else if (dst_aip->ai_grantor == newOwnerId)
1134  newpresent = true;
1135  if (dst_aip->ai_grantee == oldOwnerId)
1136  dst_aip->ai_grantee = newOwnerId;
1137  else if (dst_aip->ai_grantee == newOwnerId)
1138  newpresent = true;
1139  }
1140 
1141  /*
1142  * If the old ACL contained any references to the new owner, then we may
1143  * now have generated an ACL containing duplicate entries. Find them and
1144  * merge them so that there are not duplicates. (This is relatively
1145  * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
1146  * be the normal case.)
1147  *
1148  * To simplify deletion of duplicate entries, we temporarily leave them in
1149  * the array but set their privilege masks to zero; when we reach such an
1150  * entry it's just skipped. (Thus, a side effect of this code will be to
1151  * remove privilege-free entries, should there be any in the input.) dst
1152  * is the next output slot, targ is the currently considered input slot
1153  * (always >= dst), and src scans entries to the right of targ looking for
1154  * duplicates. Once an entry has been emitted to dst it is known
1155  * duplicate-free and need not be considered anymore.
1156  */
1157  if (newpresent)
1158  {
1159  dst = 0;
1160  for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
1161  {
1162  /* ignore if deleted in an earlier pass */
1163  if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
1164  continue;
1165  /* find and merge any duplicates */
1166  for (src = targ + 1, src_aip = targ_aip + 1; src < num;
1167  src++, src_aip++)
1168  {
1169  if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
1170  continue;
1171  if (aclitem_match(targ_aip, src_aip))
1172  {
1173  ACLITEM_SET_RIGHTS(*targ_aip,
1174  ACLITEM_GET_RIGHTS(*targ_aip) |
1175  ACLITEM_GET_RIGHTS(*src_aip));
1176  /* mark the duplicate deleted */
1177  ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
1178  }
1179  }
1180  /* and emit to output */
1181  new_aip[dst] = *targ_aip;
1182  dst++;
1183  }
1184  /* Adjust array size to be 'dst' items */
1185  ARR_DIMS(new_acl)[0] = dst;
1186  SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
1187  }
1188 
1189  return new_acl;
1190 }
1191 
1192 
1193 /*
1194  * When granting grant options, we must disallow attempts to set up circular
1195  * chains of grant options. Suppose A (the object owner) grants B some
1196  * privileges with grant option, and B re-grants them to C. If C could
1197  * grant the privileges to B as well, then A would be unable to effectively
1198  * revoke the privileges from B, since recursive_revoke would consider that
1199  * B still has 'em from C.
1200  *
1201  * We check for this by recursively deleting all grant options belonging to
1202  * the target grantee, and then seeing if the would-be grantor still has the
1203  * grant option or not.
1204  */
1205 static void
1206 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
1207  Oid ownerId)
1208 {
1209  Acl *acl;
1210  AclItem *aip;
1211  int i,
1212  num;
1213  AclMode own_privs;
1214 
1215  check_acl(old_acl);
1216 
1217  /*
1218  * For now, grant options can only be granted to roles, not PUBLIC.
1219  * Otherwise we'd have to work a bit harder here.
1220  */
1221  Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
1222 
1223  /* The owner always has grant options, no need to check */
1224  if (mod_aip->ai_grantor == ownerId)
1225  return;
1226 
1227  /* Make a working copy */
1228  acl = allocacl(ACL_NUM(old_acl));
1229  memcpy(acl, old_acl, ACL_SIZE(old_acl));
1230 
1231  /* Zap all grant options of target grantee, plus what depends on 'em */
1232 cc_restart:
1233  num = ACL_NUM(acl);
1234  aip = ACL_DAT(acl);
1235  for (i = 0; i < num; i++)
1236  {
1237  if (aip[i].ai_grantee == mod_aip->ai_grantee &&
1239  {
1240  Acl *new_acl;
1241 
1242  /* We'll actually zap ordinary privs too, but no matter */
1243  new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
1244  ownerId, DROP_CASCADE);
1245 
1246  pfree(acl);
1247  acl = new_acl;
1248 
1249  goto cc_restart;
1250  }
1251  }
1252 
1253  /* Now we can compute grantor's independently-derived privileges */
1254  own_privs = aclmask(acl,
1255  mod_aip->ai_grantor,
1256  ownerId,
1258  ACLMASK_ALL);
1259  own_privs = ACL_OPTION_TO_PRIVS(own_privs);
1260 
1261  if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
1262  ereport(ERROR,
1263  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1264  errmsg("grant options cannot be granted back to your own grantor")));
1265 
1266  pfree(acl);
1267 }
1268 
1269 
1270 /*
1271  * Ensure that no privilege is "abandoned". A privilege is abandoned
1272  * if the user that granted the privilege loses the grant option. (So
1273  * the chain through which it was granted is broken.) Either the
1274  * abandoned privileges are revoked as well, or an error message is
1275  * printed, depending on the drop behavior option.
1276  *
1277  * acl: the input ACL list
1278  * grantee: the user from whom some grant options have been revoked
1279  * revoke_privs: the grant options being revoked
1280  * ownerId: Oid of object owner
1281  * behavior: RESTRICT or CASCADE behavior for recursive removal
1282  *
1283  * The input Acl object is pfree'd if replaced.
1284  */
1285 static Acl *
1287  Oid grantee,
1288  AclMode revoke_privs,
1289  Oid ownerId,
1290  DropBehavior behavior)
1291 {
1292  AclMode still_has;
1293  AclItem *aip;
1294  int i,
1295  num;
1296 
1297  check_acl(acl);
1298 
1299  /* The owner can never truly lose grant options, so short-circuit */
1300  if (grantee == ownerId)
1301  return acl;
1302 
1303  /* The grantee might still have some grant options via another grantor */
1304  still_has = aclmask(acl, grantee, ownerId,
1305  ACL_GRANT_OPTION_FOR(revoke_privs),
1306  ACLMASK_ALL);
1307  revoke_privs &= ~ACL_OPTION_TO_PRIVS(still_has);
1308  if (revoke_privs == ACL_NO_RIGHTS)
1309  return acl;
1310 
1311 restart:
1312  num = ACL_NUM(acl);
1313  aip = ACL_DAT(acl);
1314  for (i = 0; i < num; i++)
1315  {
1316  if (aip[i].ai_grantor == grantee
1317  && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1318  {
1319  AclItem mod_acl;
1320  Acl *new_acl;
1321 
1322  if (behavior == DROP_RESTRICT)
1323  ereport(ERROR,
1324  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1325  errmsg("dependent privileges exist"),
1326  errhint("Use CASCADE to revoke them too.")));
1327 
1328  mod_acl.ai_grantor = grantee;
1329  mod_acl.ai_grantee = aip[i].ai_grantee;
1331  revoke_privs,
1332  revoke_privs);
1333 
1334  new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1335  ownerId, behavior);
1336 
1337  pfree(acl);
1338  acl = new_acl;
1339 
1340  goto restart;
1341  }
1342  }
1343 
1344  return acl;
1345 }
1346 
1347 
1348 /*
1349  * aclmask --- compute bitmask of all privileges held by roleid.
1350  *
1351  * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1352  * held by the given roleid according to the given ACL list, ANDed
1353  * with 'mask'. (The point of passing 'mask' is to let the routine
1354  * exit early if all privileges of interest have been found.)
1355  *
1356  * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1357  * is known true. (This lets us exit soonest in cases where the
1358  * caller is only going to test for zero or nonzero result.)
1359  *
1360  * Usage patterns:
1361  *
1362  * To see if any of a set of privileges are held:
1363  * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1364  *
1365  * To see if all of a set of privileges are held:
1366  * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1367  *
1368  * To determine exactly which of a set of privileges are held:
1369  * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1370  */
1371 AclMode
1372 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1373  AclMode mask, AclMaskHow how)
1374 {
1375  AclMode result;
1377  AclItem *aidat;
1378  int i,
1379  num;
1380 
1381  /*
1382  * Null ACL should not happen, since caller should have inserted
1383  * appropriate default
1384  */
1385  if (acl == NULL)
1386  elog(ERROR, "null ACL");
1387 
1388  check_acl(acl);
1389 
1390  /* Quick exit for mask == 0 */
1391  if (mask == 0)
1392  return 0;
1393 
1394  result = 0;
1395 
1396  /* Owner always implicitly has all grant options */
1397  if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1398  has_privs_of_role(roleid, ownerId))
1399  {
1400  result = mask & ACLITEM_ALL_GOPTION_BITS;
1401  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1402  return result;
1403  }
1404 
1405  num = ACL_NUM(acl);
1406  aidat = ACL_DAT(acl);
1407 
1408  /*
1409  * Check privileges granted directly to roleid or to public
1410  */
1411  for (i = 0; i < num; i++)
1412  {
1413  AclItem *aidata = &aidat[i];
1414 
1415  if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1416  aidata->ai_grantee == roleid)
1417  {
1418  result |= aidata->ai_privs & mask;
1419  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1420  return result;
1421  }
1422  }
1423 
1424  /*
1425  * Check privileges granted indirectly via role memberships. We do this in
1426  * a separate pass to minimize expensive indirect membership tests. In
1427  * particular, it's worth testing whether a given ACL entry grants any
1428  * privileges still of interest before we perform the has_privs_of_role
1429  * test.
1430  */
1431  remaining = mask & ~result;
1432  for (i = 0; i < num; i++)
1433  {
1434  AclItem *aidata = &aidat[i];
1435 
1436  if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1437  aidata->ai_grantee == roleid)
1438  continue; /* already checked it */
1439 
1440  if ((aidata->ai_privs & remaining) &&
1441  has_privs_of_role(roleid, aidata->ai_grantee))
1442  {
1443  result |= aidata->ai_privs & mask;
1444  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1445  return result;
1446  remaining = mask & ~result;
1447  }
1448  }
1449 
1450  return result;
1451 }
1452 
1453 
1454 /*
1455  * aclmask_direct --- compute bitmask of all privileges held by roleid.
1456  *
1457  * This is exactly like aclmask() except that we consider only privileges
1458  * held *directly* by roleid, not those inherited via role membership.
1459  */
1460 static AclMode
1461 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1462  AclMode mask, AclMaskHow how)
1463 {
1464  AclMode result;
1465  AclItem *aidat;
1466  int i,
1467  num;
1468 
1469  /*
1470  * Null ACL should not happen, since caller should have inserted
1471  * appropriate default
1472  */
1473  if (acl == NULL)
1474  elog(ERROR, "null ACL");
1475 
1476  check_acl(acl);
1477 
1478  /* Quick exit for mask == 0 */
1479  if (mask == 0)
1480  return 0;
1481 
1482  result = 0;
1483 
1484  /* Owner always implicitly has all grant options */
1485  if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1486  roleid == ownerId)
1487  {
1488  result = mask & ACLITEM_ALL_GOPTION_BITS;
1489  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1490  return result;
1491  }
1492 
1493  num = ACL_NUM(acl);
1494  aidat = ACL_DAT(acl);
1495 
1496  /*
1497  * Check privileges granted directly to roleid (and not to public)
1498  */
1499  for (i = 0; i < num; i++)
1500  {
1501  AclItem *aidata = &aidat[i];
1502 
1503  if (aidata->ai_grantee == roleid)
1504  {
1505  result |= aidata->ai_privs & mask;
1506  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1507  return result;
1508  }
1509  }
1510 
1511  return result;
1512 }
1513 
1514 
1515 /*
1516  * aclmembers
1517  * Find out all the roleids mentioned in an Acl.
1518  * Note that we do not distinguish grantors from grantees.
1519  *
1520  * *roleids is set to point to a palloc'd array containing distinct OIDs
1521  * in sorted order. The length of the array is the function result.
1522  */
1523 int
1524 aclmembers(const Acl *acl, Oid **roleids)
1525 {
1526  Oid *list;
1527  const AclItem *acldat;
1528  int i,
1529  j;
1530 
1531  if (acl == NULL || ACL_NUM(acl) == 0)
1532  {
1533  *roleids = NULL;
1534  return 0;
1535  }
1536 
1537  check_acl(acl);
1538 
1539  /* Allocate the worst-case space requirement */
1540  list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1541  acldat = ACL_DAT(acl);
1542 
1543  /*
1544  * Walk the ACL collecting mentioned RoleIds.
1545  */
1546  j = 0;
1547  for (i = 0; i < ACL_NUM(acl); i++)
1548  {
1549  const AclItem *ai = &acldat[i];
1550 
1551  if (ai->ai_grantee != ACL_ID_PUBLIC)
1552  list[j++] = ai->ai_grantee;
1553  /* grantor is currently never PUBLIC, but let's check anyway */
1554  if (ai->ai_grantor != ACL_ID_PUBLIC)
1555  list[j++] = ai->ai_grantor;
1556  }
1557 
1558  /* Sort the array */
1559  qsort(list, j, sizeof(Oid), oid_cmp);
1560 
1561  /*
1562  * We could repalloc the array down to minimum size, but it's hardly worth
1563  * it since it's only transient memory.
1564  */
1565  *roleids = list;
1566 
1567  /* Remove duplicates from the array */
1568  return qunique(list, j, sizeof(Oid), oid_cmp);
1569 }
1570 
1571 
1572 /*
1573  * aclinsert (exported function)
1574  */
1575 Datum
1577 {
1578  ereport(ERROR,
1579  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1580  errmsg("aclinsert is no longer supported")));
1581 
1582  PG_RETURN_NULL(); /* keep compiler quiet */
1583 }
1584 
1585 Datum
1587 {
1588  ereport(ERROR,
1589  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1590  errmsg("aclremove is no longer supported")));
1591 
1592  PG_RETURN_NULL(); /* keep compiler quiet */
1593 }
1594 
1595 Datum
1597 {
1598  Acl *acl = PG_GETARG_ACL_P(0);
1599  AclItem *aip = PG_GETARG_ACLITEM_P(1);
1600  AclItem *aidat;
1601  int i,
1602  num;
1603 
1604  check_acl(acl);
1605  num = ACL_NUM(acl);
1606  aidat = ACL_DAT(acl);
1607  for (i = 0; i < num; ++i)
1608  {
1609  if (aip->ai_grantee == aidat[i].ai_grantee &&
1610  aip->ai_grantor == aidat[i].ai_grantor &&
1611  (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1612  PG_RETURN_BOOL(true);
1613  }
1614  PG_RETURN_BOOL(false);
1615 }
1616 
1617 Datum
1619 {
1620  Oid grantee = PG_GETARG_OID(0);
1621  Oid grantor = PG_GETARG_OID(1);
1622  text *privtext = PG_GETARG_TEXT_PP(2);
1623  bool goption = PG_GETARG_BOOL(3);
1624  AclItem *result;
1625  AclMode priv;
1626  static const priv_map any_priv_map[] = {
1627  {"SELECT", ACL_SELECT},
1628  {"INSERT", ACL_INSERT},
1629  {"UPDATE", ACL_UPDATE},
1630  {"DELETE", ACL_DELETE},
1631  {"TRUNCATE", ACL_TRUNCATE},
1632  {"REFERENCES", ACL_REFERENCES},
1633  {"TRIGGER", ACL_TRIGGER},
1634  {"EXECUTE", ACL_EXECUTE},
1635  {"USAGE", ACL_USAGE},
1636  {"CREATE", ACL_CREATE},
1637  {"TEMP", ACL_CREATE_TEMP},
1638  {"TEMPORARY", ACL_CREATE_TEMP},
1639  {"CONNECT", ACL_CONNECT},
1640  {"SET", ACL_SET},
1641  {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
1642  {"MAINTAIN", ACL_MAINTAIN},
1643  {NULL, 0}
1644  };
1645 
1646  priv = convert_any_priv_string(privtext, any_priv_map);
1647 
1648  result = (AclItem *) palloc(sizeof(AclItem));
1649 
1650  result->ai_grantee = grantee;
1651  result->ai_grantor = grantor;
1652 
1653  ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1654  (goption ? priv : ACL_NO_RIGHTS));
1655 
1656  PG_RETURN_ACLITEM_P(result);
1657 }
1658 
1659 
1660 /*
1661  * convert_any_priv_string: recognize privilege strings for has_foo_privilege
1662  *
1663  * We accept a comma-separated list of case-insensitive privilege names,
1664  * producing a bitmask of the OR'd privilege bits. We are liberal about
1665  * whitespace between items, not so much about whitespace within items.
1666  * The allowed privilege names are given as an array of priv_map structs,
1667  * terminated by one with a NULL name pointer.
1668  */
1669 static AclMode
1671  const priv_map *privileges)
1672 {
1673  AclMode result = 0;
1674  char *priv_type = text_to_cstring(priv_type_text);
1675  char *chunk;
1676  char *next_chunk;
1677 
1678  /* We rely on priv_type being a private, modifiable string */
1679  for (chunk = priv_type; chunk; chunk = next_chunk)
1680  {
1681  int chunk_len;
1682  const priv_map *this_priv;
1683 
1684  /* Split string at commas */
1685  next_chunk = strchr(chunk, ',');
1686  if (next_chunk)
1687  *next_chunk++ = '\0';
1688 
1689  /* Drop leading/trailing whitespace in this chunk */
1690  while (*chunk && isspace((unsigned char) *chunk))
1691  chunk++;
1692  chunk_len = strlen(chunk);
1693  while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
1694  chunk_len--;
1695  chunk[chunk_len] = '\0';
1696 
1697  /* Match to the privileges list */
1698  for (this_priv = privileges; this_priv->name; this_priv++)
1699  {
1700  if (pg_strcasecmp(this_priv->name, chunk) == 0)
1701  {
1702  result |= this_priv->value;
1703  break;
1704  }
1705  }
1706  if (!this_priv->name)
1707  ereport(ERROR,
1708  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1709  errmsg("unrecognized privilege type: \"%s\"", chunk)));
1710  }
1711 
1712  pfree(priv_type);
1713  return result;
1714 }
1715 
1716 
1717 static const char *
1719 {
1720  switch (aclright)
1721  {
1722  case ACL_INSERT:
1723  return "INSERT";
1724  case ACL_SELECT:
1725  return "SELECT";
1726  case ACL_UPDATE:
1727  return "UPDATE";
1728  case ACL_DELETE:
1729  return "DELETE";
1730  case ACL_TRUNCATE:
1731  return "TRUNCATE";
1732  case ACL_REFERENCES:
1733  return "REFERENCES";
1734  case ACL_TRIGGER:
1735  return "TRIGGER";
1736  case ACL_EXECUTE:
1737  return "EXECUTE";
1738  case ACL_USAGE:
1739  return "USAGE";
1740  case ACL_CREATE:
1741  return "CREATE";
1742  case ACL_CREATE_TEMP:
1743  return "TEMPORARY";
1744  case ACL_CONNECT:
1745  return "CONNECT";
1746  case ACL_SET:
1747  return "SET";
1748  case ACL_ALTER_SYSTEM:
1749  return "ALTER SYSTEM";
1750  case ACL_MAINTAIN:
1751  return "MAINTAIN";
1752  default:
1753  elog(ERROR, "unrecognized aclright: %d", aclright);
1754  return NULL;
1755  }
1756 }
1757 
1758 
1759 /*----------
1760  * Convert an aclitem[] to a table.
1761  *
1762  * Example:
1763  *
1764  * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
1765  *
1766  * returns the table
1767  *
1768  * {{ OID(joe), 0::OID, 'SELECT', false },
1769  * { OID(joe), OID(foo), 'INSERT', true },
1770  * { OID(joe), OID(foo), 'UPDATE', false }}
1771  *----------
1772  */
1773 Datum
1775 {
1776  Acl *acl = PG_GETARG_ACL_P(0);
1777  FuncCallContext *funcctx;
1778  int *idx;
1779  AclItem *aidat;
1780 
1781  if (SRF_IS_FIRSTCALL())
1782  {
1783  TupleDesc tupdesc;
1784  MemoryContext oldcontext;
1785 
1786  check_acl(acl);
1787 
1788  funcctx = SRF_FIRSTCALL_INIT();
1789  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1790 
1791  /*
1792  * build tupdesc for result tuples (matches out parameters in pg_proc
1793  * entry)
1794  */
1795  tupdesc = CreateTemplateTupleDesc(4);
1796  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
1797  OIDOID, -1, 0);
1798  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
1799  OIDOID, -1, 0);
1800  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
1801  TEXTOID, -1, 0);
1802  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
1803  BOOLOID, -1, 0);
1804 
1805  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1806 
1807  /* allocate memory for user context */
1808  idx = (int *) palloc(sizeof(int[2]));
1809  idx[0] = 0; /* ACL array item index */
1810  idx[1] = -1; /* privilege type counter */
1811  funcctx->user_fctx = idx;
1812 
1813  MemoryContextSwitchTo(oldcontext);
1814  }
1815 
1816  funcctx = SRF_PERCALL_SETUP();
1817  idx = (int *) funcctx->user_fctx;
1818  aidat = ACL_DAT(acl);
1819 
1820  /* need test here in case acl has no items */
1821  while (idx[0] < ACL_NUM(acl))
1822  {
1823  AclItem *aidata;
1824  AclMode priv_bit;
1825 
1826  idx[1]++;
1827  if (idx[1] == N_ACL_RIGHTS)
1828  {
1829  idx[1] = 0;
1830  idx[0]++;
1831  if (idx[0] >= ACL_NUM(acl)) /* done */
1832  break;
1833  }
1834  aidata = &aidat[idx[0]];
1835  priv_bit = UINT64CONST(1) << idx[1];
1836 
1837  if (ACLITEM_GET_PRIVS(*aidata) & priv_bit)
1838  {
1839  Datum result;
1840  Datum values[4];
1841  bool nulls[4] = {0};
1842  HeapTuple tuple;
1843 
1844  values[0] = ObjectIdGetDatum(aidata->ai_grantor);
1845  values[1] = ObjectIdGetDatum(aidata->ai_grantee);
1847  values[3] = BoolGetDatum((ACLITEM_GET_GOPTIONS(*aidata) & priv_bit) != 0);
1848 
1849  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1850  result = HeapTupleGetDatum(tuple);
1851 
1852  SRF_RETURN_NEXT(funcctx, result);
1853  }
1854  }
1855 
1856  SRF_RETURN_DONE(funcctx);
1857 }
1858 
1859 
1860 /*
1861  * has_table_privilege variants
1862  * These are all named "has_table_privilege" at the SQL level.
1863  * They take various combinations of relation name, relation OID,
1864  * user name, user OID, or implicit user = current_user.
1865  *
1866  * The result is a boolean value: true if user has the indicated
1867  * privilege, false if not. The variants that take a relation OID
1868  * return NULL if the OID doesn't exist (rather than failing, as
1869  * they did before Postgres 8.4).
1870  */
1871 
1872 /*
1873  * has_table_privilege_name_name
1874  * Check user privileges on a table given
1875  * name username, text tablename, and text priv name.
1876  */
1877 Datum
1879 {
1880  Name rolename = PG_GETARG_NAME(0);
1881  text *tablename = PG_GETARG_TEXT_PP(1);
1882  text *priv_type_text = PG_GETARG_TEXT_PP(2);
1883  Oid roleid;
1884  Oid tableoid;
1885  AclMode mode;
1886  AclResult aclresult;
1887 
1888  roleid = get_role_oid_or_public(NameStr(*rolename));
1889  tableoid = convert_table_name(tablename);
1890  mode = convert_table_priv_string(priv_type_text);
1891 
1892  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1893 
1894  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1895 }
1896 
1897 /*
1898  * has_table_privilege_name
1899  * Check user privileges on a table given
1900  * text tablename and text priv name.
1901  * current_user is assumed
1902  */
1903 Datum
1905 {
1906  text *tablename = PG_GETARG_TEXT_PP(0);
1907  text *priv_type_text = PG_GETARG_TEXT_PP(1);
1908  Oid roleid;
1909  Oid tableoid;
1910  AclMode mode;
1911  AclResult aclresult;
1912 
1913  roleid = GetUserId();
1914  tableoid = convert_table_name(tablename);
1915  mode = convert_table_priv_string(priv_type_text);
1916 
1917  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1918 
1919  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1920 }
1921 
1922 /*
1923  * has_table_privilege_name_id
1924  * Check user privileges on a table given
1925  * name usename, table oid, and text priv name.
1926  */
1927 Datum
1929 {
1931  Oid tableoid = PG_GETARG_OID(1);
1932  text *priv_type_text = PG_GETARG_TEXT_PP(2);
1933  Oid roleid;
1934  AclMode mode;
1935  AclResult aclresult;
1936  bool is_missing = false;
1937 
1939  mode = convert_table_priv_string(priv_type_text);
1940 
1941  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
1942 
1943  if (is_missing)
1944  PG_RETURN_NULL();
1945 
1946  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1947 }
1948 
1949 /*
1950  * has_table_privilege_id
1951  * Check user privileges on a table given
1952  * table oid, and text priv name.
1953  * current_user is assumed
1954  */
1955 Datum
1957 {
1958  Oid tableoid = PG_GETARG_OID(0);
1959  text *priv_type_text = PG_GETARG_TEXT_PP(1);
1960  Oid roleid;
1961  AclMode mode;
1962  AclResult aclresult;
1963  bool is_missing = false;
1964 
1965  roleid = GetUserId();
1966  mode = convert_table_priv_string(priv_type_text);
1967 
1968  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
1969 
1970  if (is_missing)
1971  PG_RETURN_NULL();
1972 
1973  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1974 }
1975 
1976 /*
1977  * has_table_privilege_id_name
1978  * Check user privileges on a table given
1979  * roleid, text tablename, and text priv name.
1980  */
1981 Datum
1983 {
1984  Oid roleid = PG_GETARG_OID(0);
1985  text *tablename = PG_GETARG_TEXT_PP(1);
1986  text *priv_type_text = PG_GETARG_TEXT_PP(2);
1987  Oid tableoid;
1988  AclMode mode;
1989  AclResult aclresult;
1990 
1991  tableoid = convert_table_name(tablename);
1992  mode = convert_table_priv_string(priv_type_text);
1993 
1994  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1995 
1996  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1997 }
1998 
1999 /*
2000  * has_table_privilege_id_id
2001  * Check user privileges on a table given
2002  * roleid, table oid, and text priv name.
2003  */
2004 Datum
2006 {
2007  Oid roleid = PG_GETARG_OID(0);
2008  Oid tableoid = PG_GETARG_OID(1);
2009  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2010  AclMode mode;
2011  AclResult aclresult;
2012  bool is_missing = false;
2013 
2014  mode = convert_table_priv_string(priv_type_text);
2015 
2016  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2017 
2018  if (is_missing)
2019  PG_RETURN_NULL();
2020 
2021  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2022 }
2023 
2024 /*
2025  * Support routines for has_table_privilege family.
2026  */
2027 
2028 /*
2029  * Given a table name expressed as a string, look it up and return Oid
2030  */
2031 static Oid
2033 {
2034  RangeVar *relrv;
2035 
2037 
2038  /* We might not even have permissions on this relation; don't lock it. */
2039  return RangeVarGetRelid(relrv, NoLock, false);
2040 }
2041 
2042 /*
2043  * convert_table_priv_string
2044  * Convert text string to AclMode value.
2045  */
2046 static AclMode
2048 {
2049  static const priv_map table_priv_map[] = {
2050  {"SELECT", ACL_SELECT},
2051  {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2052  {"INSERT", ACL_INSERT},
2053  {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2054  {"UPDATE", ACL_UPDATE},
2055  {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2056  {"DELETE", ACL_DELETE},
2057  {"DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE)},
2058  {"TRUNCATE", ACL_TRUNCATE},
2059  {"TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE)},
2060  {"REFERENCES", ACL_REFERENCES},
2061  {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2062  {"TRIGGER", ACL_TRIGGER},
2063  {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
2064  {"MAINTAIN", ACL_MAINTAIN},
2065  {"MAINTAIN WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_MAINTAIN)},
2066  {NULL, 0}
2067  };
2068 
2069  return convert_any_priv_string(priv_type_text, table_priv_map);
2070 }
2071 
2072 /*
2073  * has_sequence_privilege variants
2074  * These are all named "has_sequence_privilege" at the SQL level.
2075  * They take various combinations of relation name, relation OID,
2076  * user name, user OID, or implicit user = current_user.
2077  *
2078  * The result is a boolean value: true if user has the indicated
2079  * privilege, false if not. The variants that take a relation OID
2080  * return NULL if the OID doesn't exist.
2081  */
2082 
2083 /*
2084  * has_sequence_privilege_name_name
2085  * Check user privileges on a sequence given
2086  * name username, text sequencename, and text priv name.
2087  */
2088 Datum
2090 {
2091  Name rolename = PG_GETARG_NAME(0);
2092  text *sequencename = PG_GETARG_TEXT_PP(1);
2093  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2094  Oid roleid;
2095  Oid sequenceoid;
2096  AclMode mode;
2097  AclResult aclresult;
2098 
2099  roleid = get_role_oid_or_public(NameStr(*rolename));
2100  mode = convert_sequence_priv_string(priv_type_text);
2101  sequenceoid = convert_table_name(sequencename);
2102  if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2103  ereport(ERROR,
2104  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2105  errmsg("\"%s\" is not a sequence",
2106  text_to_cstring(sequencename))));
2107 
2108  aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2109 
2110  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2111 }
2112 
2113 /*
2114  * has_sequence_privilege_name
2115  * Check user privileges on a sequence given
2116  * text sequencename and text priv name.
2117  * current_user is assumed
2118  */
2119 Datum
2121 {
2122  text *sequencename = PG_GETARG_TEXT_PP(0);
2123  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2124  Oid roleid;
2125  Oid sequenceoid;
2126  AclMode mode;
2127  AclResult aclresult;
2128 
2129  roleid = GetUserId();
2130  mode = convert_sequence_priv_string(priv_type_text);
2131  sequenceoid = convert_table_name(sequencename);
2132  if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2133  ereport(ERROR,
2134  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2135  errmsg("\"%s\" is not a sequence",
2136  text_to_cstring(sequencename))));
2137 
2138  aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2139 
2140  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2141 }
2142 
2143 /*
2144  * has_sequence_privilege_name_id
2145  * Check user privileges on a sequence given
2146  * name usename, sequence oid, and text priv name.
2147  */
2148 Datum
2150 {
2152  Oid sequenceoid = PG_GETARG_OID(1);
2153  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2154  Oid roleid;
2155  AclMode mode;
2156  AclResult aclresult;
2157  char relkind;
2158  bool is_missing = false;
2159 
2161  mode = convert_sequence_priv_string(priv_type_text);
2162  relkind = get_rel_relkind(sequenceoid);
2163  if (relkind == '\0')
2164  PG_RETURN_NULL();
2165  else if (relkind != RELKIND_SEQUENCE)
2166  ereport(ERROR,
2167  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2168  errmsg("\"%s\" is not a sequence",
2169  get_rel_name(sequenceoid))));
2170 
2171  aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2172 
2173  if (is_missing)
2174  PG_RETURN_NULL();
2175 
2176  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2177 }
2178 
2179 /*
2180  * has_sequence_privilege_id
2181  * Check user privileges on a sequence given
2182  * sequence oid, and text priv name.
2183  * current_user is assumed
2184  */
2185 Datum
2187 {
2188  Oid sequenceoid = PG_GETARG_OID(0);
2189  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2190  Oid roleid;
2191  AclMode mode;
2192  AclResult aclresult;
2193  char relkind;
2194  bool is_missing = false;
2195 
2196  roleid = GetUserId();
2197  mode = convert_sequence_priv_string(priv_type_text);
2198  relkind = get_rel_relkind(sequenceoid);
2199  if (relkind == '\0')
2200  PG_RETURN_NULL();
2201  else if (relkind != RELKIND_SEQUENCE)
2202  ereport(ERROR,
2203  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2204  errmsg("\"%s\" is not a sequence",
2205  get_rel_name(sequenceoid))));
2206 
2207  aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2208 
2209  if (is_missing)
2210  PG_RETURN_NULL();
2211 
2212  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2213 }
2214 
2215 /*
2216  * has_sequence_privilege_id_name
2217  * Check user privileges on a sequence given
2218  * roleid, text sequencename, and text priv name.
2219  */
2220 Datum
2222 {
2223  Oid roleid = PG_GETARG_OID(0);
2224  text *sequencename = PG_GETARG_TEXT_PP(1);
2225  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2226  Oid sequenceoid;
2227  AclMode mode;
2228  AclResult aclresult;
2229 
2230  mode = convert_sequence_priv_string(priv_type_text);
2231  sequenceoid = convert_table_name(sequencename);
2232  if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2233  ereport(ERROR,
2234  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2235  errmsg("\"%s\" is not a sequence",
2236  text_to_cstring(sequencename))));
2237 
2238  aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2239 
2240  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2241 }
2242 
2243 /*
2244  * has_sequence_privilege_id_id
2245  * Check user privileges on a sequence given
2246  * roleid, sequence oid, and text priv name.
2247  */
2248 Datum
2250 {
2251  Oid roleid = PG_GETARG_OID(0);
2252  Oid sequenceoid = PG_GETARG_OID(1);
2253  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2254  AclMode mode;
2255  AclResult aclresult;
2256  char relkind;
2257  bool is_missing = false;
2258 
2259  mode = convert_sequence_priv_string(priv_type_text);
2260  relkind = get_rel_relkind(sequenceoid);
2261  if (relkind == '\0')
2262  PG_RETURN_NULL();
2263  else if (relkind != RELKIND_SEQUENCE)
2264  ereport(ERROR,
2265  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2266  errmsg("\"%s\" is not a sequence",
2267  get_rel_name(sequenceoid))));
2268 
2269  aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2270 
2271  if (is_missing)
2272  PG_RETURN_NULL();
2273 
2274  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2275 }
2276 
2277 /*
2278  * convert_sequence_priv_string
2279  * Convert text string to AclMode value.
2280  */
2281 static AclMode
2283 {
2284  static const priv_map sequence_priv_map[] = {
2285  {"USAGE", ACL_USAGE},
2286  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
2287  {"SELECT", ACL_SELECT},
2288  {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2289  {"UPDATE", ACL_UPDATE},
2290  {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2291  {NULL, 0}
2292  };
2293 
2294  return convert_any_priv_string(priv_type_text, sequence_priv_map);
2295 }
2296 
2297 
2298 /*
2299  * has_any_column_privilege variants
2300  * These are all named "has_any_column_privilege" at the SQL level.
2301  * They take various combinations of relation name, relation OID,
2302  * user name, user OID, or implicit user = current_user.
2303  *
2304  * The result is a boolean value: true if user has the indicated
2305  * privilege for any column of the table, false if not. The variants
2306  * that take a relation OID return NULL if the OID doesn't exist.
2307  */
2308 
2309 /*
2310  * has_any_column_privilege_name_name
2311  * Check user privileges on any column of a table given
2312  * name username, text tablename, and text priv name.
2313  */
2314 Datum
2316 {
2317  Name rolename = PG_GETARG_NAME(0);
2318  text *tablename = PG_GETARG_TEXT_PP(1);
2319  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2320  Oid roleid;
2321  Oid tableoid;
2322  AclMode mode;
2323  AclResult aclresult;
2324 
2325  roleid = get_role_oid_or_public(NameStr(*rolename));
2326  tableoid = convert_table_name(tablename);
2327  mode = convert_column_priv_string(priv_type_text);
2328 
2329  /* First check at table level, then examine each column if needed */
2330  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2331  if (aclresult != ACLCHECK_OK)
2332  aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2333  ACLMASK_ANY);
2334 
2335  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2336 }
2337 
2338 /*
2339  * has_any_column_privilege_name
2340  * Check user privileges on any column of a table given
2341  * text tablename and text priv name.
2342  * current_user is assumed
2343  */
2344 Datum
2346 {
2347  text *tablename = PG_GETARG_TEXT_PP(0);
2348  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2349  Oid roleid;
2350  Oid tableoid;
2351  AclMode mode;
2352  AclResult aclresult;
2353 
2354  roleid = GetUserId();
2355  tableoid = convert_table_name(tablename);
2356  mode = convert_column_priv_string(priv_type_text);
2357 
2358  /* First check at table level, then examine each column if needed */
2359  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2360  if (aclresult != ACLCHECK_OK)
2361  aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2362  ACLMASK_ANY);
2363 
2364  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2365 }
2366 
2367 /*
2368  * has_any_column_privilege_name_id
2369  * Check user privileges on any column of a table given
2370  * name usename, table oid, and text priv name.
2371  */
2372 Datum
2374 {
2376  Oid tableoid = PG_GETARG_OID(1);
2377  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2378  Oid roleid;
2379  AclMode mode;
2380  AclResult aclresult;
2381  bool is_missing = false;
2382 
2384  mode = convert_column_priv_string(priv_type_text);
2385 
2386  /* First check at table level, then examine each column if needed */
2387  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2388  if (aclresult != ACLCHECK_OK)
2389  {
2390  if (is_missing)
2391  PG_RETURN_NULL();
2392  aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2393  ACLMASK_ANY, &is_missing);
2394  if (is_missing)
2395  PG_RETURN_NULL();
2396  }
2397 
2398  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2399 }
2400 
2401 /*
2402  * has_any_column_privilege_id
2403  * Check user privileges on any column of a table given
2404  * table oid, and text priv name.
2405  * current_user is assumed
2406  */
2407 Datum
2409 {
2410  Oid tableoid = PG_GETARG_OID(0);
2411  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2412  Oid roleid;
2413  AclMode mode;
2414  AclResult aclresult;
2415  bool is_missing = false;
2416 
2417  roleid = GetUserId();
2418  mode = convert_column_priv_string(priv_type_text);
2419 
2420  /* First check at table level, then examine each column if needed */
2421  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2422  if (aclresult != ACLCHECK_OK)
2423  {
2424  if (is_missing)
2425  PG_RETURN_NULL();
2426  aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2427  ACLMASK_ANY, &is_missing);
2428  if (is_missing)
2429  PG_RETURN_NULL();
2430  }
2431 
2432  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2433 }
2434 
2435 /*
2436  * has_any_column_privilege_id_name
2437  * Check user privileges on any column of a table given
2438  * roleid, text tablename, and text priv name.
2439  */
2440 Datum
2442 {
2443  Oid roleid = PG_GETARG_OID(0);
2444  text *tablename = PG_GETARG_TEXT_PP(1);
2445  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2446  Oid tableoid;
2447  AclMode mode;
2448  AclResult aclresult;
2449 
2450  tableoid = convert_table_name(tablename);
2451  mode = convert_column_priv_string(priv_type_text);
2452 
2453  /* First check at table level, then examine each column if needed */
2454  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2455  if (aclresult != ACLCHECK_OK)
2456  aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2457  ACLMASK_ANY);
2458 
2459  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2460 }
2461 
2462 /*
2463  * has_any_column_privilege_id_id
2464  * Check user privileges on any column of a table given
2465  * roleid, table oid, and text priv name.
2466  */
2467 Datum
2469 {
2470  Oid roleid = PG_GETARG_OID(0);
2471  Oid tableoid = PG_GETARG_OID(1);
2472  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2473  AclMode mode;
2474  AclResult aclresult;
2475  bool is_missing = false;
2476 
2477  mode = convert_column_priv_string(priv_type_text);
2478 
2479  /* First check at table level, then examine each column if needed */
2480  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2481  if (aclresult != ACLCHECK_OK)
2482  {
2483  if (is_missing)
2484  PG_RETURN_NULL();
2485  aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2486  ACLMASK_ANY, &is_missing);
2487  if (is_missing)
2488  PG_RETURN_NULL();
2489  }
2490 
2491  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2492 }
2493 
2494 
2495 /*
2496  * has_column_privilege variants
2497  * These are all named "has_column_privilege" at the SQL level.
2498  * They take various combinations of relation name, relation OID,
2499  * column name, column attnum, user name, user OID, or
2500  * implicit user = current_user.
2501  *
2502  * The result is a boolean value: true if user has the indicated
2503  * privilege, false if not. The variants that take a relation OID
2504  * return NULL (rather than throwing an error) if that relation OID
2505  * doesn't exist. Likewise, the variants that take an integer attnum
2506  * return NULL (rather than throwing an error) if there is no such
2507  * pg_attribute entry. All variants return NULL if an attisdropped
2508  * column is selected. These rules are meant to avoid unnecessary
2509  * failures in queries that scan pg_attribute.
2510  */
2511 
2512 /*
2513  * column_privilege_check: check column privileges, but don't throw an error
2514  * for dropped column or table
2515  *
2516  * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
2517  */
2518 static int
2520  Oid roleid, AclMode mode)
2521 {
2522  AclResult aclresult;
2523  bool is_missing = false;
2524 
2525  /*
2526  * If convert_column_name failed, we can just return -1 immediately.
2527  */
2528  if (attnum == InvalidAttrNumber)
2529  return -1;
2530 
2531  /*
2532  * Check for column-level privileges first. This serves in part as a check
2533  * on whether the column even exists, so we need to do it before checking
2534  * table-level privilege.
2535  */
2536  aclresult = pg_attribute_aclcheck_ext(tableoid, attnum, roleid,
2537  mode, &is_missing);
2538  if (aclresult == ACLCHECK_OK)
2539  return 1;
2540  else if (is_missing)
2541  return -1;
2542 
2543  /* Next check if we have the privilege at the table level */
2544  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2545  if (aclresult == ACLCHECK_OK)
2546  return 1;
2547  else if (is_missing)
2548  return -1;
2549  else
2550  return 0;
2551 }
2552 
2553 /*
2554  * has_column_privilege_name_name_name
2555  * Check user privileges on a column given
2556  * name username, text tablename, text colname, and text priv name.
2557  */
2558 Datum
2560 {
2561  Name rolename = PG_GETARG_NAME(0);
2562  text *tablename = PG_GETARG_TEXT_PP(1);
2563  text *column = PG_GETARG_TEXT_PP(2);
2564  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2565  Oid roleid;
2566  Oid tableoid;
2567  AttrNumber colattnum;
2568  AclMode mode;
2569  int privresult;
2570 
2571  roleid = get_role_oid_or_public(NameStr(*rolename));
2572  tableoid = convert_table_name(tablename);
2573  colattnum = convert_column_name(tableoid, column);
2574  mode = convert_column_priv_string(priv_type_text);
2575 
2576  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2577  if (privresult < 0)
2578  PG_RETURN_NULL();
2579  PG_RETURN_BOOL(privresult);
2580 }
2581 
2582 /*
2583  * has_column_privilege_name_name_attnum
2584  * Check user privileges on a column given
2585  * name username, text tablename, int attnum, and text priv name.
2586  */
2587 Datum
2589 {
2590  Name rolename = PG_GETARG_NAME(0);
2591  text *tablename = PG_GETARG_TEXT_PP(1);
2592  AttrNumber colattnum = PG_GETARG_INT16(2);
2593  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2594  Oid roleid;
2595  Oid tableoid;
2596  AclMode mode;
2597  int privresult;
2598 
2599  roleid = get_role_oid_or_public(NameStr(*rolename));
2600  tableoid = convert_table_name(tablename);
2601  mode = convert_column_priv_string(priv_type_text);
2602 
2603  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2604  if (privresult < 0)
2605  PG_RETURN_NULL();
2606  PG_RETURN_BOOL(privresult);
2607 }
2608 
2609 /*
2610  * has_column_privilege_name_id_name
2611  * Check user privileges on a column given
2612  * name username, table oid, text colname, and text priv name.
2613  */
2614 Datum
2616 {
2618  Oid tableoid = PG_GETARG_OID(1);
2619  text *column = PG_GETARG_TEXT_PP(2);
2620  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2621  Oid roleid;
2622  AttrNumber colattnum;
2623  AclMode mode;
2624  int privresult;
2625 
2627  colattnum = convert_column_name(tableoid, column);
2628  mode = convert_column_priv_string(priv_type_text);
2629 
2630  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2631  if (privresult < 0)
2632  PG_RETURN_NULL();
2633  PG_RETURN_BOOL(privresult);
2634 }
2635 
2636 /*
2637  * has_column_privilege_name_id_attnum
2638  * Check user privileges on a column given
2639  * name username, table oid, int attnum, and text priv name.
2640  */
2641 Datum
2643 {
2645  Oid tableoid = PG_GETARG_OID(1);
2646  AttrNumber colattnum = PG_GETARG_INT16(2);
2647  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2648  Oid roleid;
2649  AclMode mode;
2650  int privresult;
2651 
2653  mode = convert_column_priv_string(priv_type_text);
2654 
2655  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2656  if (privresult < 0)
2657  PG_RETURN_NULL();
2658  PG_RETURN_BOOL(privresult);
2659 }
2660 
2661 /*
2662  * has_column_privilege_id_name_name
2663  * Check user privileges on a column given
2664  * oid roleid, text tablename, text colname, and text priv name.
2665  */
2666 Datum
2668 {
2669  Oid roleid = PG_GETARG_OID(0);
2670  text *tablename = PG_GETARG_TEXT_PP(1);
2671  text *column = PG_GETARG_TEXT_PP(2);
2672  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2673  Oid tableoid;
2674  AttrNumber colattnum;
2675  AclMode mode;
2676  int privresult;
2677 
2678  tableoid = convert_table_name(tablename);
2679  colattnum = convert_column_name(tableoid, column);
2680  mode = convert_column_priv_string(priv_type_text);
2681 
2682  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2683  if (privresult < 0)
2684  PG_RETURN_NULL();
2685  PG_RETURN_BOOL(privresult);
2686 }
2687 
2688 /*
2689  * has_column_privilege_id_name_attnum
2690  * Check user privileges on a column given
2691  * oid roleid, text tablename, int attnum, and text priv name.
2692  */
2693 Datum
2695 {
2696  Oid roleid = PG_GETARG_OID(0);
2697  text *tablename = PG_GETARG_TEXT_PP(1);
2698  AttrNumber colattnum = PG_GETARG_INT16(2);
2699  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2700  Oid tableoid;
2701  AclMode mode;
2702  int privresult;
2703 
2704  tableoid = convert_table_name(tablename);
2705  mode = convert_column_priv_string(priv_type_text);
2706 
2707  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2708  if (privresult < 0)
2709  PG_RETURN_NULL();
2710  PG_RETURN_BOOL(privresult);
2711 }
2712 
2713 /*
2714  * has_column_privilege_id_id_name
2715  * Check user privileges on a column given
2716  * oid roleid, table oid, text colname, and text priv name.
2717  */
2718 Datum
2720 {
2721  Oid roleid = PG_GETARG_OID(0);
2722  Oid tableoid = PG_GETARG_OID(1);
2723  text *column = PG_GETARG_TEXT_PP(2);
2724  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2725  AttrNumber colattnum;
2726  AclMode mode;
2727  int privresult;
2728 
2729  colattnum = convert_column_name(tableoid, column);
2730  mode = convert_column_priv_string(priv_type_text);
2731 
2732  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2733  if (privresult < 0)
2734  PG_RETURN_NULL();
2735  PG_RETURN_BOOL(privresult);
2736 }
2737 
2738 /*
2739  * has_column_privilege_id_id_attnum
2740  * Check user privileges on a column given
2741  * oid roleid, table oid, int attnum, and text priv name.
2742  */
2743 Datum
2745 {
2746  Oid roleid = PG_GETARG_OID(0);
2747  Oid tableoid = PG_GETARG_OID(1);
2748  AttrNumber colattnum = PG_GETARG_INT16(2);
2749  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2750  AclMode mode;
2751  int privresult;
2752 
2753  mode = convert_column_priv_string(priv_type_text);
2754 
2755  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2756  if (privresult < 0)
2757  PG_RETURN_NULL();
2758  PG_RETURN_BOOL(privresult);
2759 }
2760 
2761 /*
2762  * has_column_privilege_name_name
2763  * Check user privileges on a column given
2764  * text tablename, text colname, and text priv name.
2765  * current_user is assumed
2766  */
2767 Datum
2769 {
2770  text *tablename = PG_GETARG_TEXT_PP(0);
2771  text *column = PG_GETARG_TEXT_PP(1);
2772  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2773  Oid roleid;
2774  Oid tableoid;
2775  AttrNumber colattnum;
2776  AclMode mode;
2777  int privresult;
2778 
2779  roleid = GetUserId();
2780  tableoid = convert_table_name(tablename);
2781  colattnum = convert_column_name(tableoid, column);
2782  mode = convert_column_priv_string(priv_type_text);
2783 
2784  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2785  if (privresult < 0)
2786  PG_RETURN_NULL();
2787  PG_RETURN_BOOL(privresult);
2788 }
2789 
2790 /*
2791  * has_column_privilege_name_attnum
2792  * Check user privileges on a column given
2793  * text tablename, int attnum, and text priv name.
2794  * current_user is assumed
2795  */
2796 Datum
2798 {
2799  text *tablename = PG_GETARG_TEXT_PP(0);
2800  AttrNumber colattnum = PG_GETARG_INT16(1);
2801  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2802  Oid roleid;
2803  Oid tableoid;
2804  AclMode mode;
2805  int privresult;
2806 
2807  roleid = GetUserId();
2808  tableoid = convert_table_name(tablename);
2809  mode = convert_column_priv_string(priv_type_text);
2810 
2811  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2812  if (privresult < 0)
2813  PG_RETURN_NULL();
2814  PG_RETURN_BOOL(privresult);
2815 }
2816 
2817 /*
2818  * has_column_privilege_id_name
2819  * Check user privileges on a column given
2820  * table oid, text colname, and text priv name.
2821  * current_user is assumed
2822  */
2823 Datum
2825 {
2826  Oid tableoid = PG_GETARG_OID(0);
2827  text *column = PG_GETARG_TEXT_PP(1);
2828  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2829  Oid roleid;
2830  AttrNumber colattnum;
2831  AclMode mode;
2832  int privresult;
2833 
2834  roleid = GetUserId();
2835  colattnum = convert_column_name(tableoid, column);
2836  mode = convert_column_priv_string(priv_type_text);
2837 
2838  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2839  if (privresult < 0)
2840  PG_RETURN_NULL();
2841  PG_RETURN_BOOL(privresult);
2842 }
2843 
2844 /*
2845  * has_column_privilege_id_attnum
2846  * Check user privileges on a column given
2847  * table oid, int attnum, and text priv name.
2848  * current_user is assumed
2849  */
2850 Datum
2852 {
2853  Oid tableoid = PG_GETARG_OID(0);
2854  AttrNumber colattnum = PG_GETARG_INT16(1);
2855  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2856  Oid roleid;
2857  AclMode mode;
2858  int privresult;
2859 
2860  roleid = GetUserId();
2861  mode = convert_column_priv_string(priv_type_text);
2862 
2863  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2864  if (privresult < 0)
2865  PG_RETURN_NULL();
2866  PG_RETURN_BOOL(privresult);
2867 }
2868 
2869 /*
2870  * Support routines for has_column_privilege family.
2871  */
2872 
2873 /*
2874  * Given a table OID and a column name expressed as a string, look it up
2875  * and return the column number. Returns InvalidAttrNumber in cases
2876  * where caller should return NULL instead of failing.
2877  */
2878 static AttrNumber
2879 convert_column_name(Oid tableoid, text *column)
2880 {
2881  char *colname;
2882  HeapTuple attTuple;
2884 
2885  colname = text_to_cstring(column);
2886 
2887  /*
2888  * We don't use get_attnum() here because it will report that dropped
2889  * columns don't exist. We need to treat dropped columns differently from
2890  * nonexistent columns.
2891  */
2892  attTuple = SearchSysCache2(ATTNAME,
2893  ObjectIdGetDatum(tableoid),
2894  CStringGetDatum(colname));
2895  if (HeapTupleIsValid(attTuple))
2896  {
2897  Form_pg_attribute attributeForm;
2898 
2899  attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
2900  /* We want to return NULL for dropped columns */
2901  if (attributeForm->attisdropped)
2903  else
2904  attnum = attributeForm->attnum;
2905  ReleaseSysCache(attTuple);
2906  }
2907  else
2908  {
2909  char *tablename = get_rel_name(tableoid);
2910 
2911  /*
2912  * If the table OID is bogus, or it's just been dropped, we'll get
2913  * NULL back. In such cases we want has_column_privilege to return
2914  * NULL too, so just return InvalidAttrNumber.
2915  */
2916  if (tablename != NULL)
2917  {
2918  /* tableoid exists, colname does not, so throw error */
2919  ereport(ERROR,
2920  (errcode(ERRCODE_UNDEFINED_COLUMN),
2921  errmsg("column \"%s\" of relation \"%s\" does not exist",
2922  colname, tablename)));
2923  }
2924  /* tableoid doesn't exist, so act like attisdropped case */
2926  }
2927 
2928  pfree(colname);
2929  return attnum;
2930 }
2931 
2932 /*
2933  * convert_column_priv_string
2934  * Convert text string to AclMode value.
2935  */
2936 static AclMode
2938 {
2939  static const priv_map column_priv_map[] = {
2940  {"SELECT", ACL_SELECT},
2941  {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2942  {"INSERT", ACL_INSERT},
2943  {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2944  {"UPDATE", ACL_UPDATE},
2945  {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2946  {"REFERENCES", ACL_REFERENCES},
2947  {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2948  {NULL, 0}
2949  };
2950 
2951  return convert_any_priv_string(priv_type_text, column_priv_map);
2952 }
2953 
2954 
2955 /*
2956  * has_database_privilege variants
2957  * These are all named "has_database_privilege" at the SQL level.
2958  * They take various combinations of database name, database OID,
2959  * user name, user OID, or implicit user = current_user.
2960  *
2961  * The result is a boolean value: true if user has the indicated
2962  * privilege, false if not, or NULL if object doesn't exist.
2963  */
2964 
2965 /*
2966  * has_database_privilege_name_name
2967  * Check user privileges on a database given
2968  * name username, text databasename, and text priv name.
2969  */
2970 Datum
2972 {
2974  text *databasename = PG_GETARG_TEXT_PP(1);
2975  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2976  Oid roleid;
2977  Oid databaseoid;
2978  AclMode mode;
2979  AclResult aclresult;
2980 
2982  databaseoid = convert_database_name(databasename);
2983  mode = convert_database_priv_string(priv_type_text);
2984 
2985  aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
2986 
2987  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2988 }
2989 
2990 /*
2991  * has_database_privilege_name
2992  * Check user privileges on a database given
2993  * text databasename and text priv name.
2994  * current_user is assumed
2995  */
2996 Datum
2998 {
2999  text *databasename = PG_GETARG_TEXT_PP(0);
3000  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3001  Oid roleid;
3002  Oid databaseoid;
3003  AclMode mode;
3004  AclResult aclresult;
3005 
3006  roleid = GetUserId();
3007  databaseoid = convert_database_name(databasename);
3008  mode = convert_database_priv_string(priv_type_text);
3009 
3010  aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3011 
3012  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3013 }
3014 
3015 /*
3016  * has_database_privilege_name_id
3017  * Check user privileges on a database given
3018  * name usename, database oid, and text priv name.
3019  */
3020 Datum
3022 {
3024  Oid databaseoid = PG_GETARG_OID(1);
3025  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3026  Oid roleid;
3027  AclMode mode;
3028  AclResult aclresult;
3029  bool is_missing = false;
3030 
3032  mode = convert_database_priv_string(priv_type_text);
3033 
3034  aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3035  roleid, mode,
3036  &is_missing);
3037 
3038  if (is_missing)
3039  PG_RETURN_NULL();
3040 
3041  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3042 }
3043 
3044 /*
3045  * has_database_privilege_id
3046  * Check user privileges on a database given
3047  * database oid, and text priv name.
3048  * current_user is assumed
3049  */
3050 Datum
3052 {
3053  Oid databaseoid = PG_GETARG_OID(0);
3054  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3055  Oid roleid;
3056  AclMode mode;
3057  AclResult aclresult;
3058  bool is_missing = false;
3059 
3060  roleid = GetUserId();
3061  mode = convert_database_priv_string(priv_type_text);
3062 
3063  aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3064  roleid, mode,
3065  &is_missing);
3066 
3067  if (is_missing)
3068  PG_RETURN_NULL();
3069 
3070  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3071 }
3072 
3073 /*
3074  * has_database_privilege_id_name
3075  * Check user privileges on a database given
3076  * roleid, text databasename, and text priv name.
3077  */
3078 Datum
3080 {
3081  Oid roleid = PG_GETARG_OID(0);
3082  text *databasename = PG_GETARG_TEXT_PP(1);
3083  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3084  Oid databaseoid;
3085  AclMode mode;
3086  AclResult aclresult;
3087 
3088  databaseoid = convert_database_name(databasename);
3089  mode = convert_database_priv_string(priv_type_text);
3090 
3091  aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3092 
3093  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3094 }
3095 
3096 /*
3097  * has_database_privilege_id_id
3098  * Check user privileges on a database given
3099  * roleid, database oid, and text priv name.
3100  */
3101 Datum
3103 {
3104  Oid roleid = PG_GETARG_OID(0);
3105  Oid databaseoid = PG_GETARG_OID(1);
3106  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3107  AclMode mode;
3108  AclResult aclresult;
3109  bool is_missing = false;
3110 
3111  mode = convert_database_priv_string(priv_type_text);
3112 
3113  aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3114  roleid, mode,
3115  &is_missing);
3116 
3117  if (is_missing)
3118  PG_RETURN_NULL();
3119 
3120  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3121 }
3122 
3123 /*
3124  * Support routines for has_database_privilege family.
3125  */
3126 
3127 /*
3128  * Given a database name expressed as a string, look it up and return Oid
3129  */
3130 static Oid
3132 {
3133  char *dbname = text_to_cstring(databasename);
3134 
3135  return get_database_oid(dbname, false);
3136 }
3137 
3138 /*
3139  * convert_database_priv_string
3140  * Convert text string to AclMode value.
3141  */
3142 static AclMode
3144 {
3145  static const priv_map database_priv_map[] = {
3146  {"CREATE", ACL_CREATE},
3147  {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
3148  {"TEMPORARY", ACL_CREATE_TEMP},
3149  {"TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
3150  {"TEMP", ACL_CREATE_TEMP},
3151  {"TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
3152  {"CONNECT", ACL_CONNECT},
3153  {"CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT)},
3154  {NULL, 0}
3155  };
3156 
3157  return convert_any_priv_string(priv_type_text, database_priv_map);
3158 }
3159 
3160 
3161 /*
3162  * has_foreign_data_wrapper_privilege variants
3163  * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
3164  * They take various combinations of foreign-data wrapper name,
3165  * fdw OID, user name, user OID, or implicit user = current_user.
3166  *
3167  * The result is a boolean value: true if user has the indicated
3168  * privilege, false if not.
3169  */
3170 
3171 /*
3172  * has_foreign_data_wrapper_privilege_name_name
3173  * Check user privileges on a foreign-data wrapper given
3174  * name username, text fdwname, and text priv name.
3175  */
3176 Datum
3178 {
3180  text *fdwname = PG_GETARG_TEXT_PP(1);
3181  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3182  Oid roleid;
3183  Oid fdwid;
3184  AclMode mode;
3185  AclResult aclresult;
3186 
3188  fdwid = convert_foreign_data_wrapper_name(fdwname);
3190 
3191  aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3192 
3193  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3194 }
3195 
3196 /*
3197  * has_foreign_data_wrapper_privilege_name
3198  * Check user privileges on a foreign-data wrapper given
3199  * text fdwname and text priv name.
3200  * current_user is assumed
3201  */
3202 Datum
3204 {
3205  text *fdwname = PG_GETARG_TEXT_PP(0);
3206  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3207  Oid roleid;
3208  Oid fdwid;
3209  AclMode mode;
3210  AclResult aclresult;
3211 
3212  roleid = GetUserId();
3213  fdwid = convert_foreign_data_wrapper_name(fdwname);
3215 
3216  aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3217 
3218  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3219 }
3220 
3221 /*
3222  * has_foreign_data_wrapper_privilege_name_id
3223  * Check user privileges on a foreign-data wrapper given
3224  * name usename, foreign-data wrapper oid, and text priv name.
3225  */
3226 Datum
3228 {
3230  Oid fdwid = PG_GETARG_OID(1);
3231  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3232  Oid roleid;
3233  AclMode mode;
3234  AclResult aclresult;
3235  bool is_missing = false;
3236 
3239 
3240  aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3241  roleid, mode,
3242  &is_missing);
3243 
3244  if (is_missing)
3245  PG_RETURN_NULL();
3246 
3247  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3248 }
3249 
3250 /*
3251  * has_foreign_data_wrapper_privilege_id
3252  * Check user privileges on a foreign-data wrapper given
3253  * foreign-data wrapper oid, and text priv name.
3254  * current_user is assumed
3255  */
3256 Datum
3258 {
3259  Oid fdwid = PG_GETARG_OID(0);
3260  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3261  Oid roleid;
3262  AclMode mode;
3263  AclResult aclresult;
3264  bool is_missing = false;
3265 
3266  roleid = GetUserId();
3268 
3269  aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3270  roleid, mode,
3271  &is_missing);
3272 
3273  if (is_missing)
3274  PG_RETURN_NULL();
3275 
3276  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3277 }
3278 
3279 /*
3280  * has_foreign_data_wrapper_privilege_id_name
3281  * Check user privileges on a foreign-data wrapper given
3282  * roleid, text fdwname, and text priv name.
3283  */
3284 Datum
3286 {
3287  Oid roleid = PG_GETARG_OID(0);
3288  text *fdwname = PG_GETARG_TEXT_PP(1);
3289  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3290  Oid fdwid;
3291  AclMode mode;
3292  AclResult aclresult;
3293 
3294  fdwid = convert_foreign_data_wrapper_name(fdwname);
3296 
3297  aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3298 
3299  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3300 }
3301 
3302 /*
3303  * has_foreign_data_wrapper_privilege_id_id
3304  * Check user privileges on a foreign-data wrapper given
3305  * roleid, fdw oid, and text priv name.
3306  */
3307 Datum
3309 {
3310  Oid roleid = PG_GETARG_OID(0);
3311  Oid fdwid = PG_GETARG_OID(1);
3312  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3313  AclMode mode;
3314  AclResult aclresult;
3315  bool is_missing = false;
3316 
3318 
3319  aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3320  roleid, mode,
3321  &is_missing);
3322 
3323  if (is_missing)
3324  PG_RETURN_NULL();
3325 
3326  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3327 }
3328 
3329 /*
3330  * Support routines for has_foreign_data_wrapper_privilege family.
3331  */
3332 
3333 /*
3334  * Given a FDW name expressed as a string, look it up and return Oid
3335  */
3336 static Oid
3338 {
3339  char *fdwstr = text_to_cstring(fdwname);
3340 
3341  return get_foreign_data_wrapper_oid(fdwstr, false);
3342 }
3343 
3344 /*
3345  * convert_foreign_data_wrapper_priv_string
3346  * Convert text string to AclMode value.
3347  */
3348 static AclMode
3350 {
3351  static const priv_map foreign_data_wrapper_priv_map[] = {
3352  {"USAGE", ACL_USAGE},
3353  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3354  {NULL, 0}
3355  };
3356 
3357  return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
3358 }
3359 
3360 
3361 /*
3362  * has_function_privilege variants
3363  * These are all named "has_function_privilege" at the SQL level.
3364  * They take various combinations of function name, function OID,
3365  * user name, user OID, or implicit user = current_user.
3366  *
3367  * The result is a boolean value: true if user has the indicated
3368  * privilege, false if not, or NULL if object doesn't exist.
3369  */
3370 
3371 /*
3372  * has_function_privilege_name_name
3373  * Check user privileges on a function given
3374  * name username, text functionname, and text priv name.
3375  */
3376 Datum
3378 {
3380  text *functionname = PG_GETARG_TEXT_PP(1);
3381  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3382  Oid roleid;
3383  Oid functionoid;
3384  AclMode mode;
3385  AclResult aclresult;
3386 
3388  functionoid = convert_function_name(functionname);
3389  mode = convert_function_priv_string(priv_type_text);
3390 
3391  aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3392 
3393  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3394 }
3395 
3396 /*
3397  * has_function_privilege_name
3398  * Check user privileges on a function given
3399  * text functionname and text priv name.
3400  * current_user is assumed
3401  */
3402 Datum
3404 {
3405  text *functionname = PG_GETARG_TEXT_PP(0);
3406  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3407  Oid roleid;
3408  Oid functionoid;
3409  AclMode mode;
3410  AclResult aclresult;
3411 
3412  roleid = GetUserId();
3413  functionoid = convert_function_name(functionname);
3414  mode = convert_function_priv_string(priv_type_text);
3415 
3416  aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3417 
3418  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3419 }
3420 
3421 /*
3422  * has_function_privilege_name_id
3423  * Check user privileges on a function given
3424  * name usename, function oid, and text priv name.
3425  */
3426 Datum
3428 {
3430  Oid functionoid = PG_GETARG_OID(1);
3431  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3432  Oid roleid;
3433  AclMode mode;
3434  AclResult aclresult;
3435  bool is_missing = false;
3436 
3438  mode = convert_function_priv_string(priv_type_text);
3439 
3440  aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3441  roleid, mode,
3442  &is_missing);
3443 
3444  if (is_missing)
3445  PG_RETURN_NULL();
3446 
3447  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3448 }
3449 
3450 /*
3451  * has_function_privilege_id
3452  * Check user privileges on a function given
3453  * function oid, and text priv name.
3454  * current_user is assumed
3455  */
3456 Datum
3458 {
3459  Oid functionoid = PG_GETARG_OID(0);
3460  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3461  Oid roleid;
3462  AclMode mode;
3463  AclResult aclresult;
3464  bool is_missing = false;
3465 
3466  roleid = GetUserId();
3467  mode = convert_function_priv_string(priv_type_text);
3468 
3469  aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3470  roleid, mode,
3471  &is_missing);
3472 
3473  if (is_missing)
3474  PG_RETURN_NULL();
3475 
3476  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3477 }
3478 
3479 /*
3480  * has_function_privilege_id_name
3481  * Check user privileges on a function given
3482  * roleid, text functionname, and text priv name.
3483  */
3484 Datum
3486 {
3487  Oid roleid = PG_GETARG_OID(0);
3488  text *functionname = PG_GETARG_TEXT_PP(1);
3489  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3490  Oid functionoid;
3491  AclMode mode;
3492  AclResult aclresult;
3493 
3494  functionoid = convert_function_name(functionname);
3495  mode = convert_function_priv_string(priv_type_text);
3496 
3497  aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3498 
3499  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3500 }
3501 
3502 /*
3503  * has_function_privilege_id_id
3504  * Check user privileges on a function given
3505  * roleid, function oid, and text priv name.
3506  */
3507 Datum
3509 {
3510  Oid roleid = PG_GETARG_OID(0);
3511  Oid functionoid = PG_GETARG_OID(1);
3512  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3513  AclMode mode;
3514  AclResult aclresult;
3515  bool is_missing = false;
3516 
3517  mode = convert_function_priv_string(priv_type_text);
3518 
3519  aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3520  roleid, mode,
3521  &is_missing);
3522 
3523  if (is_missing)
3524  PG_RETURN_NULL();
3525 
3526  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3527 }
3528 
3529 /*
3530  * Support routines for has_function_privilege family.
3531  */
3532 
3533 /*
3534  * Given a function name expressed as a string, look it up and return Oid
3535  */
3536 static Oid
3538 {
3539  char *funcname = text_to_cstring(functionname);
3540  Oid oid;
3541 
3544 
3545  if (!OidIsValid(oid))
3546  ereport(ERROR,
3547  (errcode(ERRCODE_UNDEFINED_FUNCTION),
3548  errmsg("function \"%s\" does not exist", funcname)));
3549 
3550  return oid;
3551 }
3552 
3553 /*
3554  * convert_function_priv_string
3555  * Convert text string to AclMode value.
3556  */
3557 static AclMode
3559 {
3560  static const priv_map function_priv_map[] = {
3561  {"EXECUTE", ACL_EXECUTE},
3562  {"EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE)},
3563  {NULL, 0}
3564  };
3565 
3566  return convert_any_priv_string(priv_type_text, function_priv_map);
3567 }
3568 
3569 
3570 /*
3571  * has_language_privilege variants
3572  * These are all named "has_language_privilege" at the SQL level.
3573  * They take various combinations of language name, language OID,
3574  * user name, user OID, or implicit user = current_user.
3575  *
3576  * The result is a boolean value: true if user has the indicated
3577  * privilege, false if not, or NULL if object doesn't exist.
3578  */
3579 
3580 /*
3581  * has_language_privilege_name_name
3582  * Check user privileges on a language given
3583  * name username, text languagename, and text priv name.
3584  */
3585 Datum
3587 {
3589  text *languagename = PG_GETARG_TEXT_PP(1);
3590  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3591  Oid roleid;
3592  Oid languageoid;
3593  AclMode mode;
3594  AclResult aclresult;
3595 
3597  languageoid = convert_language_name(languagename);
3598  mode = convert_language_priv_string(priv_type_text);
3599 
3600  aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3601 
3602  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3603 }
3604 
3605 /*
3606  * has_language_privilege_name
3607  * Check user privileges on a language given
3608  * text languagename and text priv name.
3609  * current_user is assumed
3610  */
3611 Datum
3613 {
3614  text *languagename = PG_GETARG_TEXT_PP(0);
3615  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3616  Oid roleid;
3617  Oid languageoid;
3618  AclMode mode;
3619  AclResult aclresult;
3620 
3621  roleid = GetUserId();
3622  languageoid = convert_language_name(languagename);
3623  mode = convert_language_priv_string(priv_type_text);
3624 
3625  aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3626 
3627  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3628 }
3629 
3630 /*
3631  * has_language_privilege_name_id
3632  * Check user privileges on a language given
3633  * name usename, language oid, and text priv name.
3634  */
3635 Datum
3637 {
3639  Oid languageoid = PG_GETARG_OID(1);
3640  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3641  Oid roleid;
3642  AclMode mode;
3643  AclResult aclresult;
3644  bool is_missing = false;
3645 
3647  mode = convert_language_priv_string(priv_type_text);
3648 
3649  aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3650  roleid, mode,
3651  &is_missing);
3652 
3653  if (is_missing)
3654  PG_RETURN_NULL();
3655 
3656  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3657 }
3658 
3659 /*
3660  * has_language_privilege_id
3661  * Check user privileges on a language given
3662  * language oid, and text priv name.
3663  * current_user is assumed
3664  */
3665 Datum
3667 {
3668  Oid languageoid = PG_GETARG_OID(0);
3669  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3670  Oid roleid;
3671  AclMode mode;
3672  AclResult aclresult;
3673  bool is_missing = false;
3674 
3675  roleid = GetUserId();
3676  mode = convert_language_priv_string(priv_type_text);
3677 
3678  aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3679  roleid, mode,
3680  &is_missing);
3681 
3682  if (is_missing)
3683  PG_RETURN_NULL();
3684 
3685  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3686 }
3687 
3688 /*
3689  * has_language_privilege_id_name
3690  * Check user privileges on a language given
3691  * roleid, text languagename, and text priv name.
3692  */
3693 Datum
3695 {
3696  Oid roleid = PG_GETARG_OID(0);
3697  text *languagename = PG_GETARG_TEXT_PP(1);
3698  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3699  Oid languageoid;
3700  AclMode mode;
3701  AclResult aclresult;
3702 
3703  languageoid = convert_language_name(languagename);
3704  mode = convert_language_priv_string(priv_type_text);
3705 
3706  aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3707 
3708  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3709 }
3710 
3711 /*
3712  * has_language_privilege_id_id
3713  * Check user privileges on a language given
3714  * roleid, language oid, and text priv name.
3715  */
3716 Datum
3718 {
3719  Oid roleid = PG_GETARG_OID(0);
3720  Oid languageoid = PG_GETARG_OID(1);
3721  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3722  AclMode mode;
3723  AclResult aclresult;
3724  bool is_missing = false;
3725 
3726  mode = convert_language_priv_string(priv_type_text);
3727 
3728  aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3729  roleid, mode,
3730  &is_missing);
3731 
3732  if (is_missing)
3733  PG_RETURN_NULL();
3734 
3735  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3736 }
3737 
3738 /*
3739  * Support routines for has_language_privilege family.
3740  */
3741 
3742 /*
3743  * Given a language name expressed as a string, look it up and return Oid
3744  */
3745 static Oid
3747 {
3748  char *langname = text_to_cstring(languagename);
3749 
3750  return get_language_oid(langname, false);
3751 }
3752 
3753 /*
3754  * convert_language_priv_string
3755  * Convert text string to AclMode value.
3756  */
3757 static AclMode
3759 {
3760  static const priv_map language_priv_map[] = {
3761  {"USAGE", ACL_USAGE},
3762  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3763  {NULL, 0}
3764  };
3765 
3766  return convert_any_priv_string(priv_type_text, language_priv_map);
3767 }
3768 
3769 
3770 /*
3771  * has_schema_privilege variants
3772  * These are all named "has_schema_privilege" at the SQL level.
3773  * They take various combinations of schema name, schema OID,
3774  * user name, user OID, or implicit user = current_user.
3775  *
3776  * The result is a boolean value: true if user has the indicated
3777  * privilege, false if not, or NULL if object doesn't exist.
3778  */
3779 
3780 /*
3781  * has_schema_privilege_name_name
3782  * Check user privileges on a schema given
3783  * name username, text schemaname, and text priv name.
3784  */
3785 Datum
3787 {
3789  text *schemaname = PG_GETARG_TEXT_PP(1);
3790  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3791  Oid roleid;
3792  Oid schemaoid;
3793  AclMode mode;
3794  AclResult aclresult;
3795 
3797  schemaoid = convert_schema_name(schemaname);
3798  mode = convert_schema_priv_string(priv_type_text);
3799 
3800  aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3801 
3802  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3803 }
3804 
3805 /*
3806  * has_schema_privilege_name
3807  * Check user privileges on a schema given
3808  * text schemaname and text priv name.
3809  * current_user is assumed
3810  */
3811 Datum
3813 {
3814  text *schemaname = PG_GETARG_TEXT_PP(0);
3815  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3816  Oid roleid;
3817  Oid schemaoid;
3818  AclMode mode;
3819  AclResult aclresult;
3820 
3821  roleid = GetUserId();
3822  schemaoid = convert_schema_name(schemaname);
3823  mode = convert_schema_priv_string(priv_type_text);
3824 
3825  aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3826 
3827  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3828 }
3829 
3830 /*
3831  * has_schema_privilege_name_id
3832  * Check user privileges on a schema given
3833  * name usename, schema oid, and text priv name.
3834  */
3835 Datum
3837 {
3839  Oid schemaoid = PG_GETARG_OID(1);
3840  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3841  Oid roleid;
3842  AclMode mode;
3843  AclResult aclresult;
3844  bool is_missing = false;
3845 
3847  mode = convert_schema_priv_string(priv_type_text);
3848 
3849  aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3850  roleid, mode,
3851  &is_missing);
3852 
3853  if (is_missing)
3854  PG_RETURN_NULL();
3855 
3856  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3857 }
3858 
3859 /*
3860  * has_schema_privilege_id
3861  * Check user privileges on a schema given
3862  * schema oid, and text priv name.
3863  * current_user is assumed
3864  */
3865 Datum
3867 {
3868  Oid schemaoid = PG_GETARG_OID(0);
3869  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3870  Oid roleid;
3871  AclMode mode;
3872  AclResult aclresult;
3873  bool is_missing = false;
3874 
3875  roleid = GetUserId();
3876  mode = convert_schema_priv_string(priv_type_text);
3877 
3878  aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3879  roleid, mode,
3880  &is_missing);
3881 
3882  if (is_missing)
3883  PG_RETURN_NULL();
3884 
3885  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3886 }
3887 
3888 /*
3889  * has_schema_privilege_id_name
3890  * Check user privileges on a schema given
3891  * roleid, text schemaname, and text priv name.
3892  */
3893 Datum
3895 {
3896  Oid roleid = PG_GETARG_OID(0);
3897  text *schemaname = PG_GETARG_TEXT_PP(1);
3898  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3899  Oid schemaoid;
3900  AclMode mode;
3901  AclResult aclresult;
3902 
3903  schemaoid = convert_schema_name(schemaname);
3904  mode = convert_schema_priv_string(priv_type_text);
3905 
3906  aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3907 
3908  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3909 }
3910 
3911 /*
3912  * has_schema_privilege_id_id
3913  * Check user privileges on a schema given
3914  * roleid, schema oid, and text priv name.
3915  */
3916 Datum
3918 {
3919  Oid roleid = PG_GETARG_OID(0);
3920  Oid schemaoid = PG_GETARG_OID(1);
3921  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3922  AclMode mode;
3923  AclResult aclresult;
3924  bool is_missing = false;
3925 
3926  mode = convert_schema_priv_string(priv_type_text);
3927 
3928  aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3929  roleid, mode,
3930  &is_missing);
3931 
3932  if (is_missing)
3933  PG_RETURN_NULL();
3934 
3935  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3936 }
3937 
3938 /*
3939  * Support routines for has_schema_privilege family.
3940  */
3941 
3942 /*
3943  * Given a schema name expressed as a string, look it up and return Oid
3944  */
3945 static Oid
3947 {
3948  char *nspname = text_to_cstring(schemaname);
3949 
3950  return get_namespace_oid(nspname, false);
3951 }
3952 
3953 /*
3954  * convert_schema_priv_string
3955  * Convert text string to AclMode value.
3956  */
3957 static AclMode
3959 {
3960  static const priv_map schema_priv_map[] = {
3961  {"CREATE", ACL_CREATE},
3962  {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
3963  {"USAGE", ACL_USAGE},
3964  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3965  {NULL, 0}
3966  };
3967 
3968  return convert_any_priv_string(priv_type_text, schema_priv_map);
3969 }
3970 
3971 
3972 /*
3973  * has_server_privilege variants
3974  * These are all named "has_server_privilege" at the SQL level.
3975  * They take various combinations of foreign server name,
3976  * server OID, user name, user OID, or implicit user = current_user.
3977  *
3978  * The result is a boolean value: true if user has the indicated
3979  * privilege, false if not.
3980  */
3981 
3982 /*
3983  * has_server_privilege_name_name
3984  * Check user privileges on a foreign server given
3985  * name username, text servername, and text priv name.
3986  */
3987 Datum
3989 {
3991  text *servername = PG_GETARG_TEXT_PP(1);
3992  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3993  Oid roleid;
3994  Oid serverid;
3995  AclMode mode;
3996  AclResult aclresult;
3997 
3999  serverid = convert_server_name(servername);
4000  mode = convert_server_priv_string(priv_type_text);
4001 
4002  aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4003 
4004  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4005 }
4006 
4007 /*
4008  * has_server_privilege_name
4009  * Check user privileges on a foreign server given
4010  * text servername and text priv name.
4011  * current_user is assumed
4012  */
4013 Datum
4015 {
4016  text *servername = PG_GETARG_TEXT_PP(0);
4017  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4018  Oid roleid;
4019  Oid serverid;
4020  AclMode mode;
4021  AclResult aclresult;
4022 
4023  roleid = GetUserId();
4024  serverid = convert_server_name(servername);
4025  mode = convert_server_priv_string(priv_type_text);
4026 
4027  aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4028 
4029  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4030 }
4031 
4032 /*
4033  * has_server_privilege_name_id
4034  * Check user privileges on a foreign server given
4035  * name usename, foreign server oid, and text priv name.
4036  */
4037 Datum
4039 {
4041  Oid serverid = PG_GETARG_OID(1);
4042  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4043  Oid roleid;
4044  AclMode mode;
4045  AclResult aclresult;
4046  bool is_missing = false;
4047 
4049  mode = convert_server_priv_string(priv_type_text);
4050 
4051  aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4052  roleid, mode,
4053  &is_missing);
4054 
4055  if (is_missing)
4056  PG_RETURN_NULL();
4057 
4058  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4059 }
4060 
4061 /*
4062  * has_server_privilege_id
4063  * Check user privileges on a foreign server given
4064  * server oid, and text priv name.
4065  * current_user is assumed
4066  */
4067 Datum
4069 {
4070  Oid serverid = PG_GETARG_OID(0);
4071  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4072  Oid roleid;
4073  AclMode mode;
4074  AclResult aclresult;
4075  bool is_missing = false;
4076 
4077  roleid = GetUserId();
4078  mode = convert_server_priv_string(priv_type_text);
4079 
4080  aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4081  roleid, mode,
4082  &is_missing);
4083 
4084  if (is_missing)
4085  PG_RETURN_NULL();
4086 
4087  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4088 }
4089 
4090 /*
4091  * has_server_privilege_id_name
4092  * Check user privileges on a foreign server given
4093  * roleid, text servername, and text priv name.
4094  */
4095 Datum
4097 {
4098  Oid roleid = PG_GETARG_OID(0);
4099  text *servername = PG_GETARG_TEXT_PP(1);
4100  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4101  Oid serverid;
4102  AclMode mode;
4103  AclResult aclresult;
4104 
4105  serverid = convert_server_name(servername);
4106  mode = convert_server_priv_string(priv_type_text);
4107 
4108  aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4109 
4110  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4111 }
4112 
4113 /*
4114  * has_server_privilege_id_id
4115  * Check user privileges on a foreign server given
4116  * roleid, server oid, and text priv name.
4117  */
4118 Datum
4120 {
4121  Oid roleid = PG_GETARG_OID(0);
4122  Oid serverid = PG_GETARG_OID(1);
4123  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4124  AclMode mode;
4125  AclResult aclresult;
4126  bool is_missing = false;
4127 
4128  mode = convert_server_priv_string(priv_type_text);
4129 
4130  aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4131  roleid, mode,
4132  &is_missing);
4133 
4134  if (is_missing)
4135  PG_RETURN_NULL();
4136 
4137  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4138 }
4139 
4140 /*
4141  * Support routines for has_server_privilege family.
4142  */
4143 
4144 /*
4145  * Given a server name expressed as a string, look it up and return Oid
4146  */
4147 static Oid
4149 {
4150  char *serverstr = text_to_cstring(servername);
4151 
4152  return get_foreign_server_oid(serverstr, false);
4153 }
4154 
4155 /*
4156  * convert_server_priv_string
4157  * Convert text string to AclMode value.
4158  */
4159 static AclMode
4161 {
4162  static const priv_map server_priv_map[] = {
4163  {"USAGE", ACL_USAGE},
4164  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4165  {NULL, 0}
4166  };
4167 
4168  return convert_any_priv_string(priv_type_text, server_priv_map);
4169 }
4170 
4171 
4172 /*
4173  * has_tablespace_privilege variants
4174  * These are all named "has_tablespace_privilege" at the SQL level.
4175  * They take various combinations of tablespace name, tablespace OID,
4176  * user name, user OID, or implicit user = current_user.
4177  *
4178  * The result is a boolean value: true if user has the indicated
4179  * privilege, false if not.
4180  */
4181 
4182 /*
4183  * has_tablespace_privilege_name_name
4184  * Check user privileges on a tablespace given
4185  * name username, text tablespacename, and text priv name.
4186  */
4187 Datum
4189 {
4191  text *tablespacename = PG_GETARG_TEXT_PP(1);
4192  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4193  Oid roleid;
4194  Oid tablespaceoid;
4195  AclMode mode;
4196  AclResult aclresult;
4197 
4199  tablespaceoid = convert_tablespace_name(tablespacename);
4200  mode = convert_tablespace_priv_string(priv_type_text);
4201 
4202  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4203 
4204  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4205 }
4206 
4207 /*
4208  * has_tablespace_privilege_name
4209  * Check user privileges on a tablespace given
4210  * text tablespacename and text priv name.
4211  * current_user is assumed
4212  */
4213 Datum
4215 {
4216  text *tablespacename = PG_GETARG_TEXT_PP(0);
4217  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4218  Oid roleid;
4219  Oid tablespaceoid;
4220  AclMode mode;
4221  AclResult aclresult;
4222 
4223  roleid = GetUserId();
4224  tablespaceoid = convert_tablespace_name(tablespacename);
4225  mode = convert_tablespace_priv_string(priv_type_text);
4226 
4227  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4228 
4229  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4230 }
4231 
4232 /*
4233  * has_tablespace_privilege_name_id
4234  * Check user privileges on a tablespace given
4235  * name usename, tablespace oid, and text priv name.
4236  */
4237 Datum
4239 {
4241  Oid tablespaceoid = PG_GETARG_OID(1);
4242  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4243  Oid roleid;
4244  AclMode mode;
4245  AclResult aclresult;
4246  bool is_missing = false;
4247 
4249  mode = convert_tablespace_priv_string(priv_type_text);
4250 
4251  aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4252  roleid, mode,
4253  &is_missing);
4254 
4255  if (is_missing)
4256  PG_RETURN_NULL();
4257 
4258  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4259 }
4260 
4261 /*
4262  * has_tablespace_privilege_id
4263  * Check user privileges on a tablespace given
4264  * tablespace oid, and text priv name.
4265  * current_user is assumed
4266  */
4267 Datum
4269 {
4270  Oid tablespaceoid = PG_GETARG_OID(0);
4271  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4272  Oid roleid;
4273  AclMode mode;
4274  AclResult aclresult;
4275  bool is_missing = false;
4276 
4277  roleid = GetUserId();
4278  mode = convert_tablespace_priv_string(priv_type_text);
4279 
4280  aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4281  roleid, mode,
4282  &is_missing);
4283 
4284  if (is_missing)
4285  PG_RETURN_NULL();
4286 
4287  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4288 }
4289 
4290 /*
4291  * has_tablespace_privilege_id_name
4292  * Check user privileges on a tablespace given
4293  * roleid, text tablespacename, and text priv name.
4294  */
4295 Datum
4297 {
4298  Oid roleid = PG_GETARG_OID(0);
4299  text *tablespacename = PG_GETARG_TEXT_PP(1);
4300  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4301  Oid tablespaceoid;
4302  AclMode mode;
4303  AclResult aclresult;
4304 
4305  tablespaceoid = convert_tablespace_name(tablespacename);
4306  mode = convert_tablespace_priv_string(priv_type_text);
4307 
4308  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4309 
4310  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4311 }
4312 
4313 /*
4314  * has_tablespace_privilege_id_id
4315  * Check user privileges on a tablespace given
4316  * roleid, tablespace oid, and text priv name.
4317  */
4318 Datum
4320 {
4321  Oid roleid = PG_GETARG_OID(0);
4322  Oid tablespaceoid = PG_GETARG_OID(1);
4323  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4324  AclMode mode;
4325  AclResult aclresult;
4326  bool is_missing = false;
4327 
4328  mode = convert_tablespace_priv_string(priv_type_text);
4329 
4330  aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4331  roleid, mode,
4332  &is_missing);
4333 
4334  if (is_missing)
4335  PG_RETURN_NULL();
4336 
4337  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4338 }
4339 
4340 /*
4341  * Support routines for has_tablespace_privilege family.
4342  */
4343 
4344 /*
4345  * Given a tablespace name expressed as a string, look it up and return Oid
4346  */
4347 static Oid
4349 {
4350  char *spcname = text_to_cstring(tablespacename);
4351 
4352  return get_tablespace_oid(spcname, false);
4353 }
4354 
4355 /*
4356  * convert_tablespace_priv_string
4357  * Convert text string to AclMode value.
4358  */
4359 static AclMode
4361 {
4362  static const priv_map tablespace_priv_map[] = {
4363  {"CREATE", ACL_CREATE},
4364  {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4365  {NULL, 0}
4366  };
4367 
4368  return convert_any_priv_string(priv_type_text, tablespace_priv_map);
4369 }
4370 
4371 /*
4372  * has_type_privilege variants
4373  * These are all named "has_type_privilege" at the SQL level.
4374  * They take various combinations of type name, type OID,
4375  * user name, user OID, or implicit user = current_user.
4376  *
4377  * The result is a boolean value: true if user has the indicated
4378  * privilege, false if not, or NULL if object doesn't exist.
4379  */
4380 
4381 /*
4382  * has_type_privilege_name_name
4383  * Check user privileges on a type given
4384  * name username, text typename, and text priv name.
4385  */
4386 Datum
4388 {
4390  text *typename = PG_GETARG_TEXT_PP(1);
4391  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4392  Oid roleid;
4393  Oid typeoid;
4394  AclMode mode;
4395  AclResult aclresult;
4396 
4398  typeoid = convert_type_name(typename);
4399  mode = convert_type_priv_string(priv_type_text);
4400 
4401  aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4402 
4403  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4404 }
4405 
4406 /*
4407  * has_type_privilege_name
4408  * Check user privileges on a type given
4409  * text typename and text priv name.
4410  * current_user is assumed
4411  */
4412 Datum
4414 {
4415  text *typename = PG_GETARG_TEXT_PP(0);
4416  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4417  Oid roleid;
4418  Oid typeoid;
4419  AclMode mode;
4420  AclResult aclresult;
4421 
4422  roleid = GetUserId();
4423  typeoid = convert_type_name(typename);
4424  mode = convert_type_priv_string(priv_type_text);
4425 
4426  aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4427 
4428  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4429 }
4430 
4431 /*
4432  * has_type_privilege_name_id
4433  * Check user privileges on a type given
4434  * name usename, type oid, and text priv name.
4435  */
4436 Datum
4438 {
4440  Oid typeoid = PG_GETARG_OID(1);
4441  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4442  Oid roleid;
4443  AclMode mode;
4444  AclResult aclresult;
4445  bool is_missing = false;
4446 
4448  mode = convert_type_priv_string(priv_type_text);
4449 
4450  aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4451  roleid, mode,
4452  &is_missing);
4453 
4454  if (is_missing)
4455  PG_RETURN_NULL();
4456 
4457  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4458 }
4459 
4460 /*
4461  * has_type_privilege_id
4462  * Check user privileges on a type given
4463  * type oid, and text priv name.
4464  * current_user is assumed
4465  */
4466 Datum
4468 {
4469  Oid typeoid = PG_GETARG_OID(0);
4470  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4471  Oid roleid;
4472  AclMode mode;
4473  AclResult aclresult;
4474  bool is_missing = false;
4475 
4476  roleid = GetUserId();
4477  mode = convert_type_priv_string(priv_type_text);
4478 
4479  aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4480  roleid, mode,
4481  &is_missing);
4482 
4483  if (is_missing)
4484  PG_RETURN_NULL();
4485 
4486  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4487 }
4488 
4489 /*
4490  * has_type_privilege_id_name
4491  * Check user privileges on a type given
4492  * roleid, text typename, and text priv name.
4493  */
4494 Datum
4496 {
4497  Oid roleid = PG_GETARG_OID(0);
4498  text *typename = PG_GETARG_TEXT_PP(1);
4499  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4500  Oid typeoid;
4501  AclMode mode;
4502  AclResult aclresult;
4503 
4504  typeoid = convert_type_name(typename);
4505  mode = convert_type_priv_string(priv_type_text);
4506 
4507  aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4508 
4509  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4510 }
4511 
4512 /*
4513  * has_type_privilege_id_id
4514  * Check user privileges on a type given
4515  * roleid, type oid, and text priv name.
4516  */
4517 Datum
4519 {
4520  Oid roleid = PG_GETARG_OID(0);
4521  Oid typeoid = PG_GETARG_OID(1);
4522  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4523  AclMode mode;
4524  AclResult aclresult;
4525  bool is_missing = false;
4526 
4527  mode = convert_type_priv_string(priv_type_text);
4528 
4529  aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4530  roleid, mode,
4531  &is_missing);
4532 
4533  if (is_missing)
4534  PG_RETURN_NULL();
4535 
4536  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4537 }
4538 
4539 /*
4540  * Support routines for has_type_privilege family.
4541  */
4542 
4543 /*
4544  * Given a type name expressed as a string, look it up and return Oid
4545  */
4546 static Oid
4548 {
4549  char *typname = text_to_cstring(typename);
4550  Oid oid;
4551 
4554 
4555  if (!OidIsValid(oid))
4556  ereport(ERROR,
4557  (errcode(ERRCODE_UNDEFINED_OBJECT),
4558  errmsg("type \"%s\" does not exist", typname)));
4559 
4560  return oid;
4561 }
4562 
4563 /*
4564  * convert_type_priv_string
4565  * Convert text string to AclMode value.
4566  */
4567 static AclMode
4569 {
4570  static const priv_map type_priv_map[] = {
4571  {"USAGE", ACL_USAGE},
4572  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4573  {NULL, 0}
4574  };
4575 
4576  return convert_any_priv_string(priv_type_text, type_priv_map);
4577 }
4578 
4579 /*
4580  * has_parameter_privilege variants
4581  * These are all named "has_parameter_privilege" at the SQL level.
4582  * They take various combinations of parameter name with
4583  * user name, user OID, or implicit user = current_user.
4584  *
4585  * The result is a boolean value: true if user has been granted
4586  * the indicated privilege or false if not.
4587  */
4588 
4589 /*
4590  * has_param_priv_byname
4591  *
4592  * Helper function to check user privileges on a parameter given the
4593  * role by Oid, parameter by text name, and privileges as AclMode.
4594  */
4595 static bool
4596 has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
4597 {
4598  char *paramstr = text_to_cstring(parameter);
4599 
4600  return pg_parameter_aclcheck(paramstr, roleid, priv) == ACLCHECK_OK;
4601 }
4602 
4603 /*
4604  * has_parameter_privilege_name_name
4605  * Check user privileges on a parameter given name username, text
4606  * parameter, and text priv name.
4607  */
4608 Datum
4610 {
4612  text *parameter = PG_GETARG_TEXT_PP(1);
4615 
4616  PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
4617 }
4618 
4619 /*
4620  * has_parameter_privilege_name
4621  * Check user privileges on a parameter given text parameter and text priv
4622  * name. current_user is assumed
4623  */
4624 Datum
4626 {
4627  text *parameter = PG_GETARG_TEXT_PP(0);
4629 
4630  PG_RETURN_BOOL(has_param_priv_byname(GetUserId(), parameter, priv));
4631 }
4632 
4633 /*
4634  * has_parameter_privilege_id_name
4635  * Check user privileges on a parameter given roleid, text parameter, and
4636  * text priv name.
4637  */
4638 Datum
4640 {
4641  Oid roleid = PG_GETARG_OID(0);
4642  text *parameter = PG_GETARG_TEXT_PP(1);
4644 
4645  PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
4646 }
4647 
4648 /*
4649  * Support routines for has_parameter_privilege family.
4650  */
4651 
4652 /*
4653  * convert_parameter_priv_string
4654  * Convert text string to AclMode value.
4655  */
4656 static AclMode
4658 {
4659  static const priv_map parameter_priv_map[] = {
4660  {"SET", ACL_SET},
4661  {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SET)},
4662  {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
4663  {"ALTER SYSTEM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ALTER_SYSTEM)},
4664  {NULL, 0}
4665  };
4666 
4667  return convert_any_priv_string(priv_text, parameter_priv_map);
4668 }
4669 
4670 /*
4671  * has_largeobject_privilege variants
4672  * These are all named "has_largeobject_privilege" at the SQL level.
4673  * They take various combinations of large object OID with
4674  * user name, user OID, or implicit user = current_user.
4675  *
4676  * The result is a boolean value: true if user has the indicated
4677  * privilege, false if not, or NULL if object doesn't exist.
4678  */
4679 
4680 /*
4681  * has_lo_priv_byid
4682  *
4683  * Helper function to check user privileges on a large object given the
4684  * role by Oid, large object by Oid, and privileges as AclMode.
4685  */
4686 static bool
4687 has_lo_priv_byid(Oid roleid, Oid lobjId, AclMode priv, bool *is_missing)
4688 {
4689  Snapshot snapshot = NULL;
4690  AclResult aclresult;
4691 
4692  if (priv & ACL_UPDATE)
4693  snapshot = NULL;
4694  else
4695  snapshot = GetActiveSnapshot();
4696 
4697  if (!LargeObjectExistsWithSnapshot(lobjId, snapshot))
4698  {
4699  Assert(is_missing != NULL);
4700  *is_missing = true;
4701  return false;
4702  }
4703 
4705  return true;
4706 
4707  aclresult = pg_largeobject_aclcheck_snapshot(lobjId,
4708  roleid,
4709  priv,
4710  snapshot);
4711  return aclresult == ACLCHECK_OK;
4712 }
4713 
4714 /*
4715  * has_largeobject_privilege_name_id
4716  * Check user privileges on a large object given
4717  * name username, large object oid, and text priv name.
4718  */
4719 Datum
4721 {
4724  Oid lobjId = PG_GETARG_OID(1);
4725  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4726  AclMode mode;
4727  bool is_missing = false;
4728  bool result;
4729 
4730  mode = convert_largeobject_priv_string(priv_type_text);
4731  result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4732 
4733  if (is_missing)
4734  PG_RETURN_NULL();
4735 
4736  PG_RETURN_BOOL(result);
4737 }
4738 
4739 /*
4740  * has_largeobject_privilege_id
4741  * Check user privileges on a large object given
4742  * large object oid, and text priv name.
4743  * current_user is assumed
4744  */
4745 Datum
4747 {
4748  Oid lobjId = PG_GETARG_OID(0);
4749  Oid roleid = GetUserId();
4750  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4751  AclMode mode;
4752  bool is_missing = false;
4753  bool result;
4754 
4755  mode = convert_largeobject_priv_string(priv_type_text);
4756  result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4757 
4758  if (is_missing)
4759  PG_RETURN_NULL();
4760 
4761  PG_RETURN_BOOL(result);
4762 }
4763 
4764 /*
4765  * has_largeobject_privilege_id_id
4766  * Check user privileges on a large object given
4767  * roleid, large object oid, and text priv name.
4768  */
4769 Datum
4771 {
4772  Oid roleid = PG_GETARG_OID(0);
4773  Oid lobjId = PG_GETARG_OID(1);
4774  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4775  AclMode mode;
4776  bool is_missing = false;
4777  bool result;
4778 
4779  mode = convert_largeobject_priv_string(priv_type_text);
4780  result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4781 
4782  if (is_missing)
4783  PG_RETURN_NULL();
4784 
4785  PG_RETURN_BOOL(result);
4786 }
4787 
4788 /*
4789  * convert_largeobject_priv_string
4790  * Convert text string to AclMode value.
4791  */
4792 static AclMode
4794 {
4795  static const priv_map largeobject_priv_map[] = {
4796  {"SELECT", ACL_SELECT},
4797  {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
4798  {"UPDATE", ACL_UPDATE},
4799  {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
4800  {NULL, 0}
4801  };
4802 
4803  return convert_any_priv_string(priv_type_text, largeobject_priv_map);
4804 }
4805 
4806 /*
4807  * pg_has_role variants
4808  * These are all named "pg_has_role" at the SQL level.
4809  * They take various combinations of role name, role OID,
4810  * user name, user OID, or implicit user = current_user.
4811  *
4812  * The result is a boolean value: true if user has the indicated
4813  * privilege, false if not.
4814  */
4815 
4816 /*
4817  * pg_has_role_name_name
4818  * Check user privileges on a role given
4819  * name username, name rolename, and text priv name.
4820  */
4821 Datum
4823 {
4825  Name rolename = PG_GETARG_NAME(1);
4826  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4827  Oid roleid;
4828  Oid roleoid;
4829  AclMode mode;
4830  AclResult aclresult;
4831 
4832  roleid = get_role_oid(NameStr(*username), false);
4833  roleoid = get_role_oid(NameStr(*rolename), false);
4834  mode = convert_role_priv_string(priv_type_text);
4835 
4836  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4837 
4838  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4839 }
4840 
4841 /*
4842  * pg_has_role_name
4843  * Check user privileges on a role given
4844  * name rolename and text priv name.
4845  * current_user is assumed
4846  */
4847 Datum
4849 {
4850  Name rolename = PG_GETARG_NAME(0);
4851  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4852  Oid roleid;
4853  Oid roleoid;
4854  AclMode mode;
4855  AclResult aclresult;
4856 
4857  roleid = GetUserId();
4858  roleoid = get_role_oid(NameStr(*rolename), false);
4859  mode = convert_role_priv_string(priv_type_text);
4860 
4861  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4862 
4863  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4864 }
4865 
4866 /*
4867  * pg_has_role_name_id
4868  * Check user privileges on a role given
4869  * name usename, role oid, and text priv name.
4870  */
4871 Datum
4873 {
4875  Oid roleoid = PG_GETARG_OID(1);
4876  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4877  Oid roleid;
4878  AclMode mode;
4879  AclResult aclresult;
4880 
4881  roleid = get_role_oid(NameStr(*username), false);
4882  mode = convert_role_priv_string(priv_type_text);
4883 
4884  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4885 
4886  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4887 }
4888 
4889 /*
4890  * pg_has_role_id
4891  * Check user privileges on a role given
4892  * role oid, and text priv name.
4893  * current_user is assumed
4894  */
4895 Datum
4897 {
4898  Oid roleoid = PG_GETARG_OID(0);
4899  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4900  Oid roleid;
4901  AclMode mode;
4902  AclResult aclresult;
4903 
4904  roleid = GetUserId();
4905  mode = convert_role_priv_string(priv_type_text);
4906 
4907  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4908 
4909  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4910 }
4911 
4912 /*
4913  * pg_has_role_id_name
4914  * Check user privileges on a role given
4915  * roleid, name rolename, and text priv name.
4916  */
4917 Datum
4919 {
4920  Oid roleid = PG_GETARG_OID(0);
4921  Name rolename = PG_GETARG_NAME(1);
4922  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4923  Oid roleoid;
4924  AclMode mode;
4925  AclResult aclresult;
4926 
4927  roleoid = get_role_oid(NameStr(*rolename), false);
4928  mode = convert_role_priv_string(priv_type_text);
4929 
4930  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4931 
4932  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4933 }
4934 
4935 /*
4936  * pg_has_role_id_id
4937  * Check user privileges on a role given
4938  * roleid, role oid, and text priv name.
4939  */
4940 Datum
4942 {
4943  Oid roleid = PG_GETARG_OID(0);
4944  Oid roleoid = PG_GETARG_OID(1);
4945  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4946  AclMode mode;
4947  AclResult aclresult;
4948 
4949  mode = convert_role_priv_string(priv_type_text);
4950 
4951  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4952 
4953  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4954 }
4955 
4956 /*
4957  * Support routines for pg_has_role family.
4958  */
4959 
4960 /*
4961  * convert_role_priv_string
4962  * Convert text string to AclMode value.
4963  *
4964  * We use USAGE to denote whether the privileges of the role are accessible
4965  * (has_privs_of_role), MEMBER to denote is_member, and MEMBER WITH GRANT
4966  * (or ADMIN) OPTION to denote is_admin. There is no ACL bit corresponding
4967  * to MEMBER so we cheat and use ACL_CREATE for that. This convention
4968  * is shared only with pg_role_aclcheck, below.
4969  */
4970 static AclMode
4972 {
4973  static const priv_map role_priv_map[] = {
4974  {"USAGE", ACL_USAGE},
4975  {"MEMBER", ACL_CREATE},
4976  {"SET", ACL_SET},
4977  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4978  {"USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4979  {"MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4980  {"MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4981  {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4982  {"SET WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4983  {NULL, 0}
4984  };
4985 
4986  return convert_any_priv_string(priv_type_text, role_priv_map);
4987 }
4988 
4989 /*
4990  * pg_role_aclcheck
4991  * Quick-and-dirty support for pg_has_role
4992  */
4993 static AclResult
4995 {
4997  {
4998  if (is_admin_of_role(roleid, role_oid))
4999  return ACLCHECK_OK;
5000  }
5001  if (mode & ACL_CREATE)
5002  {
5003  if (is_member_of_role(roleid, role_oid))
5004  return ACLCHECK_OK;
5005  }
5006  if (mode & ACL_USAGE)
5007  {
5008  if (has_privs_of_role(roleid, role_oid))
5009  return ACLCHECK_OK;
5010  }
5011  if (mode & ACL_SET)
5012  {
5013  if (member_can_set_role(roleid, role_oid))
5014  return ACLCHECK_OK;
5015  }
5016  return ACLCHECK_NO_PRIV;
5017 }
5018 
5019 
5020 /*
5021  * initialization function (called by InitPostgres)
5022  */
5023 void
5025 {
5027  {
5028  cached_db_hash =
5029  GetSysCacheHashValue1(DATABASEOID,
5031 
5032  /*
5033  * In normal mode, set a callback on any syscache invalidation of rows
5034  * of pg_auth_members (for roles_is_member_of()) pg_database (for
5035  * roles_is_member_of())
5036  */
5037  CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
5039  (Datum) 0);
5042  (Datum) 0);
5043  CacheRegisterSyscacheCallback(DATABASEOID,
5045  (Datum) 0);
5046  }
5047 }
5048 
5049 /*
5050  * RoleMembershipCacheCallback
5051  * Syscache inval callback function
5052  */
5053 static void
5055 {
5056  if (cacheid == DATABASEOID &&
5057  hashvalue != cached_db_hash &&
5058  hashvalue != 0)
5059  {
5060  return; /* ignore pg_database changes for other DBs */
5061  }
5062 
5063  /* Force membership caches to be recomputed on next use */
5067 }
5068 
5069 /*
5070  * A helper function for roles_is_member_of() that provides an optimized
5071  * implementation of list_append_unique_oid() via a Bloom filter. The caller
5072  * (i.e., roles_is_member_of()) is responsible for freeing bf once it is done
5073  * using this function.
5074  */
5075 static inline List *
5076 roles_list_append(List *roles_list, bloom_filter **bf, Oid role)
5077 {
5078  unsigned char *roleptr = (unsigned char *) &role;
5079 
5080  /*
5081  * If there is a previously-created Bloom filter, use it to try to
5082  * determine whether the role is missing from the list. If it says yes,
5083  * that's a hard fact and we can go ahead and add the role. If it says
5084  * no, that's only probabilistic and we'd better search the list. Without
5085  * a filter, we must always do an ordinary linear search through the
5086  * existing list.
5087  */
5088  if ((*bf && bloom_lacks_element(*bf, roleptr, sizeof(Oid))) ||
5089  !list_member_oid(roles_list, role))
5090  {
5091  /*
5092  * If the list is large, we take on the overhead of creating and
5093  * populating a Bloom filter to speed up future calls to this
5094  * function.
5095  */
5096  if (*bf == NULL &&
5098  {
5100  foreach_oid(roleid, roles_list)
5101  bloom_add_element(*bf, (unsigned char *) &roleid, sizeof(Oid));
5102  }
5103 
5104  /*
5105  * Finally, add the role to the list and the Bloom filter, if it
5106  * exists.
5107  */
5108  roles_list = lappend_oid(roles_list, role);
5109  if (*bf)
5110  bloom_add_element(*bf, roleptr, sizeof(Oid));
5111  }
5112 
5113  return roles_list;
5114 }
5115 
5116 /*
5117  * Get a list of roles that the specified roleid is a member of
5118  *
5119  * Type ROLERECURSE_MEMBERS recurses through all grants; ROLERECURSE_PRIVS
5120  * recurses only through inheritable grants; and ROLERECURSE_SETROLE recurses
5121  * only through grants with set_option.
5122  *
5123  * Since indirect membership testing is relatively expensive, we cache
5124  * a list of memberships. Hence, the result is only guaranteed good until
5125  * the next call of roles_is_member_of()!
5126  *
5127  * For the benefit of select_best_grantor, the result is defined to be
5128  * in breadth-first order, ie, closer relationships earlier.
5129  *
5130  * If admin_of is not InvalidOid, this function sets *admin_role, either
5131  * to the OID of the first role in the result list that directly possesses
5132  * ADMIN OPTION on the role corresponding to admin_of, or to InvalidOid if
5133  * there is no such role.
5134  */
5135 static List *
5137  Oid admin_of, Oid *admin_role)
5138 {
5139  Oid dba;
5140  List *roles_list;
5141  ListCell *l;
5142  List *new_cached_roles;
5143  MemoryContext oldctx;
5144  bloom_filter *bf = NULL;
5145 
5146  Assert(OidIsValid(admin_of) == PointerIsValid(admin_role));
5147  if (admin_role != NULL)
5148  *admin_role = InvalidOid;
5149 
5150  /* If cache is valid and ADMIN OPTION not sought, just return the list */
5151  if (cached_role[type] == roleid && !OidIsValid(admin_of) &&
5153  return cached_roles[type];
5154 
5155  /*
5156  * Role expansion happens in a non-database backend when guc.c checks
5157  * ROLE_PG_READ_ALL_SETTINGS for a physical walsender SHOW command. In
5158  * that case, no role gets pg_database_owner.
5159  */
5160  if (!OidIsValid(MyDatabaseId))
5161  dba = InvalidOid;
5162  else
5163  {
5164  HeapTuple dbtup;
5165 
5166  dbtup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
5167  if (!HeapTupleIsValid(dbtup))
5168  elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
5169  dba = ((Form_pg_database) GETSTRUCT(dbtup))->datdba;
5170  ReleaseSysCache(dbtup);
5171  }
5172 
5173  /*
5174  * Find all the roles that roleid is a member of, including multi-level
5175  * recursion. The role itself will always be the first element of the
5176  * resulting list.
5177  *
5178  * Each element of the list is scanned to see if it adds any indirect
5179  * memberships. We can use a single list as both the record of
5180  * already-found memberships and the agenda of roles yet to be scanned.
5181  * This is a bit tricky but works because the foreach() macro doesn't
5182  * fetch the next list element until the bottom of the loop.
5183  */
5184  roles_list = list_make1_oid(roleid);
5185 
5186  foreach(l, roles_list)
5187  {
5188  Oid memberid = lfirst_oid(l);
5189  CatCList *memlist;
5190  int i;
5191 
5192  /* Find roles that memberid is directly a member of */
5193  memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
5194  ObjectIdGetDatum(memberid));
5195  for (i = 0; i < memlist->n_members; i++)
5196  {
5197  HeapTuple tup = &memlist->members[i]->tuple;
5199  Oid otherid = form->roleid;
5200 
5201  /*
5202  * While otherid==InvalidOid shouldn't appear in the catalog, the
5203  * OidIsValid() avoids crashing if that arises.
5204  */
5205  if (otherid == admin_of && form->admin_option &&
5206  OidIsValid(admin_of) && !OidIsValid(*admin_role))
5207  *admin_role = memberid;
5208 
5209  /* If we're supposed to ignore non-heritable grants, do so. */
5210  if (type == ROLERECURSE_PRIVS && !form->inherit_option)
5211  continue;
5212 
5213  /* If we're supposed to ignore non-SET grants, do so. */
5214  if (type == ROLERECURSE_SETROLE && !form->set_option)
5215  continue;
5216 
5217  /*
5218  * Even though there shouldn't be any loops in the membership
5219  * graph, we must test for having already seen this role. It is
5220  * legal for instance to have both A->B and A->C->B.
5221  */
5222  roles_list = roles_list_append(roles_list, &bf, otherid);
5223  }
5224  ReleaseSysCacheList(memlist);
5225 
5226  /* implement pg_database_owner implicit membership */
5227  if (memberid == dba && OidIsValid(dba))
5228  roles_list = roles_list_append(roles_list, &bf,
5229  ROLE_PG_DATABASE_OWNER);
5230  }
5231 
5232  /*
5233  * Free the Bloom filter created by roles_list_append(), if there is one.
5234  */
5235  if (bf)
5236  bloom_free(bf);
5237 
5238  /*
5239  * Copy the completed list into TopMemoryContext so it will persist.
5240  */
5242  new_cached_roles = list_copy(roles_list);
5243  MemoryContextSwitchTo(oldctx);
5244  list_free(roles_list);
5245 
5246  /*
5247  * Now safe to assign to state variable
5248  */
5249  cached_role[type] = InvalidOid; /* just paranoia */
5251  cached_roles[type] = new_cached_roles;
5252  cached_role[type] = roleid;
5253 
5254  /* And now we can return the answer */
5255  return cached_roles[type];
5256 }
5257 
5258 
5259 /*
5260  * Does member have the privileges of role (directly or indirectly)?
5261  *
5262  * This is defined not to recurse through grants that are not inherited,
5263  * and only inherited grants confer the associated privileges automatically.
5264  *
5265  * See also member_can_set_role, below.
5266  */
5267 bool
5269 {
5270  /* Fast path for simple case */
5271  if (member == role)
5272  return true;
5273 
5274  /* Superusers have every privilege, so are part of every role */
5275  if (superuser_arg(member))
5276  return true;
5277 
5278  /*
5279  * Find all the roles that member has the privileges of, including
5280  * multi-level recursion, then see if target role is any one of them.
5281  */
5283  InvalidOid, NULL),
5284  role);
5285 }
5286 
5287 /*
5288  * Can member use SET ROLE to this role?
5289  *
5290  * There must be a chain of grants from 'member' to 'role' each of which
5291  * permits SET ROLE; that is, each of which has set_option = true.
5292  *
5293  * It doesn't matter whether the grants are inheritable. That's a separate
5294  * question; see has_privs_of_role.
5295  *
5296  * This function should be used to determine whether the session user can
5297  * use SET ROLE to become the target user. We also use it to determine whether
5298  * the session user can change an existing object to be owned by the target
5299  * user, or create new objects owned by the target user.
5300  */
5301 bool
5303 {
5304  /* Fast path for simple case */
5305  if (member == role)
5306  return true;
5307 
5308  /* Superusers have every privilege, so can always SET ROLE */
5309  if (superuser_arg(member))
5310  return true;
5311 
5312  /*
5313  * Find all the roles that member can access via SET ROLE, including
5314  * multi-level recursion, then see if target role is any one of them.
5315  */
5317  InvalidOid, NULL),
5318  role);
5319 }
5320 
5321 /*
5322  * Permission violation error unless able to SET ROLE to target role.
5323  */
5324 void
5326 {
5327  if (!member_can_set_role(member, role))
5328  ereport(ERROR,
5329  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
5330  errmsg("must be able to SET ROLE \"%s\"",
5331  GetUserNameFromId(role, false))));
5332 }
5333 
5334 /*
5335  * Is member a member of role (directly or indirectly)?
5336  *
5337  * This is defined to recurse through grants whether they are inherited or not.
5338  *
5339  * Do not use this for privilege checking, instead use has_privs_of_role().
5340  * Don't use it for determining whether it's possible to SET ROLE to some
5341  * other role; for that, use member_can_set_role(). And don't use it for
5342  * determining whether it's OK to create an object owned by some other role:
5343  * use member_can_set_role() for that, too.
5344  *
5345  * In short, calling this function is the wrong thing to do nearly everywhere.
5346  */
5347 bool
5349 {
5350  /* Fast path for simple case */
5351  if (member == role)
5352  return true;
5353 
5354  /* Superusers have every privilege, so are part of every role */
5355  if (superuser_arg(member))
5356  return true;
5357 
5358  /*
5359  * Find all the roles that member is a member of, including multi-level
5360  * recursion, then see if target role is any one of them.
5361  */
5363  InvalidOid, NULL),
5364  role);
5365 }
5366 
5367 /*
5368  * Is member a member of role, not considering superuserness?
5369  *
5370  * This is identical to is_member_of_role except we ignore superuser
5371  * status.
5372  *
5373  * Do not use this for privilege checking, instead use has_privs_of_role()
5374  */
5375 bool
5377 {
5378  /* Fast path for simple case */
5379  if (member == role)
5380  return true;
5381 
5382  /*
5383  * Find all the roles that member is a member of, including multi-level
5384  * recursion, then see if target role is any one of them.
5385  */
5387  InvalidOid, NULL),
5388  role);
5389 }
5390 
5391 
5392 /*
5393  * Is member an admin of role? That is, is member the role itself (subject to
5394  * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
5395  * or a superuser?
5396  */
5397 bool
5398 is_admin_of_role(Oid member, Oid role)
5399 {
5400  Oid admin_role;
5401 
5402  if (superuser_arg(member))
5403  return true;
5404 
5405  /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5406  if (member == role)
5407  return false;
5408 
5409  (void) roles_is_member_of(member, ROLERECURSE_MEMBERS, role, &admin_role);
5410  return OidIsValid(admin_role);
5411 }
5412 
5413 /*
5414  * Find a role whose privileges "member" inherits which has ADMIN OPTION
5415  * on "role", ignoring super-userness.
5416  *
5417  * There might be more than one such role; prefer one which involves fewer
5418  * hops. That is, if member has ADMIN OPTION, prefer that over all other
5419  * options; if not, prefer a role from which member inherits more directly
5420  * over more indirect inheritance.
5421  */
5422 Oid
5424 {
5425  Oid admin_role;
5426 
5427  /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5428  if (member == role)
5429  return InvalidOid;
5430 
5431  (void) roles_is_member_of(member, ROLERECURSE_PRIVS, role, &admin_role);
5432  return admin_role;
5433 }
5434 
5435 
5436 /* does what it says ... */
5437 static int
5439 {
5440  int nbits = 0;
5441 
5442  /* this code relies on AclMode being an unsigned type */
5443  while (mask)
5444  {
5445  if (mask & 1)
5446  nbits++;
5447  mask >>= 1;
5448  }
5449  return nbits;
5450 }
5451 
5452 
5453 /*
5454  * Select the effective grantor ID for a GRANT or REVOKE operation.
5455  *
5456  * The grantor must always be either the object owner or some role that has
5457  * been explicitly granted grant options. This ensures that all granted
5458  * privileges appear to flow from the object owner, and there are never
5459  * multiple "original sources" of a privilege. Therefore, if the would-be
5460  * grantor is a member of a role that has the needed grant options, we have
5461  * to do the grant as that role instead.
5462  *
5463  * It is possible that the would-be grantor is a member of several roles
5464  * that have different subsets of the desired grant options, but no one
5465  * role has 'em all. In this case we pick a role with the largest number
5466  * of desired options. Ties are broken in favor of closer ancestors.
5467  *
5468  * roleId: the role attempting to do the GRANT/REVOKE
5469  * privileges: the privileges to be granted/revoked
5470  * acl: the ACL of the object in question
5471  * ownerId: the role owning the object in question
5472  * *grantorId: receives the OID of the role to do the grant as
5473  * *grantOptions: receives the grant options actually held by grantorId
5474  *
5475  * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
5476  */
5477 void
5478 select_best_grantor(Oid roleId, AclMode privileges,
5479  const Acl *acl, Oid ownerId,
5480  Oid *grantorId, AclMode *grantOptions)
5481 {
5482  AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
5483  List *roles_list;
5484  int nrights;
5485  ListCell *l;
5486 
5487  /*
5488  * The object owner is always treated as having all grant options, so if
5489  * roleId is the owner it's easy. Also, if roleId is a superuser it's
5490  * easy: superusers are implicitly members of every role, so they act as
5491  * the object owner.
5492  */
5493  if (roleId == ownerId || superuser_arg(roleId))
5494  {
5495  *grantorId = ownerId;
5496  *grantOptions = needed_goptions;
5497  return;
5498  }
5499 
5500  /*
5501  * Otherwise we have to do a careful search to see if roleId has the
5502  * privileges of any suitable role. Note: we can hang onto the result of
5503  * roles_is_member_of() throughout this loop, because aclmask_direct()
5504  * doesn't query any role memberships.
5505  */
5506  roles_list = roles_is_member_of(roleId, ROLERECURSE_PRIVS,
5507  InvalidOid, NULL);
5508 
5509  /* initialize candidate result as default */
5510  *grantorId = roleId;
5511  *grantOptions = ACL_NO_RIGHTS;
5512  nrights = 0;
5513 
5514  foreach(l, roles_list)
5515  {
5516  Oid otherrole = lfirst_oid(l);
5517  AclMode otherprivs;
5518 
5519  otherprivs = aclmask_direct(acl, otherrole, ownerId,
5520  needed_goptions, ACLMASK_ALL);
5521  if (otherprivs == needed_goptions)
5522  {
5523  /* Found a suitable grantor */
5524  *grantorId = otherrole;
5525  *grantOptions = otherprivs;
5526  return;
5527  }
5528 
5529  /*
5530  * If it has just some of the needed privileges, remember best
5531  * candidate.
5532  */
5533  if (otherprivs != ACL_NO_RIGHTS)
5534  {
5535  int nnewrights = count_one_bits(otherprivs);
5536 
5537  if (nnewrights > nrights)
5538  {
5539  *grantorId = otherrole;
5540  *grantOptions = otherprivs;
5541  nrights = nnewrights;
5542  }
5543  }
5544  }
5545 }
5546 
5547 /*
5548  * get_role_oid - Given a role name, look up the role's OID.
5549  *
5550  * If missing_ok is false, throw an error if role name not found. If
5551  * true, just return InvalidOid.
5552  */
5553 Oid
5554 get_role_oid(const char *rolname, bool missing_ok)
5555 {
5556  Oid oid;
5557 
5558  oid = GetSysCacheOid1(AUTHNAME, Anum_pg_authid_oid,
5560  if (!OidIsValid(oid) && !missing_ok)
5561  ereport(ERROR,
5562  (errcode(ERRCODE_UNDEFINED_OBJECT),
5563  errmsg("role \"%s\" does not exist", rolname)));
5564  return oid;
5565 }
5566 
5567 /*
5568  * get_role_oid_or_public - As above, but return ACL_ID_PUBLIC if the
5569  * role name is "public".
5570  */
5571 Oid
5573 {
5574  if (strcmp(rolname, "public") == 0)
5575  return ACL_ID_PUBLIC;
5576 
5577  return get_role_oid(rolname, false);
5578 }
5579 
5580 /*
5581  * Given a RoleSpec node, return the OID it corresponds to. If missing_ok is
5582  * true, return InvalidOid if the role does not exist.
5583  *
5584  * PUBLIC is always disallowed here. Routines wanting to handle the PUBLIC
5585  * case must check the case separately.
5586  */
5587 Oid
5588 get_rolespec_oid(const RoleSpec *role, bool missing_ok)
5589 {
5590  Oid oid;
5591 
5592  switch (role->roletype)
5593  {
5594  case ROLESPEC_CSTRING:
5595  Assert(role->rolename);
5596  oid = get_role_oid(role->rolename, missing_ok);
5597  break;
5598 
5599  case ROLESPEC_CURRENT_ROLE:
5600  case ROLESPEC_CURRENT_USER:
5601  oid = GetUserId();
5602  break;
5603 
5604  case ROLESPEC_SESSION_USER:
5605  oid = GetSessionUserId();
5606  break;
5607 
5608  case ROLESPEC_PUBLIC:
5609  ereport(ERROR,
5610  (errcode(ERRCODE_UNDEFINED_OBJECT),
5611  errmsg("role \"%s\" does not exist", "public")));
5612  oid = InvalidOid; /* make compiler happy */
5613  break;
5614 
5615  default:
5616  elog(ERROR, "unexpected role type %d", role->roletype);
5617  }
5618 
5619  return oid;
5620 }
5621 
5622 /*
5623  * Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
5624  * Caller must ReleaseSysCache when done with the result tuple.
5625  */
5626 HeapTuple
5628 {
5629  HeapTuple tuple;
5630 
5631  switch (role->roletype)
5632  {
5633  case ROLESPEC_CSTRING:
5634  Assert(role->rolename);
5635  tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolename));
5636  if (!HeapTupleIsValid(tuple))
5637  ereport(ERROR,
5638  (errcode(ERRCODE_UNDEFINED_OBJECT),
5639  errmsg("role \"%s\" does not exist", role->rolename)));
5640  break;
5641 
5642  case ROLESPEC_CURRENT_ROLE:
5643  case ROLESPEC_CURRENT_USER:
5644  tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
5645  if (!HeapTupleIsValid(tuple))
5646  elog(ERROR, "cache lookup failed for role %u", GetUserId());
5647  break;
5648 
5649  case ROLESPEC_SESSION_USER:
5650  tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetSessionUserId()));
5651  if (!HeapTupleIsValid(tuple))
5652  elog(ERROR, "cache lookup failed for role %u", GetSessionUserId());
5653  break;
5654 
5655  case ROLESPEC_PUBLIC:
5656  ereport(ERROR,
5657  (errcode(ERRCODE_UNDEFINED_OBJECT),
5658  errmsg("role \"%s\" does not exist", "public")));
5659  tuple = NULL; /* make compiler happy */
5660  break;
5661 
5662  default:
5663  elog(ERROR, "unexpected role type %d", role->roletype);
5664  }
5665 
5666  return tuple;
5667 }
5668 
5669 /*
5670  * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
5671  */
5672 char *
5674 {
5675  HeapTuple tp;
5676  Form_pg_authid authForm;
5677  char *rolename;
5678 
5679  tp = get_rolespec_tuple(role);
5680  authForm = (Form_pg_authid) GETSTRUCT(tp);
5681  rolename = pstrdup(NameStr(authForm->rolname));
5682  ReleaseSysCache(tp);
5683 
5684  return rolename;
5685 }
5686 
5687 /*
5688  * Given a RoleSpec, throw an error if the name is reserved, using detail_msg,
5689  * if provided (which must be already translated).
5690  *
5691  * If node is NULL, no error is thrown. If detail_msg is NULL then no detail
5692  * message is provided.
5693  */
5694 void
5695 check_rolespec_name(const RoleSpec *role, const char *detail_msg)
5696 {
5697  if (!role)
5698  return;
5699 
5700  if (role->roletype != ROLESPEC_CSTRING)
5701  return;
5702 
5703  if (IsReservedName(role->rolename))
5704  {
5705  if (detail_msg)
5706  ereport(ERROR,
5707  (errcode(ERRCODE_RESERVED_NAME),
5708  errmsg("role name \"%s\" is reserved",
5709  role->rolename),
5710  errdetail_internal("%s", detail_msg)));
5711  else
5712  ereport(ERROR,
5713  (errcode(ERRCODE_RESERVED_NAME),
5714  errmsg("role name \"%s\" is reserved",
5715  role->rolename)));
5716  }
5717 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
Datum pg_has_role_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4941
Datum has_schema_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3866
Datum has_largeobject_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4770
Datum hash_aclitem(PG_FUNCTION_ARGS)
Definition: acl.c:752
void initialize_acl(void)
Definition: acl.c:5024
Datum has_sequence_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:2120
Datum has_table_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:2005
Datum has_server_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:4068
Acl * aclupdate(const Acl *old_acl, const AclItem *mod_aip, int modechg, Oid ownerId, DropBehavior behavior)
Definition: acl.c:976
Datum has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4319
Datum has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2744
Datum has_server_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3988
Datum aclinsert(PG_FUNCTION_ARGS)
Definition: acl.c:1576
static AclMode convert_function_priv_string(text *priv_type_text)
Definition: acl.c:3558
Datum has_largeobject_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4720
static const char * getid(const char *s, char *n, Node *escontext)
Definition: acl.c:153
static const char * convert_aclright_to_string(int aclright)
Definition: acl.c:1718
bool is_admin_of_role(Oid member, Oid role)
Definition: acl.c:5398
Datum has_column_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2824
static bool aclitem_match(const AclItem *a1, const AclItem *a2)
Definition: acl.c:697
Datum pg_has_role_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:4822
Datum has_language_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3586
Datum has_schema_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3786
Datum aclitem_eq(PG_FUNCTION_ARGS)
Definition: acl.c:732
Datum has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4238
Datum makeaclitem(PG_FUNCTION_ARGS)
Definition: acl.c:1618
Datum has_table_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:1982
Datum has_server_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4038
Datum has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2642
Datum has_language_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3694