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