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 Acl *
1096 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
1097 {
1098  Acl *new_acl;
1099  AclItem *new_aip;
1100  AclItem *old_aip;
1101  AclItem *dst_aip;
1102  AclItem *src_aip;
1103  AclItem *targ_aip;
1104  bool newpresent = false;
1105  int dst,
1106  src,
1107  targ,
1108  num;
1109 
1110  check_acl(old_acl);
1111 
1112  /*
1113  * Make a copy of the given ACL, substituting new owner ID for old
1114  * wherever it appears as either grantor or grantee. Also note if the new
1115  * owner ID is already present.
1116  */
1117  num = ACL_NUM(old_acl);
1118  old_aip = ACL_DAT(old_acl);
1119  new_acl = allocacl(num);
1120  new_aip = ACL_DAT(new_acl);
1121  memcpy(new_aip, old_aip, num * sizeof(AclItem));
1122  for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
1123  {
1124  if (dst_aip->ai_grantor == oldOwnerId)
1125  dst_aip->ai_grantor = newOwnerId;
1126  else if (dst_aip->ai_grantor == newOwnerId)
1127  newpresent = true;
1128  if (dst_aip->ai_grantee == oldOwnerId)
1129  dst_aip->ai_grantee = newOwnerId;
1130  else if (dst_aip->ai_grantee == newOwnerId)
1131  newpresent = true;
1132  }
1133 
1134  /*
1135  * If the old ACL contained any references to the new owner, then we may
1136  * now have generated an ACL containing duplicate entries. Find them and
1137  * merge them so that there are not duplicates. (This is relatively
1138  * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
1139  * be the normal case.)
1140  *
1141  * To simplify deletion of duplicate entries, we temporarily leave them in
1142  * the array but set their privilege masks to zero; when we reach such an
1143  * entry it's just skipped. (Thus, a side effect of this code will be to
1144  * remove privilege-free entries, should there be any in the input.) dst
1145  * is the next output slot, targ is the currently considered input slot
1146  * (always >= dst), and src scans entries to the right of targ looking for
1147  * duplicates. Once an entry has been emitted to dst it is known
1148  * duplicate-free and need not be considered anymore.
1149  */
1150  if (newpresent)
1151  {
1152  dst = 0;
1153  for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
1154  {
1155  /* ignore if deleted in an earlier pass */
1156  if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
1157  continue;
1158  /* find and merge any duplicates */
1159  for (src = targ + 1, src_aip = targ_aip + 1; src < num;
1160  src++, src_aip++)
1161  {
1162  if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
1163  continue;
1164  if (aclitem_match(targ_aip, src_aip))
1165  {
1166  ACLITEM_SET_RIGHTS(*targ_aip,
1167  ACLITEM_GET_RIGHTS(*targ_aip) |
1168  ACLITEM_GET_RIGHTS(*src_aip));
1169  /* mark the duplicate deleted */
1170  ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
1171  }
1172  }
1173  /* and emit to output */
1174  new_aip[dst] = *targ_aip;
1175  dst++;
1176  }
1177  /* Adjust array size to be 'dst' items */
1178  ARR_DIMS(new_acl)[0] = dst;
1179  SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
1180  }
1181 
1182  return new_acl;
1183 }
1184 
1185 
1186 /*
1187  * When granting grant options, we must disallow attempts to set up circular
1188  * chains of grant options. Suppose A (the object owner) grants B some
1189  * privileges with grant option, and B re-grants them to C. If C could
1190  * grant the privileges to B as well, then A would be unable to effectively
1191  * revoke the privileges from B, since recursive_revoke would consider that
1192  * B still has 'em from C.
1193  *
1194  * We check for this by recursively deleting all grant options belonging to
1195  * the target grantee, and then seeing if the would-be grantor still has the
1196  * grant option or not.
1197  */
1198 static void
1199 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
1200  Oid ownerId)
1201 {
1202  Acl *acl;
1203  AclItem *aip;
1204  int i,
1205  num;
1206  AclMode own_privs;
1207 
1208  check_acl(old_acl);
1209 
1210  /*
1211  * For now, grant options can only be granted to roles, not PUBLIC.
1212  * Otherwise we'd have to work a bit harder here.
1213  */
1214  Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
1215 
1216  /* The owner always has grant options, no need to check */
1217  if (mod_aip->ai_grantor == ownerId)
1218  return;
1219 
1220  /* Make a working copy */
1221  acl = allocacl(ACL_NUM(old_acl));
1222  memcpy(acl, old_acl, ACL_SIZE(old_acl));
1223 
1224  /* Zap all grant options of target grantee, plus what depends on 'em */
1225 cc_restart:
1226  num = ACL_NUM(acl);
1227  aip = ACL_DAT(acl);
1228  for (i = 0; i < num; i++)
1229  {
1230  if (aip[i].ai_grantee == mod_aip->ai_grantee &&
1232  {
1233  Acl *new_acl;
1234 
1235  /* We'll actually zap ordinary privs too, but no matter */
1236  new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
1237  ownerId, DROP_CASCADE);
1238 
1239  pfree(acl);
1240  acl = new_acl;
1241 
1242  goto cc_restart;
1243  }
1244  }
1245 
1246  /* Now we can compute grantor's independently-derived privileges */
1247  own_privs = aclmask(acl,
1248  mod_aip->ai_grantor,
1249  ownerId,
1251  ACLMASK_ALL);
1252  own_privs = ACL_OPTION_TO_PRIVS(own_privs);
1253 
1254  if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
1255  ereport(ERROR,
1256  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1257  errmsg("grant options cannot be granted back to your own grantor")));
1258 
1259  pfree(acl);
1260 }
1261 
1262 
1263 /*
1264  * Ensure that no privilege is "abandoned". A privilege is abandoned
1265  * if the user that granted the privilege loses the grant option. (So
1266  * the chain through which it was granted is broken.) Either the
1267  * abandoned privileges are revoked as well, or an error message is
1268  * printed, depending on the drop behavior option.
1269  *
1270  * acl: the input ACL list
1271  * grantee: the user from whom some grant options have been revoked
1272  * revoke_privs: the grant options being revoked
1273  * ownerId: Oid of object owner
1274  * behavior: RESTRICT or CASCADE behavior for recursive removal
1275  *
1276  * The input Acl object is pfree'd if replaced.
1277  */
1278 static Acl *
1280  Oid grantee,
1281  AclMode revoke_privs,
1282  Oid ownerId,
1283  DropBehavior behavior)
1284 {
1285  AclMode still_has;
1286  AclItem *aip;
1287  int i,
1288  num;
1289 
1290  check_acl(acl);
1291 
1292  /* The owner can never truly lose grant options, so short-circuit */
1293  if (grantee == ownerId)
1294  return acl;
1295 
1296  /* The grantee might still have some grant options via another grantor */
1297  still_has = aclmask(acl, grantee, ownerId,
1298  ACL_GRANT_OPTION_FOR(revoke_privs),
1299  ACLMASK_ALL);
1300  revoke_privs &= ~ACL_OPTION_TO_PRIVS(still_has);
1301  if (revoke_privs == ACL_NO_RIGHTS)
1302  return acl;
1303 
1304 restart:
1305  num = ACL_NUM(acl);
1306  aip = ACL_DAT(acl);
1307  for (i = 0; i < num; i++)
1308  {
1309  if (aip[i].ai_grantor == grantee
1310  && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1311  {
1312  AclItem mod_acl;
1313  Acl *new_acl;
1314 
1315  if (behavior == DROP_RESTRICT)
1316  ereport(ERROR,
1317  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1318  errmsg("dependent privileges exist"),
1319  errhint("Use CASCADE to revoke them too.")));
1320 
1321  mod_acl.ai_grantor = grantee;
1322  mod_acl.ai_grantee = aip[i].ai_grantee;
1324  revoke_privs,
1325  revoke_privs);
1326 
1327  new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1328  ownerId, behavior);
1329 
1330  pfree(acl);
1331  acl = new_acl;
1332 
1333  goto restart;
1334  }
1335  }
1336 
1337  return acl;
1338 }
1339 
1340 
1341 /*
1342  * aclmask --- compute bitmask of all privileges held by roleid.
1343  *
1344  * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1345  * held by the given roleid according to the given ACL list, ANDed
1346  * with 'mask'. (The point of passing 'mask' is to let the routine
1347  * exit early if all privileges of interest have been found.)
1348  *
1349  * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1350  * is known true. (This lets us exit soonest in cases where the
1351  * caller is only going to test for zero or nonzero result.)
1352  *
1353  * Usage patterns:
1354  *
1355  * To see if any of a set of privileges are held:
1356  * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1357  *
1358  * To see if all of a set of privileges are held:
1359  * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1360  *
1361  * To determine exactly which of a set of privileges are held:
1362  * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1363  */
1364 AclMode
1365 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1366  AclMode mask, AclMaskHow how)
1367 {
1368  AclMode result;
1370  AclItem *aidat;
1371  int i,
1372  num;
1373 
1374  /*
1375  * Null ACL should not happen, since caller should have inserted
1376  * appropriate default
1377  */
1378  if (acl == NULL)
1379  elog(ERROR, "null ACL");
1380 
1381  check_acl(acl);
1382 
1383  /* Quick exit for mask == 0 */
1384  if (mask == 0)
1385  return 0;
1386 
1387  result = 0;
1388 
1389  /* Owner always implicitly has all grant options */
1390  if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1391  has_privs_of_role(roleid, ownerId))
1392  {
1393  result = mask & ACLITEM_ALL_GOPTION_BITS;
1394  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1395  return result;
1396  }
1397 
1398  num = ACL_NUM(acl);
1399  aidat = ACL_DAT(acl);
1400 
1401  /*
1402  * Check privileges granted directly to roleid or to public
1403  */
1404  for (i = 0; i < num; i++)
1405  {
1406  AclItem *aidata = &aidat[i];
1407 
1408  if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1409  aidata->ai_grantee == roleid)
1410  {
1411  result |= aidata->ai_privs & mask;
1412  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1413  return result;
1414  }
1415  }
1416 
1417  /*
1418  * Check privileges granted indirectly via role memberships. We do this in
1419  * a separate pass to minimize expensive indirect membership tests. In
1420  * particular, it's worth testing whether a given ACL entry grants any
1421  * privileges still of interest before we perform the has_privs_of_role
1422  * test.
1423  */
1424  remaining = mask & ~result;
1425  for (i = 0; i < num; i++)
1426  {
1427  AclItem *aidata = &aidat[i];
1428 
1429  if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1430  aidata->ai_grantee == roleid)
1431  continue; /* already checked it */
1432 
1433  if ((aidata->ai_privs & remaining) &&
1434  has_privs_of_role(roleid, aidata->ai_grantee))
1435  {
1436  result |= aidata->ai_privs & mask;
1437  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1438  return result;
1439  remaining = mask & ~result;
1440  }
1441  }
1442 
1443  return result;
1444 }
1445 
1446 
1447 /*
1448  * aclmask_direct --- compute bitmask of all privileges held by roleid.
1449  *
1450  * This is exactly like aclmask() except that we consider only privileges
1451  * held *directly* by roleid, not those inherited via role membership.
1452  */
1453 static AclMode
1454 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1455  AclMode mask, AclMaskHow how)
1456 {
1457  AclMode result;
1458  AclItem *aidat;
1459  int i,
1460  num;
1461 
1462  /*
1463  * Null ACL should not happen, since caller should have inserted
1464  * appropriate default
1465  */
1466  if (acl == NULL)
1467  elog(ERROR, "null ACL");
1468 
1469  check_acl(acl);
1470 
1471  /* Quick exit for mask == 0 */
1472  if (mask == 0)
1473  return 0;
1474 
1475  result = 0;
1476 
1477  /* Owner always implicitly has all grant options */
1478  if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1479  roleid == ownerId)
1480  {
1481  result = mask & ACLITEM_ALL_GOPTION_BITS;
1482  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1483  return result;
1484  }
1485 
1486  num = ACL_NUM(acl);
1487  aidat = ACL_DAT(acl);
1488 
1489  /*
1490  * Check privileges granted directly to roleid (and not to public)
1491  */
1492  for (i = 0; i < num; i++)
1493  {
1494  AclItem *aidata = &aidat[i];
1495 
1496  if (aidata->ai_grantee == roleid)
1497  {
1498  result |= aidata->ai_privs & mask;
1499  if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1500  return result;
1501  }
1502  }
1503 
1504  return result;
1505 }
1506 
1507 
1508 /*
1509  * aclmembers
1510  * Find out all the roleids mentioned in an Acl.
1511  * Note that we do not distinguish grantors from grantees.
1512  *
1513  * *roleids is set to point to a palloc'd array containing distinct OIDs
1514  * in sorted order. The length of the array is the function result.
1515  */
1516 int
1517 aclmembers(const Acl *acl, Oid **roleids)
1518 {
1519  Oid *list;
1520  const AclItem *acldat;
1521  int i,
1522  j;
1523 
1524  if (acl == NULL || ACL_NUM(acl) == 0)
1525  {
1526  *roleids = NULL;
1527  return 0;
1528  }
1529 
1530  check_acl(acl);
1531 
1532  /* Allocate the worst-case space requirement */
1533  list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1534  acldat = ACL_DAT(acl);
1535 
1536  /*
1537  * Walk the ACL collecting mentioned RoleIds.
1538  */
1539  j = 0;
1540  for (i = 0; i < ACL_NUM(acl); i++)
1541  {
1542  const AclItem *ai = &acldat[i];
1543 
1544  if (ai->ai_grantee != ACL_ID_PUBLIC)
1545  list[j++] = ai->ai_grantee;
1546  /* grantor is currently never PUBLIC, but let's check anyway */
1547  if (ai->ai_grantor != ACL_ID_PUBLIC)
1548  list[j++] = ai->ai_grantor;
1549  }
1550 
1551  /* Sort the array */
1552  qsort(list, j, sizeof(Oid), oid_cmp);
1553 
1554  /*
1555  * We could repalloc the array down to minimum size, but it's hardly worth
1556  * it since it's only transient memory.
1557  */
1558  *roleids = list;
1559 
1560  /* Remove duplicates from the array */
1561  return qunique(list, j, sizeof(Oid), oid_cmp);
1562 }
1563 
1564 
1565 /*
1566  * aclinsert (exported function)
1567  */
1568 Datum
1570 {
1571  ereport(ERROR,
1572  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1573  errmsg("aclinsert is no longer supported")));
1574 
1575  PG_RETURN_NULL(); /* keep compiler quiet */
1576 }
1577 
1578 Datum
1580 {
1581  ereport(ERROR,
1582  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1583  errmsg("aclremove is no longer supported")));
1584 
1585  PG_RETURN_NULL(); /* keep compiler quiet */
1586 }
1587 
1588 Datum
1590 {
1591  Acl *acl = PG_GETARG_ACL_P(0);
1592  AclItem *aip = PG_GETARG_ACLITEM_P(1);
1593  AclItem *aidat;
1594  int i,
1595  num;
1596 
1597  check_acl(acl);
1598  num = ACL_NUM(acl);
1599  aidat = ACL_DAT(acl);
1600  for (i = 0; i < num; ++i)
1601  {
1602  if (aip->ai_grantee == aidat[i].ai_grantee &&
1603  aip->ai_grantor == aidat[i].ai_grantor &&
1604  (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1605  PG_RETURN_BOOL(true);
1606  }
1607  PG_RETURN_BOOL(false);
1608 }
1609 
1610 Datum
1612 {
1613  Oid grantee = PG_GETARG_OID(0);
1614  Oid grantor = PG_GETARG_OID(1);
1615  text *privtext = PG_GETARG_TEXT_PP(2);
1616  bool goption = PG_GETARG_BOOL(3);
1617  AclItem *result;
1618  AclMode priv;
1619  static const priv_map any_priv_map[] = {
1620  {"SELECT", ACL_SELECT},
1621  {"INSERT", ACL_INSERT},
1622  {"UPDATE", ACL_UPDATE},
1623  {"DELETE", ACL_DELETE},
1624  {"TRUNCATE", ACL_TRUNCATE},
1625  {"REFERENCES", ACL_REFERENCES},
1626  {"TRIGGER", ACL_TRIGGER},
1627  {"EXECUTE", ACL_EXECUTE},
1628  {"USAGE", ACL_USAGE},
1629  {"CREATE", ACL_CREATE},
1630  {"TEMP", ACL_CREATE_TEMP},
1631  {"TEMPORARY", ACL_CREATE_TEMP},
1632  {"CONNECT", ACL_CONNECT},
1633  {"SET", ACL_SET},
1634  {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
1635  {"MAINTAIN", ACL_MAINTAIN},
1636  {"RULE", 0}, /* ignore old RULE privileges */
1637  {NULL, 0}
1638  };
1639 
1640  priv = convert_any_priv_string(privtext, any_priv_map);
1641 
1642  result = (AclItem *) palloc(sizeof(AclItem));
1643 
1644  result->ai_grantee = grantee;
1645  result->ai_grantor = grantor;
1646 
1647  ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1648  (goption ? priv : ACL_NO_RIGHTS));
1649 
1650  PG_RETURN_ACLITEM_P(result);
1651 }
1652 
1653 
1654 /*
1655  * convert_any_priv_string: recognize privilege strings for has_foo_privilege
1656  *
1657  * We accept a comma-separated list of case-insensitive privilege names,
1658  * producing a bitmask of the OR'd privilege bits. We are liberal about
1659  * whitespace between items, not so much about whitespace within items.
1660  * The allowed privilege names are given as an array of priv_map structs,
1661  * terminated by one with a NULL name pointer.
1662  */
1663 static AclMode
1665  const priv_map *privileges)
1666 {
1667  AclMode result = 0;
1668  char *priv_type = text_to_cstring(priv_type_text);
1669  char *chunk;
1670  char *next_chunk;
1671 
1672  /* We rely on priv_type being a private, modifiable string */
1673  for (chunk = priv_type; chunk; chunk = next_chunk)
1674  {
1675  int chunk_len;
1676  const priv_map *this_priv;
1677 
1678  /* Split string at commas */
1679  next_chunk = strchr(chunk, ',');
1680  if (next_chunk)
1681  *next_chunk++ = '\0';
1682 
1683  /* Drop leading/trailing whitespace in this chunk */
1684  while (*chunk && isspace((unsigned char) *chunk))
1685  chunk++;
1686  chunk_len = strlen(chunk);
1687  while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
1688  chunk_len--;
1689  chunk[chunk_len] = '\0';
1690 
1691  /* Match to the privileges list */
1692  for (this_priv = privileges; this_priv->name; this_priv++)
1693  {
1694  if (pg_strcasecmp(this_priv->name, chunk) == 0)
1695  {
1696  result |= this_priv->value;
1697  break;
1698  }
1699  }
1700  if (!this_priv->name)
1701  ereport(ERROR,
1702  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1703  errmsg("unrecognized privilege type: \"%s\"", chunk)));
1704  }
1705 
1706  pfree(priv_type);
1707  return result;
1708 }
1709 
1710 
1711 static const char *
1713 {
1714  switch (aclright)
1715  {
1716  case ACL_INSERT:
1717  return "INSERT";
1718  case ACL_SELECT:
1719  return "SELECT";
1720  case ACL_UPDATE:
1721  return "UPDATE";
1722  case ACL_DELETE:
1723  return "DELETE";
1724  case ACL_TRUNCATE:
1725  return "TRUNCATE";
1726  case ACL_REFERENCES:
1727  return "REFERENCES";
1728  case ACL_TRIGGER:
1729  return "TRIGGER";
1730  case ACL_EXECUTE:
1731  return "EXECUTE";
1732  case ACL_USAGE:
1733  return "USAGE";
1734  case ACL_CREATE:
1735  return "CREATE";
1736  case ACL_CREATE_TEMP:
1737  return "TEMPORARY";
1738  case ACL_CONNECT:
1739  return "CONNECT";
1740  case ACL_SET:
1741  return "SET";
1742  case ACL_ALTER_SYSTEM:
1743  return "ALTER SYSTEM";
1744  case ACL_MAINTAIN:
1745  return "MAINTAIN";
1746  default:
1747  elog(ERROR, "unrecognized aclright: %d", aclright);
1748  return NULL;
1749  }
1750 }
1751 
1752 
1753 /*----------
1754  * Convert an aclitem[] to a table.
1755  *
1756  * Example:
1757  *
1758  * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
1759  *
1760  * returns the table
1761  *
1762  * {{ OID(joe), 0::OID, 'SELECT', false },
1763  * { OID(joe), OID(foo), 'INSERT', true },
1764  * { OID(joe), OID(foo), 'UPDATE', false }}
1765  *----------
1766  */
1767 Datum
1769 {
1770  Acl *acl = PG_GETARG_ACL_P(0);
1771  FuncCallContext *funcctx;
1772  int *idx;
1773  AclItem *aidat;
1774 
1775  if (SRF_IS_FIRSTCALL())
1776  {
1777  TupleDesc tupdesc;
1778  MemoryContext oldcontext;
1779 
1780  check_acl(acl);
1781 
1782  funcctx = SRF_FIRSTCALL_INIT();
1783  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1784 
1785  /*
1786  * build tupdesc for result tuples (matches out parameters in pg_proc
1787  * entry)
1788  */
1789  tupdesc = CreateTemplateTupleDesc(4);
1790  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
1791  OIDOID, -1, 0);
1792  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
1793  OIDOID, -1, 0);
1794  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
1795  TEXTOID, -1, 0);
1796  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
1797  BOOLOID, -1, 0);
1798 
1799  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1800 
1801  /* allocate memory for user context */
1802  idx = (int *) palloc(sizeof(int[2]));
1803  idx[0] = 0; /* ACL array item index */
1804  idx[1] = -1; /* privilege type counter */
1805  funcctx->user_fctx = (void *) idx;
1806 
1807  MemoryContextSwitchTo(oldcontext);
1808  }
1809 
1810  funcctx = SRF_PERCALL_SETUP();
1811  idx = (int *) funcctx->user_fctx;
1812  aidat = ACL_DAT(acl);
1813 
1814  /* need test here in case acl has no items */
1815  while (idx[0] < ACL_NUM(acl))
1816  {
1817  AclItem *aidata;
1818  AclMode priv_bit;
1819 
1820  idx[1]++;
1821  if (idx[1] == N_ACL_RIGHTS)
1822  {
1823  idx[1] = 0;
1824  idx[0]++;
1825  if (idx[0] >= ACL_NUM(acl)) /* done */
1826  break;
1827  }
1828  aidata = &aidat[idx[0]];
1829  priv_bit = UINT64CONST(1) << idx[1];
1830 
1831  if (ACLITEM_GET_PRIVS(*aidata) & priv_bit)
1832  {
1833  Datum result;
1834  Datum values[4];
1835  bool nulls[4] = {0};
1836  HeapTuple tuple;
1837 
1838  values[0] = ObjectIdGetDatum(aidata->ai_grantor);
1839  values[1] = ObjectIdGetDatum(aidata->ai_grantee);
1841  values[3] = BoolGetDatum((ACLITEM_GET_GOPTIONS(*aidata) & priv_bit) != 0);
1842 
1843  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1844  result = HeapTupleGetDatum(tuple);
1845 
1846  SRF_RETURN_NEXT(funcctx, result);
1847  }
1848  }
1849 
1850  SRF_RETURN_DONE(funcctx);
1851 }
1852 
1853 
1854 /*
1855  * has_table_privilege variants
1856  * These are all named "has_table_privilege" at the SQL level.
1857  * They take various combinations of relation name, relation OID,
1858  * user name, user OID, or implicit user = current_user.
1859  *
1860  * The result is a boolean value: true if user has the indicated
1861  * privilege, false if not. The variants that take a relation OID
1862  * return NULL if the OID doesn't exist (rather than failing, as
1863  * they did before Postgres 8.4).
1864  */
1865 
1866 /*
1867  * has_table_privilege_name_name
1868  * Check user privileges on a table given
1869  * name username, text tablename, and text priv name.
1870  */
1871 Datum
1873 {
1874  Name rolename = PG_GETARG_NAME(0);
1875  text *tablename = PG_GETARG_TEXT_PP(1);
1876  text *priv_type_text = PG_GETARG_TEXT_PP(2);
1877  Oid roleid;
1878  Oid tableoid;
1879  AclMode mode;
1880  AclResult aclresult;
1881 
1882  roleid = get_role_oid_or_public(NameStr(*rolename));
1883  tableoid = convert_table_name(tablename);
1884  mode = convert_table_priv_string(priv_type_text);
1885 
1886  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1887 
1888  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1889 }
1890 
1891 /*
1892  * has_table_privilege_name
1893  * Check user privileges on a table given
1894  * text tablename and text priv name.
1895  * current_user is assumed
1896  */
1897 Datum
1899 {
1900  text *tablename = PG_GETARG_TEXT_PP(0);
1901  text *priv_type_text = PG_GETARG_TEXT_PP(1);
1902  Oid roleid;
1903  Oid tableoid;
1904  AclMode mode;
1905  AclResult aclresult;
1906 
1907  roleid = GetUserId();
1908  tableoid = convert_table_name(tablename);
1909  mode = convert_table_priv_string(priv_type_text);
1910 
1911  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1912 
1913  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1914 }
1915 
1916 /*
1917  * has_table_privilege_name_id
1918  * Check user privileges on a table given
1919  * name usename, table oid, and text priv name.
1920  */
1921 Datum
1923 {
1925  Oid tableoid = PG_GETARG_OID(1);
1926  text *priv_type_text = PG_GETARG_TEXT_PP(2);
1927  Oid roleid;
1928  AclMode mode;
1929  AclResult aclresult;
1930  bool is_missing = false;
1931 
1933  mode = convert_table_priv_string(priv_type_text);
1934 
1935  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
1936 
1937  if (is_missing)
1938  PG_RETURN_NULL();
1939 
1940  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1941 }
1942 
1943 /*
1944  * has_table_privilege_id
1945  * Check user privileges on a table given
1946  * table oid, and text priv name.
1947  * current_user is assumed
1948  */
1949 Datum
1951 {
1952  Oid tableoid = PG_GETARG_OID(0);
1953  text *priv_type_text = PG_GETARG_TEXT_PP(1);
1954  Oid roleid;
1955  AclMode mode;
1956  AclResult aclresult;
1957  bool is_missing = false;
1958 
1959  roleid = GetUserId();
1960  mode = convert_table_priv_string(priv_type_text);
1961 
1962  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
1963 
1964  if (is_missing)
1965  PG_RETURN_NULL();
1966 
1967  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1968 }
1969 
1970 /*
1971  * has_table_privilege_id_name
1972  * Check user privileges on a table given
1973  * roleid, text tablename, and text priv name.
1974  */
1975 Datum
1977 {
1978  Oid roleid = PG_GETARG_OID(0);
1979  text *tablename = PG_GETARG_TEXT_PP(1);
1980  text *priv_type_text = PG_GETARG_TEXT_PP(2);
1981  Oid tableoid;
1982  AclMode mode;
1983  AclResult aclresult;
1984 
1985  tableoid = convert_table_name(tablename);
1986  mode = convert_table_priv_string(priv_type_text);
1987 
1988  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1989 
1990  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1991 }
1992 
1993 /*
1994  * has_table_privilege_id_id
1995  * Check user privileges on a table given
1996  * roleid, table oid, and text priv name.
1997  */
1998 Datum
2000 {
2001  Oid roleid = PG_GETARG_OID(0);
2002  Oid tableoid = PG_GETARG_OID(1);
2003  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2004  AclMode mode;
2005  AclResult aclresult;
2006  bool is_missing = false;
2007 
2008  mode = convert_table_priv_string(priv_type_text);
2009 
2010  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2011 
2012  if (is_missing)
2013  PG_RETURN_NULL();
2014 
2015  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2016 }
2017 
2018 /*
2019  * Support routines for has_table_privilege family.
2020  */
2021 
2022 /*
2023  * Given a table name expressed as a string, look it up and return Oid
2024  */
2025 static Oid
2027 {
2028  RangeVar *relrv;
2029 
2031 
2032  /* We might not even have permissions on this relation; don't lock it. */
2033  return RangeVarGetRelid(relrv, NoLock, false);
2034 }
2035 
2036 /*
2037  * convert_table_priv_string
2038  * Convert text string to AclMode value.
2039  */
2040 static AclMode
2042 {
2043  static const priv_map table_priv_map[] = {
2044  {"SELECT", ACL_SELECT},
2045  {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2046  {"INSERT", ACL_INSERT},
2047  {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2048  {"UPDATE", ACL_UPDATE},
2049  {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2050  {"DELETE", ACL_DELETE},
2051  {"DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE)},
2052  {"TRUNCATE", ACL_TRUNCATE},
2053  {"TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE)},
2054  {"REFERENCES", ACL_REFERENCES},
2055  {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2056  {"TRIGGER", ACL_TRIGGER},
2057  {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
2058  {"MAINTAIN", ACL_MAINTAIN},
2059  {"MAINTAIN WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_MAINTAIN)},
2060  {"RULE", 0}, /* ignore old RULE privileges */
2061  {"RULE WITH GRANT OPTION", 0},
2062  {NULL, 0}
2063  };
2064 
2065  return convert_any_priv_string(priv_type_text, table_priv_map);
2066 }
2067 
2068 /*
2069  * has_sequence_privilege variants
2070  * These are all named "has_sequence_privilege" at the SQL level.
2071  * They take various combinations of relation name, relation OID,
2072  * user name, user OID, or implicit user = current_user.
2073  *
2074  * The result is a boolean value: true if user has the indicated
2075  * privilege, false if not. The variants that take a relation OID
2076  * return NULL if the OID doesn't exist.
2077  */
2078 
2079 /*
2080  * has_sequence_privilege_name_name
2081  * Check user privileges on a sequence given
2082  * name username, text sequencename, and text priv name.
2083  */
2084 Datum
2086 {
2087  Name rolename = PG_GETARG_NAME(0);
2088  text *sequencename = PG_GETARG_TEXT_PP(1);
2089  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2090  Oid roleid;
2091  Oid sequenceoid;
2092  AclMode mode;
2093  AclResult aclresult;
2094 
2095  roleid = get_role_oid_or_public(NameStr(*rolename));
2096  mode = convert_sequence_priv_string(priv_type_text);
2097  sequenceoid = convert_table_name(sequencename);
2098  if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2099  ereport(ERROR,
2100  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2101  errmsg("\"%s\" is not a sequence",
2102  text_to_cstring(sequencename))));
2103 
2104  aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2105 
2106  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2107 }
2108 
2109 /*
2110  * has_sequence_privilege_name
2111  * Check user privileges on a sequence given
2112  * text sequencename and text priv name.
2113  * current_user is assumed
2114  */
2115 Datum
2117 {
2118  text *sequencename = PG_GETARG_TEXT_PP(0);
2119  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2120  Oid roleid;
2121  Oid sequenceoid;
2122  AclMode mode;
2123  AclResult aclresult;
2124 
2125  roleid = GetUserId();
2126  mode = convert_sequence_priv_string(priv_type_text);
2127  sequenceoid = convert_table_name(sequencename);
2128  if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2129  ereport(ERROR,
2130  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2131  errmsg("\"%s\" is not a sequence",
2132  text_to_cstring(sequencename))));
2133 
2134  aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2135 
2136  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2137 }
2138 
2139 /*
2140  * has_sequence_privilege_name_id
2141  * Check user privileges on a sequence given
2142  * name usename, sequence oid, and text priv name.
2143  */
2144 Datum
2146 {
2148  Oid sequenceoid = PG_GETARG_OID(1);
2149  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2150  Oid roleid;
2151  AclMode mode;
2152  AclResult aclresult;
2153  char relkind;
2154  bool is_missing = false;
2155 
2157  mode = convert_sequence_priv_string(priv_type_text);
2158  relkind = get_rel_relkind(sequenceoid);
2159  if (relkind == '\0')
2160  PG_RETURN_NULL();
2161  else if (relkind != RELKIND_SEQUENCE)
2162  ereport(ERROR,
2163  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2164  errmsg("\"%s\" is not a sequence",
2165  get_rel_name(sequenceoid))));
2166 
2167  aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2168 
2169  if (is_missing)
2170  PG_RETURN_NULL();
2171 
2172  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2173 }
2174 
2175 /*
2176  * has_sequence_privilege_id
2177  * Check user privileges on a sequence given
2178  * sequence oid, and text priv name.
2179  * current_user is assumed
2180  */
2181 Datum
2183 {
2184  Oid sequenceoid = PG_GETARG_OID(0);
2185  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2186  Oid roleid;
2187  AclMode mode;
2188  AclResult aclresult;
2189  char relkind;
2190  bool is_missing = false;
2191 
2192  roleid = GetUserId();
2193  mode = convert_sequence_priv_string(priv_type_text);
2194  relkind = get_rel_relkind(sequenceoid);
2195  if (relkind == '\0')
2196  PG_RETURN_NULL();
2197  else if (relkind != RELKIND_SEQUENCE)
2198  ereport(ERROR,
2199  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2200  errmsg("\"%s\" is not a sequence",
2201  get_rel_name(sequenceoid))));
2202 
2203  aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2204 
2205  if (is_missing)
2206  PG_RETURN_NULL();
2207 
2208  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2209 }
2210 
2211 /*
2212  * has_sequence_privilege_id_name
2213  * Check user privileges on a sequence given
2214  * roleid, text sequencename, and text priv name.
2215  */
2216 Datum
2218 {
2219  Oid roleid = PG_GETARG_OID(0);
2220  text *sequencename = PG_GETARG_TEXT_PP(1);
2221  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2222  Oid sequenceoid;
2223  AclMode mode;
2224  AclResult aclresult;
2225 
2226  mode = convert_sequence_priv_string(priv_type_text);
2227  sequenceoid = convert_table_name(sequencename);
2228  if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2229  ereport(ERROR,
2230  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2231  errmsg("\"%s\" is not a sequence",
2232  text_to_cstring(sequencename))));
2233 
2234  aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2235 
2236  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2237 }
2238 
2239 /*
2240  * has_sequence_privilege_id_id
2241  * Check user privileges on a sequence given
2242  * roleid, sequence oid, and text priv name.
2243  */
2244 Datum
2246 {
2247  Oid roleid = PG_GETARG_OID(0);
2248  Oid sequenceoid = PG_GETARG_OID(1);
2249  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2250  AclMode mode;
2251  AclResult aclresult;
2252  char relkind;
2253  bool is_missing = false;
2254 
2255  mode = convert_sequence_priv_string(priv_type_text);
2256  relkind = get_rel_relkind(sequenceoid);
2257  if (relkind == '\0')
2258  PG_RETURN_NULL();
2259  else if (relkind != RELKIND_SEQUENCE)
2260  ereport(ERROR,
2261  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2262  errmsg("\"%s\" is not a sequence",
2263  get_rel_name(sequenceoid))));
2264 
2265  aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2266 
2267  if (is_missing)
2268  PG_RETURN_NULL();
2269 
2270  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2271 }
2272 
2273 /*
2274  * convert_sequence_priv_string
2275  * Convert text string to AclMode value.
2276  */
2277 static AclMode
2279 {
2280  static const priv_map sequence_priv_map[] = {
2281  {"USAGE", ACL_USAGE},
2282  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
2283  {"SELECT", ACL_SELECT},
2284  {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2285  {"UPDATE", ACL_UPDATE},
2286  {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2287  {NULL, 0}
2288  };
2289 
2290  return convert_any_priv_string(priv_type_text, sequence_priv_map);
2291 }
2292 
2293 
2294 /*
2295  * has_any_column_privilege variants
2296  * These are all named "has_any_column_privilege" at the SQL level.
2297  * They take various combinations of relation name, relation OID,
2298  * user name, user OID, or implicit user = current_user.
2299  *
2300  * The result is a boolean value: true if user has the indicated
2301  * privilege for any column of the table, false if not. The variants
2302  * that take a relation OID return NULL if the OID doesn't exist.
2303  */
2304 
2305 /*
2306  * has_any_column_privilege_name_name
2307  * Check user privileges on any column of a table given
2308  * name username, text tablename, and text priv name.
2309  */
2310 Datum
2312 {
2313  Name rolename = PG_GETARG_NAME(0);
2314  text *tablename = PG_GETARG_TEXT_PP(1);
2315  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2316  Oid roleid;
2317  Oid tableoid;
2318  AclMode mode;
2319  AclResult aclresult;
2320 
2321  roleid = get_role_oid_or_public(NameStr(*rolename));
2322  tableoid = convert_table_name(tablename);
2323  mode = convert_column_priv_string(priv_type_text);
2324 
2325  /* First check at table level, then examine each column if needed */
2326  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2327  if (aclresult != ACLCHECK_OK)
2328  aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2329  ACLMASK_ANY);
2330 
2331  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2332 }
2333 
2334 /*
2335  * has_any_column_privilege_name
2336  * Check user privileges on any column of a table given
2337  * text tablename and text priv name.
2338  * current_user is assumed
2339  */
2340 Datum
2342 {
2343  text *tablename = PG_GETARG_TEXT_PP(0);
2344  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2345  Oid roleid;
2346  Oid tableoid;
2347  AclMode mode;
2348  AclResult aclresult;
2349 
2350  roleid = GetUserId();
2351  tableoid = convert_table_name(tablename);
2352  mode = convert_column_priv_string(priv_type_text);
2353 
2354  /* First check at table level, then examine each column if needed */
2355  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2356  if (aclresult != ACLCHECK_OK)
2357  aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2358  ACLMASK_ANY);
2359 
2360  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2361 }
2362 
2363 /*
2364  * has_any_column_privilege_name_id
2365  * Check user privileges on any column of a table given
2366  * name usename, table oid, and text priv name.
2367  */
2368 Datum
2370 {
2372  Oid tableoid = PG_GETARG_OID(1);
2373  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2374  Oid roleid;
2375  AclMode mode;
2376  AclResult aclresult;
2377  bool is_missing = false;
2378 
2380  mode = convert_column_priv_string(priv_type_text);
2381 
2382  /* First check at table level, then examine each column if needed */
2383  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2384  if (aclresult != ACLCHECK_OK)
2385  {
2386  if (is_missing)
2387  PG_RETURN_NULL();
2388  aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2389  ACLMASK_ANY, &is_missing);
2390  if (is_missing)
2391  PG_RETURN_NULL();
2392  }
2393 
2394  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2395 }
2396 
2397 /*
2398  * has_any_column_privilege_id
2399  * Check user privileges on any column of a table given
2400  * table oid, and text priv name.
2401  * current_user is assumed
2402  */
2403 Datum
2405 {
2406  Oid tableoid = PG_GETARG_OID(0);
2407  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2408  Oid roleid;
2409  AclMode mode;
2410  AclResult aclresult;
2411  bool is_missing = false;
2412 
2413  roleid = GetUserId();
2414  mode = convert_column_priv_string(priv_type_text);
2415 
2416  /* First check at table level, then examine each column if needed */
2417  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2418  if (aclresult != ACLCHECK_OK)
2419  {
2420  if (is_missing)
2421  PG_RETURN_NULL();
2422  aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2423  ACLMASK_ANY, &is_missing);
2424  if (is_missing)
2425  PG_RETURN_NULL();
2426  }
2427 
2428  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2429 }
2430 
2431 /*
2432  * has_any_column_privilege_id_name
2433  * Check user privileges on any column of a table given
2434  * roleid, text tablename, and text priv name.
2435  */
2436 Datum
2438 {
2439  Oid roleid = PG_GETARG_OID(0);
2440  text *tablename = PG_GETARG_TEXT_PP(1);
2441  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2442  Oid tableoid;
2443  AclMode mode;
2444  AclResult aclresult;
2445 
2446  tableoid = convert_table_name(tablename);
2447  mode = convert_column_priv_string(priv_type_text);
2448 
2449  /* First check at table level, then examine each column if needed */
2450  aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2451  if (aclresult != ACLCHECK_OK)
2452  aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2453  ACLMASK_ANY);
2454 
2455  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2456 }
2457 
2458 /*
2459  * has_any_column_privilege_id_id
2460  * Check user privileges on any column of a table given
2461  * roleid, table oid, and text priv name.
2462  */
2463 Datum
2465 {
2466  Oid roleid = PG_GETARG_OID(0);
2467  Oid tableoid = PG_GETARG_OID(1);
2468  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2469  AclMode mode;
2470  AclResult aclresult;
2471  bool is_missing = false;
2472 
2473  mode = convert_column_priv_string(priv_type_text);
2474 
2475  /* First check at table level, then examine each column if needed */
2476  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2477  if (aclresult != ACLCHECK_OK)
2478  {
2479  if (is_missing)
2480  PG_RETURN_NULL();
2481  aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2482  ACLMASK_ANY, &is_missing);
2483  if (is_missing)
2484  PG_RETURN_NULL();
2485  }
2486 
2487  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2488 }
2489 
2490 
2491 /*
2492  * has_column_privilege variants
2493  * These are all named "has_column_privilege" at the SQL level.
2494  * They take various combinations of relation name, relation OID,
2495  * column name, column attnum, user name, user OID, or
2496  * implicit user = current_user.
2497  *
2498  * The result is a boolean value: true if user has the indicated
2499  * privilege, false if not. The variants that take a relation OID
2500  * return NULL (rather than throwing an error) if that relation OID
2501  * doesn't exist. Likewise, the variants that take an integer attnum
2502  * return NULL (rather than throwing an error) if there is no such
2503  * pg_attribute entry. All variants return NULL if an attisdropped
2504  * column is selected. These rules are meant to avoid unnecessary
2505  * failures in queries that scan pg_attribute.
2506  */
2507 
2508 /*
2509  * column_privilege_check: check column privileges, but don't throw an error
2510  * for dropped column or table
2511  *
2512  * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
2513  */
2514 static int
2516  Oid roleid, AclMode mode)
2517 {
2518  AclResult aclresult;
2519  bool is_missing = false;
2520 
2521  /*
2522  * If convert_column_name failed, we can just return -1 immediately.
2523  */
2524  if (attnum == InvalidAttrNumber)
2525  return -1;
2526 
2527  /*
2528  * Check for column-level privileges first. This serves in part as a check
2529  * on whether the column even exists, so we need to do it before checking
2530  * table-level privilege.
2531  */
2532  aclresult = pg_attribute_aclcheck_ext(tableoid, attnum, roleid,
2533  mode, &is_missing);
2534  if (aclresult == ACLCHECK_OK)
2535  return 1;
2536  else if (is_missing)
2537  return -1;
2538 
2539  /* Next check if we have the privilege at the table level */
2540  aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2541  if (aclresult == ACLCHECK_OK)
2542  return 1;
2543  else if (is_missing)
2544  return -1;
2545  else
2546  return 0;
2547 }
2548 
2549 /*
2550  * has_column_privilege_name_name_name
2551  * Check user privileges on a column given
2552  * name username, text tablename, text colname, and text priv name.
2553  */
2554 Datum
2556 {
2557  Name rolename = PG_GETARG_NAME(0);
2558  text *tablename = PG_GETARG_TEXT_PP(1);
2559  text *column = PG_GETARG_TEXT_PP(2);
2560  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2561  Oid roleid;
2562  Oid tableoid;
2563  AttrNumber colattnum;
2564  AclMode mode;
2565  int privresult;
2566 
2567  roleid = get_role_oid_or_public(NameStr(*rolename));
2568  tableoid = convert_table_name(tablename);
2569  colattnum = convert_column_name(tableoid, column);
2570  mode = convert_column_priv_string(priv_type_text);
2571 
2572  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2573  if (privresult < 0)
2574  PG_RETURN_NULL();
2575  PG_RETURN_BOOL(privresult);
2576 }
2577 
2578 /*
2579  * has_column_privilege_name_name_attnum
2580  * Check user privileges on a column given
2581  * name username, text tablename, int attnum, and text priv name.
2582  */
2583 Datum
2585 {
2586  Name rolename = PG_GETARG_NAME(0);
2587  text *tablename = PG_GETARG_TEXT_PP(1);
2588  AttrNumber colattnum = PG_GETARG_INT16(2);
2589  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2590  Oid roleid;
2591  Oid tableoid;
2592  AclMode mode;
2593  int privresult;
2594 
2595  roleid = get_role_oid_or_public(NameStr(*rolename));
2596  tableoid = convert_table_name(tablename);
2597  mode = convert_column_priv_string(priv_type_text);
2598 
2599  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2600  if (privresult < 0)
2601  PG_RETURN_NULL();
2602  PG_RETURN_BOOL(privresult);
2603 }
2604 
2605 /*
2606  * has_column_privilege_name_id_name
2607  * Check user privileges on a column given
2608  * name username, table oid, text colname, and text priv name.
2609  */
2610 Datum
2612 {
2614  Oid tableoid = PG_GETARG_OID(1);
2615  text *column = PG_GETARG_TEXT_PP(2);
2616  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2617  Oid roleid;
2618  AttrNumber colattnum;
2619  AclMode mode;
2620  int privresult;
2621 
2623  colattnum = convert_column_name(tableoid, column);
2624  mode = convert_column_priv_string(priv_type_text);
2625 
2626  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2627  if (privresult < 0)
2628  PG_RETURN_NULL();
2629  PG_RETURN_BOOL(privresult);
2630 }
2631 
2632 /*
2633  * has_column_privilege_name_id_attnum
2634  * Check user privileges on a column given
2635  * name username, table oid, int attnum, and text priv name.
2636  */
2637 Datum
2639 {
2641  Oid tableoid = PG_GETARG_OID(1);
2642  AttrNumber colattnum = PG_GETARG_INT16(2);
2643  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2644  Oid roleid;
2645  AclMode mode;
2646  int privresult;
2647 
2649  mode = convert_column_priv_string(priv_type_text);
2650 
2651  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2652  if (privresult < 0)
2653  PG_RETURN_NULL();
2654  PG_RETURN_BOOL(privresult);
2655 }
2656 
2657 /*
2658  * has_column_privilege_id_name_name
2659  * Check user privileges on a column given
2660  * oid roleid, text tablename, text colname, and text priv name.
2661  */
2662 Datum
2664 {
2665  Oid roleid = PG_GETARG_OID(0);
2666  text *tablename = PG_GETARG_TEXT_PP(1);
2667  text *column = PG_GETARG_TEXT_PP(2);
2668  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2669  Oid tableoid;
2670  AttrNumber colattnum;
2671  AclMode mode;
2672  int privresult;
2673 
2674  tableoid = convert_table_name(tablename);
2675  colattnum = convert_column_name(tableoid, column);
2676  mode = convert_column_priv_string(priv_type_text);
2677 
2678  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2679  if (privresult < 0)
2680  PG_RETURN_NULL();
2681  PG_RETURN_BOOL(privresult);
2682 }
2683 
2684 /*
2685  * has_column_privilege_id_name_attnum
2686  * Check user privileges on a column given
2687  * oid roleid, text tablename, int attnum, and text priv name.
2688  */
2689 Datum
2691 {
2692  Oid roleid = PG_GETARG_OID(0);
2693  text *tablename = PG_GETARG_TEXT_PP(1);
2694  AttrNumber colattnum = PG_GETARG_INT16(2);
2695  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2696  Oid tableoid;
2697  AclMode mode;
2698  int privresult;
2699 
2700  tableoid = convert_table_name(tablename);
2701  mode = convert_column_priv_string(priv_type_text);
2702 
2703  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2704  if (privresult < 0)
2705  PG_RETURN_NULL();
2706  PG_RETURN_BOOL(privresult);
2707 }
2708 
2709 /*
2710  * has_column_privilege_id_id_name
2711  * Check user privileges on a column given
2712  * oid roleid, table oid, text colname, and text priv name.
2713  */
2714 Datum
2716 {
2717  Oid roleid = PG_GETARG_OID(0);
2718  Oid tableoid = PG_GETARG_OID(1);
2719  text *column = PG_GETARG_TEXT_PP(2);
2720  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2721  AttrNumber colattnum;
2722  AclMode mode;
2723  int privresult;
2724 
2725  colattnum = convert_column_name(tableoid, column);
2726  mode = convert_column_priv_string(priv_type_text);
2727 
2728  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2729  if (privresult < 0)
2730  PG_RETURN_NULL();
2731  PG_RETURN_BOOL(privresult);
2732 }
2733 
2734 /*
2735  * has_column_privilege_id_id_attnum
2736  * Check user privileges on a column given
2737  * oid roleid, table oid, int attnum, and text priv name.
2738  */
2739 Datum
2741 {
2742  Oid roleid = PG_GETARG_OID(0);
2743  Oid tableoid = PG_GETARG_OID(1);
2744  AttrNumber colattnum = PG_GETARG_INT16(2);
2745  text *priv_type_text = PG_GETARG_TEXT_PP(3);
2746  AclMode mode;
2747  int privresult;
2748 
2749  mode = convert_column_priv_string(priv_type_text);
2750 
2751  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2752  if (privresult < 0)
2753  PG_RETURN_NULL();
2754  PG_RETURN_BOOL(privresult);
2755 }
2756 
2757 /*
2758  * has_column_privilege_name_name
2759  * Check user privileges on a column given
2760  * text tablename, text colname, and text priv name.
2761  * current_user is assumed
2762  */
2763 Datum
2765 {
2766  text *tablename = PG_GETARG_TEXT_PP(0);
2767  text *column = PG_GETARG_TEXT_PP(1);
2768  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2769  Oid roleid;
2770  Oid tableoid;
2771  AttrNumber colattnum;
2772  AclMode mode;
2773  int privresult;
2774 
2775  roleid = GetUserId();
2776  tableoid = convert_table_name(tablename);
2777  colattnum = convert_column_name(tableoid, column);
2778  mode = convert_column_priv_string(priv_type_text);
2779 
2780  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2781  if (privresult < 0)
2782  PG_RETURN_NULL();
2783  PG_RETURN_BOOL(privresult);
2784 }
2785 
2786 /*
2787  * has_column_privilege_name_attnum
2788  * Check user privileges on a column given
2789  * text tablename, int attnum, and text priv name.
2790  * current_user is assumed
2791  */
2792 Datum
2794 {
2795  text *tablename = PG_GETARG_TEXT_PP(0);
2796  AttrNumber colattnum = PG_GETARG_INT16(1);
2797  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2798  Oid roleid;
2799  Oid tableoid;
2800  AclMode mode;
2801  int privresult;
2802 
2803  roleid = GetUserId();
2804  tableoid = convert_table_name(tablename);
2805  mode = convert_column_priv_string(priv_type_text);
2806 
2807  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2808  if (privresult < 0)
2809  PG_RETURN_NULL();
2810  PG_RETURN_BOOL(privresult);
2811 }
2812 
2813 /*
2814  * has_column_privilege_id_name
2815  * Check user privileges on a column given
2816  * table oid, text colname, and text priv name.
2817  * current_user is assumed
2818  */
2819 Datum
2821 {
2822  Oid tableoid = PG_GETARG_OID(0);
2823  text *column = PG_GETARG_TEXT_PP(1);
2824  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2825  Oid roleid;
2826  AttrNumber colattnum;
2827  AclMode mode;
2828  int privresult;
2829 
2830  roleid = GetUserId();
2831  colattnum = convert_column_name(tableoid, column);
2832  mode = convert_column_priv_string(priv_type_text);
2833 
2834  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2835  if (privresult < 0)
2836  PG_RETURN_NULL();
2837  PG_RETURN_BOOL(privresult);
2838 }
2839 
2840 /*
2841  * has_column_privilege_id_attnum
2842  * Check user privileges on a column given
2843  * table oid, int attnum, and text priv name.
2844  * current_user is assumed
2845  */
2846 Datum
2848 {
2849  Oid tableoid = PG_GETARG_OID(0);
2850  AttrNumber colattnum = PG_GETARG_INT16(1);
2851  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2852  Oid roleid;
2853  AclMode mode;
2854  int privresult;
2855 
2856  roleid = GetUserId();
2857  mode = convert_column_priv_string(priv_type_text);
2858 
2859  privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2860  if (privresult < 0)
2861  PG_RETURN_NULL();
2862  PG_RETURN_BOOL(privresult);
2863 }
2864 
2865 /*
2866  * Support routines for has_column_privilege family.
2867  */
2868 
2869 /*
2870  * Given a table OID and a column name expressed as a string, look it up
2871  * and return the column number. Returns InvalidAttrNumber in cases
2872  * where caller should return NULL instead of failing.
2873  */
2874 static AttrNumber
2875 convert_column_name(Oid tableoid, text *column)
2876 {
2877  char *colname;
2878  HeapTuple attTuple;
2880 
2881  colname = text_to_cstring(column);
2882 
2883  /*
2884  * We don't use get_attnum() here because it will report that dropped
2885  * columns don't exist. We need to treat dropped columns differently from
2886  * nonexistent columns.
2887  */
2888  attTuple = SearchSysCache2(ATTNAME,
2889  ObjectIdGetDatum(tableoid),
2890  CStringGetDatum(colname));
2891  if (HeapTupleIsValid(attTuple))
2892  {
2893  Form_pg_attribute attributeForm;
2894 
2895  attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
2896  /* We want to return NULL for dropped columns */
2897  if (attributeForm->attisdropped)
2899  else
2900  attnum = attributeForm->attnum;
2901  ReleaseSysCache(attTuple);
2902  }
2903  else
2904  {
2905  char *tablename = get_rel_name(tableoid);
2906 
2907  /*
2908  * If the table OID is bogus, or it's just been dropped, we'll get
2909  * NULL back. In such cases we want has_column_privilege to return
2910  * NULL too, so just return InvalidAttrNumber.
2911  */
2912  if (tablename != NULL)
2913  {
2914  /* tableoid exists, colname does not, so throw error */
2915  ereport(ERROR,
2916  (errcode(ERRCODE_UNDEFINED_COLUMN),
2917  errmsg("column \"%s\" of relation \"%s\" does not exist",
2918  colname, tablename)));
2919  }
2920  /* tableoid doesn't exist, so act like attisdropped case */
2922  }
2923 
2924  pfree(colname);
2925  return attnum;
2926 }
2927 
2928 /*
2929  * convert_column_priv_string
2930  * Convert text string to AclMode value.
2931  */
2932 static AclMode
2934 {
2935  static const priv_map column_priv_map[] = {
2936  {"SELECT", ACL_SELECT},
2937  {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2938  {"INSERT", ACL_INSERT},
2939  {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2940  {"UPDATE", ACL_UPDATE},
2941  {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2942  {"REFERENCES", ACL_REFERENCES},
2943  {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2944  {NULL, 0}
2945  };
2946 
2947  return convert_any_priv_string(priv_type_text, column_priv_map);
2948 }
2949 
2950 
2951 /*
2952  * has_database_privilege variants
2953  * These are all named "has_database_privilege" at the SQL level.
2954  * They take various combinations of database name, database OID,
2955  * user name, user OID, or implicit user = current_user.
2956  *
2957  * The result is a boolean value: true if user has the indicated
2958  * privilege, false if not, or NULL if object doesn't exist.
2959  */
2960 
2961 /*
2962  * has_database_privilege_name_name
2963  * Check user privileges on a database given
2964  * name username, text databasename, and text priv name.
2965  */
2966 Datum
2968 {
2970  text *databasename = PG_GETARG_TEXT_PP(1);
2971  text *priv_type_text = PG_GETARG_TEXT_PP(2);
2972  Oid roleid;
2973  Oid databaseoid;
2974  AclMode mode;
2975  AclResult aclresult;
2976 
2978  databaseoid = convert_database_name(databasename);
2979  mode = convert_database_priv_string(priv_type_text);
2980 
2981  aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
2982 
2983  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2984 }
2985 
2986 /*
2987  * has_database_privilege_name
2988  * Check user privileges on a database given
2989  * text databasename and text priv name.
2990  * current_user is assumed
2991  */
2992 Datum
2994 {
2995  text *databasename = PG_GETARG_TEXT_PP(0);
2996  text *priv_type_text = PG_GETARG_TEXT_PP(1);
2997  Oid roleid;
2998  Oid databaseoid;
2999  AclMode mode;
3000  AclResult aclresult;
3001 
3002  roleid = GetUserId();
3003  databaseoid = convert_database_name(databasename);
3004  mode = convert_database_priv_string(priv_type_text);
3005 
3006  aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3007 
3008  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3009 }
3010 
3011 /*
3012  * has_database_privilege_name_id
3013  * Check user privileges on a database given
3014  * name usename, database oid, and text priv name.
3015  */
3016 Datum
3018 {
3020  Oid databaseoid = PG_GETARG_OID(1);
3021  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3022  Oid roleid;
3023  AclMode mode;
3024  AclResult aclresult;
3025  bool is_missing = false;
3026 
3028  mode = convert_database_priv_string(priv_type_text);
3029 
3030  aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3031  roleid, mode,
3032  &is_missing);
3033 
3034  if (is_missing)
3035  PG_RETURN_NULL();
3036 
3037  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3038 }
3039 
3040 /*
3041  * has_database_privilege_id
3042  * Check user privileges on a database given
3043  * database oid, and text priv name.
3044  * current_user is assumed
3045  */
3046 Datum
3048 {
3049  Oid databaseoid = PG_GETARG_OID(0);
3050  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3051  Oid roleid;
3052  AclMode mode;
3053  AclResult aclresult;
3054  bool is_missing = false;
3055 
3056  roleid = GetUserId();
3057  mode = convert_database_priv_string(priv_type_text);
3058 
3059  aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3060  roleid, mode,
3061  &is_missing);
3062 
3063  if (is_missing)
3064  PG_RETURN_NULL();
3065 
3066  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3067 }
3068 
3069 /*
3070  * has_database_privilege_id_name
3071  * Check user privileges on a database given
3072  * roleid, text databasename, and text priv name.
3073  */
3074 Datum
3076 {
3077  Oid roleid = PG_GETARG_OID(0);
3078  text *databasename = PG_GETARG_TEXT_PP(1);
3079  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3080  Oid databaseoid;
3081  AclMode mode;
3082  AclResult aclresult;
3083 
3084  databaseoid = convert_database_name(databasename);
3085  mode = convert_database_priv_string(priv_type_text);
3086 
3087  aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3088 
3089  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3090 }
3091 
3092 /*
3093  * has_database_privilege_id_id
3094  * Check user privileges on a database given
3095  * roleid, database oid, and text priv name.
3096  */
3097 Datum
3099 {
3100  Oid roleid = PG_GETARG_OID(0);
3101  Oid databaseoid = PG_GETARG_OID(1);
3102  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3103  AclMode mode;
3104  AclResult aclresult;
3105  bool is_missing = false;
3106 
3107  mode = convert_database_priv_string(priv_type_text);
3108 
3109  aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3110  roleid, mode,
3111  &is_missing);
3112 
3113  if (is_missing)
3114  PG_RETURN_NULL();
3115 
3116  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3117 }
3118 
3119 /*
3120  * Support routines for has_database_privilege family.
3121  */
3122 
3123 /*
3124  * Given a database name expressed as a string, look it up and return Oid
3125  */
3126 static Oid
3128 {
3129  char *dbname = text_to_cstring(databasename);
3130 
3131  return get_database_oid(dbname, false);
3132 }
3133 
3134 /*
3135  * convert_database_priv_string
3136  * Convert text string to AclMode value.
3137  */
3138 static AclMode
3140 {
3141  static const priv_map database_priv_map[] = {
3142  {"CREATE", ACL_CREATE},
3143  {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
3144  {"TEMPORARY", ACL_CREATE_TEMP},
3145  {"TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
3146  {"TEMP", ACL_CREATE_TEMP},
3147  {"TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
3148  {"CONNECT", ACL_CONNECT},
3149  {"CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT)},
3150  {NULL, 0}
3151  };
3152 
3153  return convert_any_priv_string(priv_type_text, database_priv_map);
3154 }
3155 
3156 
3157 /*
3158  * has_foreign_data_wrapper_privilege variants
3159  * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
3160  * They take various combinations of foreign-data wrapper name,
3161  * fdw OID, user name, user OID, or implicit user = current_user.
3162  *
3163  * The result is a boolean value: true if user has the indicated
3164  * privilege, false if not.
3165  */
3166 
3167 /*
3168  * has_foreign_data_wrapper_privilege_name_name
3169  * Check user privileges on a foreign-data wrapper given
3170  * name username, text fdwname, and text priv name.
3171  */
3172 Datum
3174 {
3176  text *fdwname = PG_GETARG_TEXT_PP(1);
3177  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3178  Oid roleid;
3179  Oid fdwid;
3180  AclMode mode;
3181  AclResult aclresult;
3182 
3184  fdwid = convert_foreign_data_wrapper_name(fdwname);
3186 
3187  aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3188 
3189  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3190 }
3191 
3192 /*
3193  * has_foreign_data_wrapper_privilege_name
3194  * Check user privileges on a foreign-data wrapper given
3195  * text fdwname and text priv name.
3196  * current_user is assumed
3197  */
3198 Datum
3200 {
3201  text *fdwname = PG_GETARG_TEXT_PP(0);
3202  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3203  Oid roleid;
3204  Oid fdwid;
3205  AclMode mode;
3206  AclResult aclresult;
3207 
3208  roleid = GetUserId();
3209  fdwid = convert_foreign_data_wrapper_name(fdwname);
3211 
3212  aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3213 
3214  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3215 }
3216 
3217 /*
3218  * has_foreign_data_wrapper_privilege_name_id
3219  * Check user privileges on a foreign-data wrapper given
3220  * name usename, foreign-data wrapper oid, and text priv name.
3221  */
3222 Datum
3224 {
3226  Oid fdwid = PG_GETARG_OID(1);
3227  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3228  Oid roleid;
3229  AclMode mode;
3230  AclResult aclresult;
3231  bool is_missing = false;
3232 
3235 
3236  aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3237  roleid, mode,
3238  &is_missing);
3239 
3240  if (is_missing)
3241  PG_RETURN_NULL();
3242 
3243  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3244 }
3245 
3246 /*
3247  * has_foreign_data_wrapper_privilege_id
3248  * Check user privileges on a foreign-data wrapper given
3249  * foreign-data wrapper oid, and text priv name.
3250  * current_user is assumed
3251  */
3252 Datum
3254 {
3255  Oid fdwid = PG_GETARG_OID(0);
3256  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3257  Oid roleid;
3258  AclMode mode;
3259  AclResult aclresult;
3260  bool is_missing = false;
3261 
3262  roleid = GetUserId();
3264 
3265  aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3266  roleid, mode,
3267  &is_missing);
3268 
3269  if (is_missing)
3270  PG_RETURN_NULL();
3271 
3272  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3273 }
3274 
3275 /*
3276  * has_foreign_data_wrapper_privilege_id_name
3277  * Check user privileges on a foreign-data wrapper given
3278  * roleid, text fdwname, and text priv name.
3279  */
3280 Datum
3282 {
3283  Oid roleid = PG_GETARG_OID(0);
3284  text *fdwname = PG_GETARG_TEXT_PP(1);
3285  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3286  Oid fdwid;
3287  AclMode mode;
3288  AclResult aclresult;
3289 
3290  fdwid = convert_foreign_data_wrapper_name(fdwname);
3292 
3293  aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3294 
3295  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3296 }
3297 
3298 /*
3299  * has_foreign_data_wrapper_privilege_id_id
3300  * Check user privileges on a foreign-data wrapper given
3301  * roleid, fdw oid, and text priv name.
3302  */
3303 Datum
3305 {
3306  Oid roleid = PG_GETARG_OID(0);
3307  Oid fdwid = PG_GETARG_OID(1);
3308  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3309  AclMode mode;
3310  AclResult aclresult;
3311  bool is_missing = false;
3312 
3314 
3315  aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3316  roleid, mode,
3317  &is_missing);
3318 
3319  if (is_missing)
3320  PG_RETURN_NULL();
3321 
3322  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3323 }
3324 
3325 /*
3326  * Support routines for has_foreign_data_wrapper_privilege family.
3327  */
3328 
3329 /*
3330  * Given a FDW name expressed as a string, look it up and return Oid
3331  */
3332 static Oid
3334 {
3335  char *fdwstr = text_to_cstring(fdwname);
3336 
3337  return get_foreign_data_wrapper_oid(fdwstr, false);
3338 }
3339 
3340 /*
3341  * convert_foreign_data_wrapper_priv_string
3342  * Convert text string to AclMode value.
3343  */
3344 static AclMode
3346 {
3347  static const priv_map foreign_data_wrapper_priv_map[] = {
3348  {"USAGE", ACL_USAGE},
3349  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3350  {NULL, 0}
3351  };
3352 
3353  return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
3354 }
3355 
3356 
3357 /*
3358  * has_function_privilege variants
3359  * These are all named "has_function_privilege" at the SQL level.
3360  * They take various combinations of function name, function OID,
3361  * user name, user OID, or implicit user = current_user.
3362  *
3363  * The result is a boolean value: true if user has the indicated
3364  * privilege, false if not, or NULL if object doesn't exist.
3365  */
3366 
3367 /*
3368  * has_function_privilege_name_name
3369  * Check user privileges on a function given
3370  * name username, text functionname, and text priv name.
3371  */
3372 Datum
3374 {
3376  text *functionname = PG_GETARG_TEXT_PP(1);
3377  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3378  Oid roleid;
3379  Oid functionoid;
3380  AclMode mode;
3381  AclResult aclresult;
3382 
3384  functionoid = convert_function_name(functionname);
3385  mode = convert_function_priv_string(priv_type_text);
3386 
3387  aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3388 
3389  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3390 }
3391 
3392 /*
3393  * has_function_privilege_name
3394  * Check user privileges on a function given
3395  * text functionname and text priv name.
3396  * current_user is assumed
3397  */
3398 Datum
3400 {
3401  text *functionname = PG_GETARG_TEXT_PP(0);
3402  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3403  Oid roleid;
3404  Oid functionoid;
3405  AclMode mode;
3406  AclResult aclresult;
3407 
3408  roleid = GetUserId();
3409  functionoid = convert_function_name(functionname);
3410  mode = convert_function_priv_string(priv_type_text);
3411 
3412  aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3413 
3414  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3415 }
3416 
3417 /*
3418  * has_function_privilege_name_id
3419  * Check user privileges on a function given
3420  * name usename, function oid, and text priv name.
3421  */
3422 Datum
3424 {
3426  Oid functionoid = PG_GETARG_OID(1);
3427  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3428  Oid roleid;
3429  AclMode mode;
3430  AclResult aclresult;
3431  bool is_missing = false;
3432 
3434  mode = convert_function_priv_string(priv_type_text);
3435 
3436  aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3437  roleid, mode,
3438  &is_missing);
3439 
3440  if (is_missing)
3441  PG_RETURN_NULL();
3442 
3443  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3444 }
3445 
3446 /*
3447  * has_function_privilege_id
3448  * Check user privileges on a function given
3449  * function oid, and text priv name.
3450  * current_user is assumed
3451  */
3452 Datum
3454 {
3455  Oid functionoid = PG_GETARG_OID(0);
3456  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3457  Oid roleid;
3458  AclMode mode;
3459  AclResult aclresult;
3460  bool is_missing = false;
3461 
3462  roleid = GetUserId();
3463  mode = convert_function_priv_string(priv_type_text);
3464 
3465  aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3466  roleid, mode,
3467  &is_missing);
3468 
3469  if (is_missing)
3470  PG_RETURN_NULL();
3471 
3472  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3473 }
3474 
3475 /*
3476  * has_function_privilege_id_name
3477  * Check user privileges on a function given
3478  * roleid, text functionname, and text priv name.
3479  */
3480 Datum
3482 {
3483  Oid roleid = PG_GETARG_OID(0);
3484  text *functionname = PG_GETARG_TEXT_PP(1);
3485  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3486  Oid functionoid;
3487  AclMode mode;
3488  AclResult aclresult;
3489 
3490  functionoid = convert_function_name(functionname);
3491  mode = convert_function_priv_string(priv_type_text);
3492 
3493  aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3494 
3495  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3496 }
3497 
3498 /*
3499  * has_function_privilege_id_id
3500  * Check user privileges on a function given
3501  * roleid, function oid, and text priv name.
3502  */
3503 Datum
3505 {
3506  Oid roleid = PG_GETARG_OID(0);
3507  Oid functionoid = PG_GETARG_OID(1);
3508  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3509  AclMode mode;
3510  AclResult aclresult;
3511  bool is_missing = false;
3512 
3513  mode = convert_function_priv_string(priv_type_text);
3514 
3515  aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3516  roleid, mode,
3517  &is_missing);
3518 
3519  if (is_missing)
3520  PG_RETURN_NULL();
3521 
3522  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3523 }
3524 
3525 /*
3526  * Support routines for has_function_privilege family.
3527  */
3528 
3529 /*
3530  * Given a function name expressed as a string, look it up and return Oid
3531  */
3532 static Oid
3534 {
3535  char *funcname = text_to_cstring(functionname);
3536  Oid oid;
3537 
3540 
3541  if (!OidIsValid(oid))
3542  ereport(ERROR,
3543  (errcode(ERRCODE_UNDEFINED_FUNCTION),
3544  errmsg("function \"%s\" does not exist", funcname)));
3545 
3546  return oid;
3547 }
3548 
3549 /*
3550  * convert_function_priv_string
3551  * Convert text string to AclMode value.
3552  */
3553 static AclMode
3555 {
3556  static const priv_map function_priv_map[] = {
3557  {"EXECUTE", ACL_EXECUTE},
3558  {"EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE)},
3559  {NULL, 0}
3560  };
3561 
3562  return convert_any_priv_string(priv_type_text, function_priv_map);
3563 }
3564 
3565 
3566 /*
3567  * has_language_privilege variants
3568  * These are all named "has_language_privilege" at the SQL level.
3569  * They take various combinations of language name, language OID,
3570  * user name, user OID, or implicit user = current_user.
3571  *
3572  * The result is a boolean value: true if user has the indicated
3573  * privilege, false if not, or NULL if object doesn't exist.
3574  */
3575 
3576 /*
3577  * has_language_privilege_name_name
3578  * Check user privileges on a language given
3579  * name username, text languagename, and text priv name.
3580  */
3581 Datum
3583 {
3585  text *languagename = PG_GETARG_TEXT_PP(1);
3586  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3587  Oid roleid;
3588  Oid languageoid;
3589  AclMode mode;
3590  AclResult aclresult;
3591 
3593  languageoid = convert_language_name(languagename);
3594  mode = convert_language_priv_string(priv_type_text);
3595 
3596  aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3597 
3598  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3599 }
3600 
3601 /*
3602  * has_language_privilege_name
3603  * Check user privileges on a language given
3604  * text languagename and text priv name.
3605  * current_user is assumed
3606  */
3607 Datum
3609 {
3610  text *languagename = PG_GETARG_TEXT_PP(0);
3611  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3612  Oid roleid;
3613  Oid languageoid;
3614  AclMode mode;
3615  AclResult aclresult;
3616 
3617  roleid = GetUserId();
3618  languageoid = convert_language_name(languagename);
3619  mode = convert_language_priv_string(priv_type_text);
3620 
3621  aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3622 
3623  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3624 }
3625 
3626 /*
3627  * has_language_privilege_name_id
3628  * Check user privileges on a language given
3629  * name usename, language oid, and text priv name.
3630  */
3631 Datum
3633 {
3635  Oid languageoid = PG_GETARG_OID(1);
3636  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3637  Oid roleid;
3638  AclMode mode;
3639  AclResult aclresult;
3640  bool is_missing = false;
3641 
3643  mode = convert_language_priv_string(priv_type_text);
3644 
3645  aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3646  roleid, mode,
3647  &is_missing);
3648 
3649  if (is_missing)
3650  PG_RETURN_NULL();
3651 
3652  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3653 }
3654 
3655 /*
3656  * has_language_privilege_id
3657  * Check user privileges on a language given
3658  * language oid, and text priv name.
3659  * current_user is assumed
3660  */
3661 Datum
3663 {
3664  Oid languageoid = PG_GETARG_OID(0);
3665  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3666  Oid roleid;
3667  AclMode mode;
3668  AclResult aclresult;
3669  bool is_missing = false;
3670 
3671  roleid = GetUserId();
3672  mode = convert_language_priv_string(priv_type_text);
3673 
3674  aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3675  roleid, mode,
3676  &is_missing);
3677 
3678  if (is_missing)
3679  PG_RETURN_NULL();
3680 
3681  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3682 }
3683 
3684 /*
3685  * has_language_privilege_id_name
3686  * Check user privileges on a language given
3687  * roleid, text languagename, and text priv name.
3688  */
3689 Datum
3691 {
3692  Oid roleid = PG_GETARG_OID(0);
3693  text *languagename = PG_GETARG_TEXT_PP(1);
3694  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3695  Oid languageoid;
3696  AclMode mode;
3697  AclResult aclresult;
3698 
3699  languageoid = convert_language_name(languagename);
3700  mode = convert_language_priv_string(priv_type_text);
3701 
3702  aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3703 
3704  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3705 }
3706 
3707 /*
3708  * has_language_privilege_id_id
3709  * Check user privileges on a language given
3710  * roleid, language oid, and text priv name.
3711  */
3712 Datum
3714 {
3715  Oid roleid = PG_GETARG_OID(0);
3716  Oid languageoid = PG_GETARG_OID(1);
3717  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3718  AclMode mode;
3719  AclResult aclresult;
3720  bool is_missing = false;
3721 
3722  mode = convert_language_priv_string(priv_type_text);
3723 
3724  aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3725  roleid, mode,
3726  &is_missing);
3727 
3728  if (is_missing)
3729  PG_RETURN_NULL();
3730 
3731  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3732 }
3733 
3734 /*
3735  * Support routines for has_language_privilege family.
3736  */
3737 
3738 /*
3739  * Given a language name expressed as a string, look it up and return Oid
3740  */
3741 static Oid
3743 {
3744  char *langname = text_to_cstring(languagename);
3745 
3746  return get_language_oid(langname, false);
3747 }
3748 
3749 /*
3750  * convert_language_priv_string
3751  * Convert text string to AclMode value.
3752  */
3753 static AclMode
3755 {
3756  static const priv_map language_priv_map[] = {
3757  {"USAGE", ACL_USAGE},
3758  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3759  {NULL, 0}
3760  };
3761 
3762  return convert_any_priv_string(priv_type_text, language_priv_map);
3763 }
3764 
3765 
3766 /*
3767  * has_schema_privilege variants
3768  * These are all named "has_schema_privilege" at the SQL level.
3769  * They take various combinations of schema name, schema OID,
3770  * user name, user OID, or implicit user = current_user.
3771  *
3772  * The result is a boolean value: true if user has the indicated
3773  * privilege, false if not, or NULL if object doesn't exist.
3774  */
3775 
3776 /*
3777  * has_schema_privilege_name_name
3778  * Check user privileges on a schema given
3779  * name username, text schemaname, and text priv name.
3780  */
3781 Datum
3783 {
3785  text *schemaname = PG_GETARG_TEXT_PP(1);
3786  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3787  Oid roleid;
3788  Oid schemaoid;
3789  AclMode mode;
3790  AclResult aclresult;
3791 
3793  schemaoid = convert_schema_name(schemaname);
3794  mode = convert_schema_priv_string(priv_type_text);
3795 
3796  aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3797 
3798  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3799 }
3800 
3801 /*
3802  * has_schema_privilege_name
3803  * Check user privileges on a schema given
3804  * text schemaname and text priv name.
3805  * current_user is assumed
3806  */
3807 Datum
3809 {
3810  text *schemaname = PG_GETARG_TEXT_PP(0);
3811  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3812  Oid roleid;
3813  Oid schemaoid;
3814  AclMode mode;
3815  AclResult aclresult;
3816 
3817  roleid = GetUserId();
3818  schemaoid = convert_schema_name(schemaname);
3819  mode = convert_schema_priv_string(priv_type_text);
3820 
3821  aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3822 
3823  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3824 }
3825 
3826 /*
3827  * has_schema_privilege_name_id
3828  * Check user privileges on a schema given
3829  * name usename, schema oid, and text priv name.
3830  */
3831 Datum
3833 {
3835  Oid schemaoid = PG_GETARG_OID(1);
3836  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3837  Oid roleid;
3838  AclMode mode;
3839  AclResult aclresult;
3840  bool is_missing = false;
3841 
3843  mode = convert_schema_priv_string(priv_type_text);
3844 
3845  aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3846  roleid, mode,
3847  &is_missing);
3848 
3849  if (is_missing)
3850  PG_RETURN_NULL();
3851 
3852  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3853 }
3854 
3855 /*
3856  * has_schema_privilege_id
3857  * Check user privileges on a schema given
3858  * schema oid, and text priv name.
3859  * current_user is assumed
3860  */
3861 Datum
3863 {
3864  Oid schemaoid = PG_GETARG_OID(0);
3865  text *priv_type_text = PG_GETARG_TEXT_PP(1);
3866  Oid roleid;
3867  AclMode mode;
3868  AclResult aclresult;
3869  bool is_missing = false;
3870 
3871  roleid = GetUserId();
3872  mode = convert_schema_priv_string(priv_type_text);
3873 
3874  aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3875  roleid, mode,
3876  &is_missing);
3877 
3878  if (is_missing)
3879  PG_RETURN_NULL();
3880 
3881  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3882 }
3883 
3884 /*
3885  * has_schema_privilege_id_name
3886  * Check user privileges on a schema given
3887  * roleid, text schemaname, and text priv name.
3888  */
3889 Datum
3891 {
3892  Oid roleid = PG_GETARG_OID(0);
3893  text *schemaname = PG_GETARG_TEXT_PP(1);
3894  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3895  Oid schemaoid;
3896  AclMode mode;
3897  AclResult aclresult;
3898 
3899  schemaoid = convert_schema_name(schemaname);
3900  mode = convert_schema_priv_string(priv_type_text);
3901 
3902  aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3903 
3904  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3905 }
3906 
3907 /*
3908  * has_schema_privilege_id_id
3909  * Check user privileges on a schema given
3910  * roleid, schema oid, and text priv name.
3911  */
3912 Datum
3914 {
3915  Oid roleid = PG_GETARG_OID(0);
3916  Oid schemaoid = PG_GETARG_OID(1);
3917  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3918  AclMode mode;
3919  AclResult aclresult;
3920  bool is_missing = false;
3921 
3922  mode = convert_schema_priv_string(priv_type_text);
3923 
3924  aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3925  roleid, mode,
3926  &is_missing);
3927 
3928  if (is_missing)
3929  PG_RETURN_NULL();
3930 
3931  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3932 }
3933 
3934 /*
3935  * Support routines for has_schema_privilege family.
3936  */
3937 
3938 /*
3939  * Given a schema name expressed as a string, look it up and return Oid
3940  */
3941 static Oid
3943 {
3944  char *nspname = text_to_cstring(schemaname);
3945 
3946  return get_namespace_oid(nspname, false);
3947 }
3948 
3949 /*
3950  * convert_schema_priv_string
3951  * Convert text string to AclMode value.
3952  */
3953 static AclMode
3955 {
3956  static const priv_map schema_priv_map[] = {
3957  {"CREATE", ACL_CREATE},
3958  {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
3959  {"USAGE", ACL_USAGE},
3960  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3961  {NULL, 0}
3962  };
3963 
3964  return convert_any_priv_string(priv_type_text, schema_priv_map);
3965 }
3966 
3967 
3968 /*
3969  * has_server_privilege variants
3970  * These are all named "has_server_privilege" at the SQL level.
3971  * They take various combinations of foreign server name,
3972  * server OID, user name, user OID, or implicit user = current_user.
3973  *
3974  * The result is a boolean value: true if user has the indicated
3975  * privilege, false if not.
3976  */
3977 
3978 /*
3979  * has_server_privilege_name_name
3980  * Check user privileges on a foreign server given
3981  * name username, text servername, and text priv name.
3982  */
3983 Datum
3985 {
3987  text *servername = PG_GETARG_TEXT_PP(1);
3988  text *priv_type_text = PG_GETARG_TEXT_PP(2);
3989  Oid roleid;
3990  Oid serverid;
3991  AclMode mode;
3992  AclResult aclresult;
3993 
3995  serverid = convert_server_name(servername);
3996  mode = convert_server_priv_string(priv_type_text);
3997 
3998  aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
3999 
4000  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4001 }
4002 
4003 /*
4004  * has_server_privilege_name
4005  * Check user privileges on a foreign server given
4006  * text servername and text priv name.
4007  * current_user is assumed
4008  */
4009 Datum
4011 {
4012  text *servername = PG_GETARG_TEXT_PP(0);
4013  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4014  Oid roleid;
4015  Oid serverid;
4016  AclMode mode;
4017  AclResult aclresult;
4018 
4019  roleid = GetUserId();
4020  serverid = convert_server_name(servername);
4021  mode = convert_server_priv_string(priv_type_text);
4022 
4023  aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4024 
4025  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4026 }
4027 
4028 /*
4029  * has_server_privilege_name_id
4030  * Check user privileges on a foreign server given
4031  * name usename, foreign server oid, and text priv name.
4032  */
4033 Datum
4035 {
4037  Oid serverid = PG_GETARG_OID(1);
4038  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4039  Oid roleid;
4040  AclMode mode;
4041  AclResult aclresult;
4042  bool is_missing = false;
4043 
4045  mode = convert_server_priv_string(priv_type_text);
4046 
4047  aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4048  roleid, mode,
4049  &is_missing);
4050 
4051  if (is_missing)
4052  PG_RETURN_NULL();
4053 
4054  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4055 }
4056 
4057 /*
4058  * has_server_privilege_id
4059  * Check user privileges on a foreign server given
4060  * server oid, and text priv name.
4061  * current_user is assumed
4062  */
4063 Datum
4065 {
4066  Oid serverid = PG_GETARG_OID(0);
4067  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4068  Oid roleid;
4069  AclMode mode;
4070  AclResult aclresult;
4071  bool is_missing = false;
4072 
4073  roleid = GetUserId();
4074  mode = convert_server_priv_string(priv_type_text);
4075 
4076  aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4077  roleid, mode,
4078  &is_missing);
4079 
4080  if (is_missing)
4081  PG_RETURN_NULL();
4082 
4083  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4084 }
4085 
4086 /*
4087  * has_server_privilege_id_name
4088  * Check user privileges on a foreign server given
4089  * roleid, text servername, and text priv name.
4090  */
4091 Datum
4093 {
4094  Oid roleid = PG_GETARG_OID(0);
4095  text *servername = PG_GETARG_TEXT_PP(1);
4096  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4097  Oid serverid;
4098  AclMode mode;
4099  AclResult aclresult;
4100 
4101  serverid = convert_server_name(servername);
4102  mode = convert_server_priv_string(priv_type_text);
4103 
4104  aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4105 
4106  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4107 }
4108 
4109 /*
4110  * has_server_privilege_id_id
4111  * Check user privileges on a foreign server given
4112  * roleid, server oid, and text priv name.
4113  */
4114 Datum
4116 {
4117  Oid roleid = PG_GETARG_OID(0);
4118  Oid serverid = PG_GETARG_OID(1);
4119  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4120  AclMode mode;
4121  AclResult aclresult;
4122  bool is_missing = false;
4123 
4124  mode = convert_server_priv_string(priv_type_text);
4125 
4126  aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4127  roleid, mode,
4128  &is_missing);
4129 
4130  if (is_missing)
4131  PG_RETURN_NULL();
4132 
4133  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4134 }
4135 
4136 /*
4137  * Support routines for has_server_privilege family.
4138  */
4139 
4140 /*
4141  * Given a server name expressed as a string, look it up and return Oid
4142  */
4143 static Oid
4145 {
4146  char *serverstr = text_to_cstring(servername);
4147 
4148  return get_foreign_server_oid(serverstr, false);
4149 }
4150 
4151 /*
4152  * convert_server_priv_string
4153  * Convert text string to AclMode value.
4154  */
4155 static AclMode
4157 {
4158  static const priv_map server_priv_map[] = {
4159  {"USAGE", ACL_USAGE},
4160  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4161  {NULL, 0}
4162  };
4163 
4164  return convert_any_priv_string(priv_type_text, server_priv_map);
4165 }
4166 
4167 
4168 /*
4169  * has_tablespace_privilege variants
4170  * These are all named "has_tablespace_privilege" at the SQL level.
4171  * They take various combinations of tablespace name, tablespace OID,
4172  * user name, user OID, or implicit user = current_user.
4173  *
4174  * The result is a boolean value: true if user has the indicated
4175  * privilege, false if not.
4176  */
4177 
4178 /*
4179  * has_tablespace_privilege_name_name
4180  * Check user privileges on a tablespace given
4181  * name username, text tablespacename, and text priv name.
4182  */
4183 Datum
4185 {
4187  text *tablespacename = PG_GETARG_TEXT_PP(1);
4188  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4189  Oid roleid;
4190  Oid tablespaceoid;
4191  AclMode mode;
4192  AclResult aclresult;
4193 
4195  tablespaceoid = convert_tablespace_name(tablespacename);
4196  mode = convert_tablespace_priv_string(priv_type_text);
4197 
4198  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4199 
4200  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4201 }
4202 
4203 /*
4204  * has_tablespace_privilege_name
4205  * Check user privileges on a tablespace given
4206  * text tablespacename and text priv name.
4207  * current_user is assumed
4208  */
4209 Datum
4211 {
4212  text *tablespacename = PG_GETARG_TEXT_PP(0);
4213  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4214  Oid roleid;
4215  Oid tablespaceoid;
4216  AclMode mode;
4217  AclResult aclresult;
4218 
4219  roleid = GetUserId();
4220  tablespaceoid = convert_tablespace_name(tablespacename);
4221  mode = convert_tablespace_priv_string(priv_type_text);
4222 
4223  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4224 
4225  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4226 }
4227 
4228 /*
4229  * has_tablespace_privilege_name_id
4230  * Check user privileges on a tablespace given
4231  * name usename, tablespace oid, and text priv name.
4232  */
4233 Datum
4235 {
4237  Oid tablespaceoid = PG_GETARG_OID(1);
4238  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4239  Oid roleid;
4240  AclMode mode;
4241  AclResult aclresult;
4242  bool is_missing = false;
4243 
4245  mode = convert_tablespace_priv_string(priv_type_text);
4246 
4247  aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4248  roleid, mode,
4249  &is_missing);
4250 
4251  if (is_missing)
4252  PG_RETURN_NULL();
4253 
4254  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4255 }
4256 
4257 /*
4258  * has_tablespace_privilege_id
4259  * Check user privileges on a tablespace given
4260  * tablespace oid, and text priv name.
4261  * current_user is assumed
4262  */
4263 Datum
4265 {
4266  Oid tablespaceoid = PG_GETARG_OID(0);
4267  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4268  Oid roleid;
4269  AclMode mode;
4270  AclResult aclresult;
4271  bool is_missing = false;
4272 
4273  roleid = GetUserId();
4274  mode = convert_tablespace_priv_string(priv_type_text);
4275 
4276  aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4277  roleid, mode,
4278  &is_missing);
4279 
4280  if (is_missing)
4281  PG_RETURN_NULL();
4282 
4283  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4284 }
4285 
4286 /*
4287  * has_tablespace_privilege_id_name
4288  * Check user privileges on a tablespace given
4289  * roleid, text tablespacename, and text priv name.
4290  */
4291 Datum
4293 {
4294  Oid roleid = PG_GETARG_OID(0);
4295  text *tablespacename = PG_GETARG_TEXT_PP(1);
4296  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4297  Oid tablespaceoid;
4298  AclMode mode;
4299  AclResult aclresult;
4300 
4301  tablespaceoid = convert_tablespace_name(tablespacename);
4302  mode = convert_tablespace_priv_string(priv_type_text);
4303 
4304  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4305 
4306  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4307 }
4308 
4309 /*
4310  * has_tablespace_privilege_id_id
4311  * Check user privileges on a tablespace given
4312  * roleid, tablespace oid, and text priv name.
4313  */
4314 Datum
4316 {
4317  Oid roleid = PG_GETARG_OID(0);
4318  Oid tablespaceoid = PG_GETARG_OID(1);
4319  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4320  AclMode mode;
4321  AclResult aclresult;
4322  bool is_missing = false;
4323 
4324  mode = convert_tablespace_priv_string(priv_type_text);
4325 
4326  aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4327  roleid, mode,
4328  &is_missing);
4329 
4330  if (is_missing)
4331  PG_RETURN_NULL();
4332 
4333  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4334 }
4335 
4336 /*
4337  * Support routines for has_tablespace_privilege family.
4338  */
4339 
4340 /*
4341  * Given a tablespace name expressed as a string, look it up and return Oid
4342  */
4343 static Oid
4345 {
4346  char *spcname = text_to_cstring(tablespacename);
4347 
4348  return get_tablespace_oid(spcname, false);
4349 }
4350 
4351 /*
4352  * convert_tablespace_priv_string
4353  * Convert text string to AclMode value.
4354  */
4355 static AclMode
4357 {
4358  static const priv_map tablespace_priv_map[] = {
4359  {"CREATE", ACL_CREATE},
4360  {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4361  {NULL, 0}
4362  };
4363 
4364  return convert_any_priv_string(priv_type_text, tablespace_priv_map);
4365 }
4366 
4367 /*
4368  * has_type_privilege variants
4369  * These are all named "has_type_privilege" at the SQL level.
4370  * They take various combinations of type name, type OID,
4371  * user name, user OID, or implicit user = current_user.
4372  *
4373  * The result is a boolean value: true if user has the indicated
4374  * privilege, false if not, or NULL if object doesn't exist.
4375  */
4376 
4377 /*
4378  * has_type_privilege_name_name
4379  * Check user privileges on a type given
4380  * name username, text typename, and text priv name.
4381  */
4382 Datum
4384 {
4386  text *typename = PG_GETARG_TEXT_PP(1);
4387  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4388  Oid roleid;
4389  Oid typeoid;
4390  AclMode mode;
4391  AclResult aclresult;
4392 
4394  typeoid = convert_type_name(typename);
4395  mode = convert_type_priv_string(priv_type_text);
4396 
4397  aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4398 
4399  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4400 }
4401 
4402 /*
4403  * has_type_privilege_name
4404  * Check user privileges on a type given
4405  * text typename and text priv name.
4406  * current_user is assumed
4407  */
4408 Datum
4410 {
4411  text *typename = PG_GETARG_TEXT_PP(0);
4412  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4413  Oid roleid;
4414  Oid typeoid;
4415  AclMode mode;
4416  AclResult aclresult;
4417 
4418  roleid = GetUserId();
4419  typeoid = convert_type_name(typename);
4420  mode = convert_type_priv_string(priv_type_text);
4421 
4422  aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4423 
4424  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4425 }
4426 
4427 /*
4428  * has_type_privilege_name_id
4429  * Check user privileges on a type given
4430  * name usename, type oid, and text priv name.
4431  */
4432 Datum
4434 {
4436  Oid typeoid = PG_GETARG_OID(1);
4437  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4438  Oid roleid;
4439  AclMode mode;
4440  AclResult aclresult;
4441  bool is_missing = false;
4442 
4444  mode = convert_type_priv_string(priv_type_text);
4445 
4446  aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4447  roleid, mode,
4448  &is_missing);
4449 
4450  if (is_missing)
4451  PG_RETURN_NULL();
4452 
4453  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4454 }
4455 
4456 /*
4457  * has_type_privilege_id
4458  * Check user privileges on a type given
4459  * type oid, and text priv name.
4460  * current_user is assumed
4461  */
4462 Datum
4464 {
4465  Oid typeoid = PG_GETARG_OID(0);
4466  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4467  Oid roleid;
4468  AclMode mode;
4469  AclResult aclresult;
4470  bool is_missing = false;
4471 
4472  roleid = GetUserId();
4473  mode = convert_type_priv_string(priv_type_text);
4474 
4475  aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4476  roleid, mode,
4477  &is_missing);
4478 
4479  if (is_missing)
4480  PG_RETURN_NULL();
4481 
4482  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4483 }
4484 
4485 /*
4486  * has_type_privilege_id_name
4487  * Check user privileges on a type given
4488  * roleid, text typename, and text priv name.
4489  */
4490 Datum
4492 {
4493  Oid roleid = PG_GETARG_OID(0);
4494  text *typename = PG_GETARG_TEXT_PP(1);
4495  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4496  Oid typeoid;
4497  AclMode mode;
4498  AclResult aclresult;
4499 
4500  typeoid = convert_type_name(typename);
4501  mode = convert_type_priv_string(priv_type_text);
4502 
4503  aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4504 
4505  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4506 }
4507 
4508 /*
4509  * has_type_privilege_id_id
4510  * Check user privileges on a type given
4511  * roleid, type oid, and text priv name.
4512  */
4513 Datum
4515 {
4516  Oid roleid = PG_GETARG_OID(0);
4517  Oid typeoid = PG_GETARG_OID(1);
4518  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4519  AclMode mode;
4520  AclResult aclresult;
4521  bool is_missing = false;
4522 
4523  mode = convert_type_priv_string(priv_type_text);
4524 
4525  aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4526  roleid, mode,
4527  &is_missing);
4528 
4529  if (is_missing)
4530  PG_RETURN_NULL();
4531 
4532  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4533 }
4534 
4535 /*
4536  * Support routines for has_type_privilege family.
4537  */
4538 
4539 /*
4540  * Given a type name expressed as a string, look it up and return Oid
4541  */
4542 static Oid
4544 {
4545  char *typname = text_to_cstring(typename);
4546  Oid oid;
4547 
4550 
4551  if (!OidIsValid(oid))
4552  ereport(ERROR,
4553  (errcode(ERRCODE_UNDEFINED_OBJECT),
4554  errmsg("type \"%s\" does not exist", typname)));
4555 
4556  return oid;
4557 }
4558 
4559 /*
4560  * convert_type_priv_string
4561  * Convert text string to AclMode value.
4562  */
4563 static AclMode
4565 {
4566  static const priv_map type_priv_map[] = {
4567  {"USAGE", ACL_USAGE},
4568  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4569  {NULL, 0}
4570  };
4571 
4572  return convert_any_priv_string(priv_type_text, type_priv_map);
4573 }
4574 
4575 /*
4576  * has_parameter_privilege variants
4577  * These are all named "has_parameter_privilege" at the SQL level.
4578  * They take various combinations of parameter name with
4579  * user name, user OID, or implicit user = current_user.
4580  *
4581  * The result is a boolean value: true if user has been granted
4582  * the indicated privilege or false if not.
4583  */
4584 
4585 /*
4586  * has_param_priv_byname
4587  *
4588  * Helper function to check user privileges on a parameter given the
4589  * role by Oid, parameter by text name, and privileges as AclMode.
4590  */
4591 static bool
4592 has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
4593 {
4594  char *paramstr = text_to_cstring(parameter);
4595 
4596  return pg_parameter_aclcheck(paramstr, roleid, priv) == ACLCHECK_OK;
4597 }
4598 
4599 /*
4600  * has_parameter_privilege_name_name
4601  * Check user privileges on a parameter given name username, text
4602  * parameter, and text priv name.
4603  */
4604 Datum
4606 {
4608  text *parameter = PG_GETARG_TEXT_PP(1);
4611 
4612  PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
4613 }
4614 
4615 /*
4616  * has_parameter_privilege_name
4617  * Check user privileges on a parameter given text parameter and text priv
4618  * name. current_user is assumed
4619  */
4620 Datum
4622 {
4623  text *parameter = PG_GETARG_TEXT_PP(0);
4625 
4626  PG_RETURN_BOOL(has_param_priv_byname(GetUserId(), parameter, priv));
4627 }
4628 
4629 /*
4630  * has_parameter_privilege_id_name
4631  * Check user privileges on a parameter given roleid, text parameter, and
4632  * text priv name.
4633  */
4634 Datum
4636 {
4637  Oid roleid = PG_GETARG_OID(0);
4638  text *parameter = PG_GETARG_TEXT_PP(1);
4640 
4641  PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
4642 }
4643 
4644 /*
4645  * Support routines for has_parameter_privilege family.
4646  */
4647 
4648 /*
4649  * convert_parameter_priv_string
4650  * Convert text string to AclMode value.
4651  */
4652 static AclMode
4654 {
4655  static const priv_map parameter_priv_map[] = {
4656  {"SET", ACL_SET},
4657  {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SET)},
4658  {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
4659  {"ALTER SYSTEM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ALTER_SYSTEM)},
4660  {NULL, 0}
4661  };
4662 
4663  return convert_any_priv_string(priv_text, parameter_priv_map);
4664 }
4665 
4666 /*
4667  * pg_has_role variants
4668  * These are all named "pg_has_role" at the SQL level.
4669  * They take various combinations of role name, role OID,
4670  * user name, user OID, or implicit user = current_user.
4671  *
4672  * The result is a boolean value: true if user has the indicated
4673  * privilege, false if not.
4674  */
4675 
4676 /*
4677  * pg_has_role_name_name
4678  * Check user privileges on a role given
4679  * name username, name rolename, and text priv name.
4680  */
4681 Datum
4683 {
4685  Name rolename = PG_GETARG_NAME(1);
4686  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4687  Oid roleid;
4688  Oid roleoid;
4689  AclMode mode;
4690  AclResult aclresult;
4691 
4692  roleid = get_role_oid(NameStr(*username), false);
4693  roleoid = get_role_oid(NameStr(*rolename), false);
4694  mode = convert_role_priv_string(priv_type_text);
4695 
4696  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4697 
4698  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4699 }
4700 
4701 /*
4702  * pg_has_role_name
4703  * Check user privileges on a role given
4704  * name rolename and text priv name.
4705  * current_user is assumed
4706  */
4707 Datum
4709 {
4710  Name rolename = PG_GETARG_NAME(0);
4711  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4712  Oid roleid;
4713  Oid roleoid;
4714  AclMode mode;
4715  AclResult aclresult;
4716 
4717  roleid = GetUserId();
4718  roleoid = get_role_oid(NameStr(*rolename), false);
4719  mode = convert_role_priv_string(priv_type_text);
4720 
4721  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4722 
4723  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4724 }
4725 
4726 /*
4727  * pg_has_role_name_id
4728  * Check user privileges on a role given
4729  * name usename, role oid, and text priv name.
4730  */
4731 Datum
4733 {
4735  Oid roleoid = PG_GETARG_OID(1);
4736  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4737  Oid roleid;
4738  AclMode mode;
4739  AclResult aclresult;
4740 
4741  roleid = get_role_oid(NameStr(*username), false);
4742  mode = convert_role_priv_string(priv_type_text);
4743 
4744  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4745 
4746  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4747 }
4748 
4749 /*
4750  * pg_has_role_id
4751  * Check user privileges on a role given
4752  * role oid, and text priv name.
4753  * current_user is assumed
4754  */
4755 Datum
4757 {
4758  Oid roleoid = PG_GETARG_OID(0);
4759  text *priv_type_text = PG_GETARG_TEXT_PP(1);
4760  Oid roleid;
4761  AclMode mode;
4762  AclResult aclresult;
4763 
4764  roleid = GetUserId();
4765  mode = convert_role_priv_string(priv_type_text);
4766 
4767  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4768 
4769  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4770 }
4771 
4772 /*
4773  * pg_has_role_id_name
4774  * Check user privileges on a role given
4775  * roleid, name rolename, and text priv name.
4776  */
4777 Datum
4779 {
4780  Oid roleid = PG_GETARG_OID(0);
4781  Name rolename = PG_GETARG_NAME(1);
4782  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4783  Oid roleoid;
4784  AclMode mode;
4785  AclResult aclresult;
4786 
4787  roleoid = get_role_oid(NameStr(*rolename), false);
4788  mode = convert_role_priv_string(priv_type_text);
4789 
4790  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4791 
4792  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4793 }
4794 
4795 /*
4796  * pg_has_role_id_id
4797  * Check user privileges on a role given
4798  * roleid, role oid, and text priv name.
4799  */
4800 Datum
4802 {
4803  Oid roleid = PG_GETARG_OID(0);
4804  Oid roleoid = PG_GETARG_OID(1);
4805  text *priv_type_text = PG_GETARG_TEXT_PP(2);
4806  AclMode mode;
4807  AclResult aclresult;
4808 
4809  mode = convert_role_priv_string(priv_type_text);
4810 
4811  aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4812 
4813  PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4814 }
4815 
4816 /*
4817  * Support routines for pg_has_role family.
4818  */
4819 
4820 /*
4821  * convert_role_priv_string
4822  * Convert text string to AclMode value.
4823  *
4824  * We use USAGE to denote whether the privileges of the role are accessible
4825  * (has_privs_of_role), MEMBER to denote is_member, and MEMBER WITH GRANT
4826  * (or ADMIN) OPTION to denote is_admin. There is no ACL bit corresponding
4827  * to MEMBER so we cheat and use ACL_CREATE for that. This convention
4828  * is shared only with pg_role_aclcheck, below.
4829  */
4830 static AclMode
4832 {
4833  static const priv_map role_priv_map[] = {
4834  {"USAGE", ACL_USAGE},
4835  {"MEMBER", ACL_CREATE},
4836  {"SET", ACL_SET},
4837  {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4838  {"USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4839  {"MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4840  {"MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4841  {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4842  {"SET WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4843  {NULL, 0}
4844  };
4845 
4846  return convert_any_priv_string(priv_type_text, role_priv_map);
4847 }
4848 
4849 /*
4850  * pg_role_aclcheck
4851  * Quick-and-dirty support for pg_has_role
4852  */
4853 static AclResult
4855 {
4857  {
4858  if (is_admin_of_role(roleid, role_oid))
4859  return ACLCHECK_OK;
4860  }
4861  if (mode & ACL_CREATE)
4862  {
4863  if (is_member_of_role(roleid, role_oid))
4864  return ACLCHECK_OK;
4865  }
4866  if (mode & ACL_USAGE)
4867  {
4868  if (has_privs_of_role(roleid, role_oid))
4869  return ACLCHECK_OK;
4870  }
4871  if (mode & ACL_SET)
4872  {
4873  if (member_can_set_role(roleid, role_oid))
4874  return ACLCHECK_OK;
4875  }
4876  return ACLCHECK_NO_PRIV;
4877 }
4878 
4879 
4880 /*
4881  * initialization function (called by InitPostgres)
4882  */
4883 void
4885 {
4887  {
4888  cached_db_hash =
4889  GetSysCacheHashValue1(DATABASEOID,
4891 
4892  /*
4893  * In normal mode, set a callback on any syscache invalidation of rows
4894  * of pg_auth_members (for roles_is_member_of()) pg_database (for
4895  * roles_is_member_of())
4896  */
4897  CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
4899  (Datum) 0);
4902  (Datum) 0);
4903  CacheRegisterSyscacheCallback(DATABASEOID,
4905  (Datum) 0);
4906  }
4907 }
4908 
4909 /*
4910  * RoleMembershipCacheCallback
4911  * Syscache inval callback function
4912  */
4913 static void
4915 {
4916  if (cacheid == DATABASEOID &&
4917  hashvalue != cached_db_hash &&
4918  hashvalue != 0)
4919  {
4920  return; /* ignore pg_database changes for other DBs */
4921  }
4922 
4923  /* Force membership caches to be recomputed on next use */
4927 }
4928 
4929 /*
4930  * A helper function for roles_is_member_of() that provides an optimized
4931  * implementation of list_append_unique_oid() via a Bloom filter. The caller
4932  * (i.e., roles_is_member_of()) is responsible for freeing bf once it is done
4933  * using this function.
4934  */
4935 static inline List *
4936 roles_list_append(List *roles_list, bloom_filter **bf, Oid role)
4937 {
4938  unsigned char *roleptr = (unsigned char *) &role;
4939 
4940  /*
4941  * If there is a previously-created Bloom filter, use it to try to
4942  * determine whether the role is missing from the list. If it says yes,
4943  * that's a hard fact and we can go ahead and add the role. If it says
4944  * no, that's only probabilistic and we'd better search the list. Without
4945  * a filter, we must always do an ordinary linear search through the
4946  * existing list.
4947  */
4948  if ((*bf && bloom_lacks_element(*bf, roleptr, sizeof(Oid))) ||
4949  !list_member_oid(roles_list, role))
4950  {
4951  /*
4952  * If the list is large, we take on the overhead of creating and
4953  * populating a Bloom filter to speed up future calls to this
4954  * function.
4955  */
4956  if (*bf == NULL &&
4958  {
4960  foreach_oid(roleid, roles_list)
4961  bloom_add_element(*bf, (unsigned char *) &roleid, sizeof(Oid));
4962  }
4963 
4964  /*
4965  * Finally, add the role to the list and the Bloom filter, if it
4966  * exists.
4967  */
4968  roles_list = lappend_oid(roles_list, role);
4969  if (*bf)
4970  bloom_add_element(*bf, roleptr, sizeof(Oid));
4971  }
4972 
4973  return roles_list;
4974 }
4975 
4976 /*
4977  * Get a list of roles that the specified roleid is a member of
4978  *
4979  * Type ROLERECURSE_MEMBERS recurses through all grants; ROLERECURSE_PRIVS
4980  * recurses only through inheritable grants; and ROLERECURSE_SETROLE recurses
4981  * only through grants with set_option.
4982  *
4983  * Since indirect membership testing is relatively expensive, we cache
4984  * a list of memberships. Hence, the result is only guaranteed good until
4985  * the next call of roles_is_member_of()!
4986  *
4987  * For the benefit of select_best_grantor, the result is defined to be
4988  * in breadth-first order, ie, closer relationships earlier.
4989  *
4990  * If admin_of is not InvalidOid, this function sets *admin_role, either
4991  * to the OID of the first role in the result list that directly possesses
4992  * ADMIN OPTION on the role corresponding to admin_of, or to InvalidOid if
4993  * there is no such role.
4994  */
4995 static List *
4997  Oid admin_of, Oid *admin_role)
4998 {
4999  Oid dba;
5000  List *roles_list;
5001  ListCell *l;
5002  List *new_cached_roles;
5003  MemoryContext oldctx;
5004  bloom_filter *bf = NULL;
5005 
5006  Assert(OidIsValid(admin_of) == PointerIsValid(admin_role));
5007  if (admin_role != NULL)
5008  *admin_role = InvalidOid;
5009 
5010  /* If cache is valid and ADMIN OPTION not sought, just return the list */
5011  if (cached_role[type] == roleid && !OidIsValid(admin_of) &&
5013  return cached_roles[type];
5014 
5015  /*
5016  * Role expansion happens in a non-database backend when guc.c checks
5017  * ROLE_PG_READ_ALL_SETTINGS for a physical walsender SHOW command. In
5018  * that case, no role gets pg_database_owner.
5019  */
5020  if (!OidIsValid(MyDatabaseId))
5021  dba = InvalidOid;
5022  else
5023  {
5024  HeapTuple dbtup;
5025 
5026  dbtup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
5027  if (!HeapTupleIsValid(dbtup))
5028  elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
5029  dba = ((Form_pg_database) GETSTRUCT(dbtup))->datdba;
5030  ReleaseSysCache(dbtup);
5031  }
5032 
5033  /*
5034  * Find all the roles that roleid is a member of, including multi-level
5035  * recursion. The role itself will always be the first element of the
5036  * resulting list.
5037  *
5038  * Each element of the list is scanned to see if it adds any indirect
5039  * memberships. We can use a single list as both the record of
5040  * already-found memberships and the agenda of roles yet to be scanned.
5041  * This is a bit tricky but works because the foreach() macro doesn't
5042  * fetch the next list element until the bottom of the loop.
5043  */
5044  roles_list = list_make1_oid(roleid);
5045 
5046  foreach(l, roles_list)
5047  {
5048  Oid memberid = lfirst_oid(l);
5049  CatCList *memlist;
5050  int i;
5051 
5052  /* Find roles that memberid is directly a member of */
5053  memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
5054  ObjectIdGetDatum(memberid));
5055  for (i = 0; i < memlist->n_members; i++)
5056  {
5057  HeapTuple tup = &memlist->members[i]->tuple;
5059  Oid otherid = form->roleid;
5060 
5061  /*
5062  * While otherid==InvalidOid shouldn't appear in the catalog, the
5063  * OidIsValid() avoids crashing if that arises.
5064  */
5065  if (otherid == admin_of && form->admin_option &&
5066  OidIsValid(admin_of) && !OidIsValid(*admin_role))
5067  *admin_role = memberid;
5068 
5069  /* If we're supposed to ignore non-heritable grants, do so. */
5070  if (type == ROLERECURSE_PRIVS && !form->inherit_option)
5071  continue;
5072 
5073  /* If we're supposed to ignore non-SET grants, do so. */
5074  if (type == ROLERECURSE_SETROLE && !form->set_option)
5075  continue;
5076 
5077  /*
5078  * Even though there shouldn't be any loops in the membership
5079  * graph, we must test for having already seen this role. It is
5080  * legal for instance to have both A->B and A->C->B.
5081  */
5082  roles_list = roles_list_append(roles_list, &bf, otherid);
5083  }
5084  ReleaseSysCacheList(memlist);
5085 
5086  /* implement pg_database_owner implicit membership */
5087  if (memberid == dba && OidIsValid(dba))
5088  roles_list = roles_list_append(roles_list, &bf,
5089  ROLE_PG_DATABASE_OWNER);
5090  }
5091 
5092  /*
5093  * Free the Bloom filter created by roles_list_append(), if there is one.
5094  */
5095  if (bf)
5096  bloom_free(bf);
5097 
5098  /*
5099  * Copy the completed list into TopMemoryContext so it will persist.
5100  */
5102  new_cached_roles = list_copy(roles_list);
5103  MemoryContextSwitchTo(oldctx);
5104  list_free(roles_list);
5105 
5106  /*
5107  * Now safe to assign to state variable
5108  */
5109  cached_role[type] = InvalidOid; /* just paranoia */
5111  cached_roles[type] = new_cached_roles;
5112  cached_role[type] = roleid;
5113 
5114  /* And now we can return the answer */
5115  return cached_roles[type];
5116 }
5117 
5118 
5119 /*
5120  * Does member have the privileges of role (directly or indirectly)?
5121  *
5122  * This is defined not to recurse through grants that are not inherited,
5123  * and only inherited grants confer the associated privileges automatically.
5124  *
5125  * See also member_can_set_role, below.
5126  */
5127 bool
5129 {
5130  /* Fast path for simple case */
5131  if (member == role)
5132  return true;
5133 
5134  /* Superusers have every privilege, so are part of every role */
5135  if (superuser_arg(member))
5136  return true;
5137 
5138  /*
5139  * Find all the roles that member has the privileges of, including
5140  * multi-level recursion, then see if target role is any one of them.
5141  */
5143  InvalidOid, NULL),
5144  role);
5145 }
5146 
5147 /*
5148  * Can member use SET ROLE to this role?
5149  *
5150  * There must be a chain of grants from 'member' to 'role' each of which
5151  * permits SET ROLE; that is, each of which has set_option = true.
5152  *
5153  * It doesn't matter whether the grants are inheritable. That's a separate
5154  * question; see has_privs_of_role.
5155  *
5156  * This function should be used to determine whether the session user can
5157  * use SET ROLE to become the target user. We also use it to determine whether
5158  * the session user can change an existing object to be owned by the target
5159  * user, or create new objects owned by the target user.
5160  */
5161 bool
5163 {
5164  /* Fast path for simple case */
5165  if (member == role)
5166  return true;
5167 
5168  /* Superusers have every privilege, so can always SET ROLE */
5169  if (superuser_arg(member))
5170  return true;
5171 
5172  /*
5173  * Find all the roles that member can access via SET ROLE, including
5174  * multi-level recursion, then see if target role is any one of them.
5175  */
5177  InvalidOid, NULL),
5178  role);
5179 }
5180 
5181 /*
5182  * Permission violation error unless able to SET ROLE to target role.
5183  */
5184 void
5186 {
5187  if (!member_can_set_role(member, role))
5188  ereport(ERROR,
5189  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
5190  errmsg("must be able to SET ROLE \"%s\"",
5191  GetUserNameFromId(role, false))));
5192 }
5193 
5194 /*
5195  * Is member a member of role (directly or indirectly)?
5196  *
5197  * This is defined to recurse through grants whether they are inherited or not.
5198  *
5199  * Do not use this for privilege checking, instead use has_privs_of_role().
5200  * Don't use it for determining whether it's possible to SET ROLE to some
5201  * other role; for that, use member_can_set_role(). And don't use it for
5202  * determining whether it's OK to create an object owned by some other role:
5203  * use member_can_set_role() for that, too.
5204  *
5205  * In short, calling this function is the wrong thing to do nearly everywhere.
5206  */
5207 bool
5209 {
5210  /* Fast path for simple case */
5211  if (member == role)
5212  return true;
5213 
5214  /* Superusers have every privilege, so are part of every role */
5215  if (superuser_arg(member))
5216  return true;
5217 
5218  /*
5219  * Find all the roles that member is a member of, including multi-level
5220  * recursion, then see if target role is any one of them.
5221  */
5223  InvalidOid, NULL),
5224  role);
5225 }
5226 
5227 /*
5228  * Is member a member of role, not considering superuserness?
5229  *
5230  * This is identical to is_member_of_role except we ignore superuser
5231  * status.
5232  *
5233  * Do not use this for privilege checking, instead use has_privs_of_role()
5234  */
5235 bool
5237 {
5238  /* Fast path for simple case */
5239  if (member == role)
5240  return true;
5241 
5242  /*
5243  * Find all the roles that member is a member of, including multi-level
5244  * recursion, then see if target role is any one of them.
5245  */
5247  InvalidOid, NULL),
5248  role);
5249 }
5250 
5251 
5252 /*
5253  * Is member an admin of role? That is, is member the role itself (subject to
5254  * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
5255  * or a superuser?
5256  */
5257 bool
5258 is_admin_of_role(Oid member, Oid role)
5259 {
5260  Oid admin_role;
5261 
5262  if (superuser_arg(member))
5263  return true;
5264 
5265  /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5266  if (member == role)
5267  return false;
5268 
5269  (void) roles_is_member_of(member, ROLERECURSE_MEMBERS, role, &admin_role);
5270  return OidIsValid(admin_role);
5271 }
5272 
5273 /*
5274  * Find a role whose privileges "member" inherits which has ADMIN OPTION
5275  * on "role", ignoring super-userness.
5276  *
5277  * There might be more than one such role; prefer one which involves fewer
5278  * hops. That is, if member has ADMIN OPTION, prefer that over all other
5279  * options; if not, prefer a role from which member inherits more directly
5280  * over more indirect inheritance.
5281  */
5282 Oid
5284 {
5285  Oid admin_role;
5286 
5287  /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5288  if (member == role)
5289  return InvalidOid;
5290 
5291  (void) roles_is_member_of(member, ROLERECURSE_PRIVS, role, &admin_role);
5292  return admin_role;
5293 }
5294 
5295 
5296 /* does what it says ... */
5297 static int
5299 {
5300  int nbits = 0;
5301 
5302  /* this code relies on AclMode being an unsigned type */
5303  while (mask)
5304  {
5305  if (mask & 1)
5306  nbits++;
5307  mask >>= 1;
5308  }
5309  return nbits;
5310 }
5311 
5312 
5313 /*
5314  * Select the effective grantor ID for a GRANT or REVOKE operation.
5315  *
5316  * The grantor must always be either the object owner or some role that has
5317  * been explicitly granted grant options. This ensures that all granted
5318  * privileges appear to flow from the object owner, and there are never
5319  * multiple "original sources" of a privilege. Therefore, if the would-be
5320  * grantor is a member of a role that has the needed grant options, we have
5321  * to do the grant as that role instead.
5322  *
5323  * It is possible that the would-be grantor is a member of several roles
5324  * that have different subsets of the desired grant options, but no one
5325  * role has 'em all. In this case we pick a role with the largest number
5326  * of desired options. Ties are broken in favor of closer ancestors.
5327  *
5328  * roleId: the role attempting to do the GRANT/REVOKE
5329  * privileges: the privileges to be granted/revoked
5330  * acl: the ACL of the object in question
5331  * ownerId: the role owning the object in question
5332  * *grantorId: receives the OID of the role to do the grant as
5333  * *grantOptions: receives the grant options actually held by grantorId
5334  *
5335  * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
5336  */
5337 void
5338 select_best_grantor(Oid roleId, AclMode privileges,
5339  const Acl *acl, Oid ownerId,
5340  Oid *grantorId, AclMode *grantOptions)
5341 {
5342  AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
5343  List *roles_list;
5344  int nrights;
5345  ListCell *l;
5346 
5347  /*
5348  * The object owner is always treated as having all grant options, so if
5349  * roleId is the owner it's easy. Also, if roleId is a superuser it's
5350  * easy: superusers are implicitly members of every role, so they act as
5351  * the object owner.
5352  */
5353  if (roleId == ownerId || superuser_arg(roleId))
5354  {
5355  *grantorId = ownerId;
5356  *grantOptions = needed_goptions;
5357  return;
5358  }
5359 
5360  /*
5361  * Otherwise we have to do a careful search to see if roleId has the
5362  * privileges of any suitable role. Note: we can hang onto the result of
5363  * roles_is_member_of() throughout this loop, because aclmask_direct()
5364  * doesn't query any role memberships.
5365  */
5366  roles_list = roles_is_member_of(roleId, ROLERECURSE_PRIVS,
5367  InvalidOid, NULL);
5368 
5369  /* initialize candidate result as default */
5370  *grantorId = roleId;
5371  *grantOptions = ACL_NO_RIGHTS;
5372  nrights = 0;
5373 
5374  foreach(l, roles_list)
5375  {
5376  Oid otherrole = lfirst_oid(l);
5377  AclMode otherprivs;
5378 
5379  otherprivs = aclmask_direct(acl, otherrole, ownerId,
5380  needed_goptions, ACLMASK_ALL);
5381  if (otherprivs == needed_goptions)
5382  {
5383  /* Found a suitable grantor */
5384  *grantorId = otherrole;
5385  *grantOptions = otherprivs;
5386  return;
5387  }
5388 
5389  /*
5390  * If it has just some of the needed privileges, remember best
5391  * candidate.
5392  */
5393  if (otherprivs != ACL_NO_RIGHTS)
5394  {
5395  int nnewrights = count_one_bits(otherprivs);
5396 
5397  if (nnewrights > nrights)
5398  {
5399  *grantorId = otherrole;
5400  *grantOptions = otherprivs;
5401  nrights = nnewrights;
5402  }
5403  }
5404  }
5405 }
5406 
5407 /*
5408  * get_role_oid - Given a role name, look up the role's OID.
5409  *
5410  * If missing_ok is false, throw an error if role name not found. If
5411  * true, just return InvalidOid.
5412  */
5413 Oid
5414 get_role_oid(const char *rolname, bool missing_ok)
5415 {
5416  Oid oid;
5417 
5418  oid = GetSysCacheOid1(AUTHNAME, Anum_pg_authid_oid,
5420  if (!OidIsValid(oid) && !missing_ok)
5421  ereport(ERROR,
5422  (errcode(ERRCODE_UNDEFINED_OBJECT),
5423  errmsg("role \"%s\" does not exist", rolname)));
5424  return oid;
5425 }
5426 
5427 /*
5428  * get_role_oid_or_public - As above, but return ACL_ID_PUBLIC if the
5429  * role name is "public".
5430  */
5431 Oid
5433 {
5434  if (strcmp(rolname, "public") == 0)
5435  return ACL_ID_PUBLIC;
5436 
5437  return get_role_oid(rolname, false);
5438 }
5439 
5440 /*
5441  * Given a RoleSpec node, return the OID it corresponds to. If missing_ok is
5442  * true, return InvalidOid if the role does not exist.
5443  *
5444  * PUBLIC is always disallowed here. Routines wanting to handle the PUBLIC
5445  * case must check the case separately.
5446  */
5447 Oid
5448 get_rolespec_oid(const RoleSpec *role, bool missing_ok)
5449 {
5450  Oid oid;
5451 
5452  switch (role->roletype)
5453  {
5454  case ROLESPEC_CSTRING:
5455  Assert(role->rolename);
5456  oid = get_role_oid(role->rolename, missing_ok);
5457  break;
5458 
5459  case ROLESPEC_CURRENT_ROLE:
5460  case ROLESPEC_CURRENT_USER:
5461  oid = GetUserId();
5462  break;
5463 
5464  case ROLESPEC_SESSION_USER:
5465  oid = GetSessionUserId();
5466  break;
5467 
5468  case ROLESPEC_PUBLIC:
5469  ereport(ERROR,
5470  (errcode(ERRCODE_UNDEFINED_OBJECT),
5471  errmsg("role \"%s\" does not exist", "public")));
5472  oid = InvalidOid; /* make compiler happy */
5473  break;
5474 
5475  default:
5476  elog(ERROR, "unexpected role type %d", role->roletype);
5477  }
5478 
5479  return oid;
5480 }
5481 
5482 /*
5483  * Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
5484  * Caller must ReleaseSysCache when done with the result tuple.
5485  */
5486 HeapTuple
5488 {
5489  HeapTuple tuple;
5490 
5491  switch (role->roletype)
5492  {
5493  case ROLESPEC_CSTRING:
5494  Assert(role->rolename);
5495  tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolename));
5496  if (!HeapTupleIsValid(tuple))
5497  ereport(ERROR,
5498  (errcode(ERRCODE_UNDEFINED_OBJECT),
5499  errmsg("role \"%s\" does not exist", role->rolename)));
5500  break;
5501 
5502  case ROLESPEC_CURRENT_ROLE:
5503  case ROLESPEC_CURRENT_USER:
5504  tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
5505  if (!HeapTupleIsValid(tuple))
5506  elog(ERROR, "cache lookup failed for role %u", GetUserId());
5507  break;
5508 
5509  case ROLESPEC_SESSION_USER:
5510  tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetSessionUserId()));
5511  if (!HeapTupleIsValid(tuple))
5512  elog(ERROR, "cache lookup failed for role %u", GetSessionUserId());
5513  break;
5514 
5515  case ROLESPEC_PUBLIC:
5516  ereport(ERROR,
5517  (errcode(ERRCODE_UNDEFINED_OBJECT),
5518  errmsg("role \"%s\" does not exist", "public")));
5519  tuple = NULL; /* make compiler happy */
5520  break;
5521 
5522  default:
5523  elog(ERROR, "unexpected role type %d", role->roletype);
5524  }
5525 
5526  return tuple;
5527 }
5528 
5529 /*
5530  * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
5531  */
5532 char *
5534 {
5535  HeapTuple tp;
5536  Form_pg_authid authForm;
5537  char *rolename;
5538 
5539  tp = get_rolespec_tuple(role);
5540  authForm = (Form_pg_authid) GETSTRUCT(tp);
5541  rolename = pstrdup(NameStr(authForm->rolname));
5542  ReleaseSysCache(tp);
5543 
5544  return rolename;
5545 }
5546 
5547 /*
5548  * Given a RoleSpec, throw an error if the name is reserved, using detail_msg,
5549  * if provided (which must be already translated).
5550  *
5551  * If node is NULL, no error is thrown. If detail_msg is NULL then no detail
5552  * message is provided.
5553  */
5554 void
5555 check_rolespec_name(const RoleSpec *role, const char *detail_msg)
5556 {
5557  if (!role)
5558  return;
5559 
5560  if (role->roletype != ROLESPEC_CSTRING)
5561  return;
5562 
5563  if (IsReservedName(role->rolename))
5564  {
5565  if (detail_msg)
5566  ereport(ERROR,
5567  (errcode(ERRCODE_RESERVED_NAME),
5568  errmsg("role name \"%s\" is reserved",
5569  role->rolename),
5570  errdetail_internal("%s", detail_msg)));
5571  else
5572  ereport(ERROR,
5573  (errcode(ERRCODE_RESERVED_NAME),
5574  errmsg("role name \"%s\" is reserved",
5575  role->rolename)));
5576  }
5577 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
Datum pg_has_role_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4801
Datum has_schema_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3862
Datum hash_aclitem(PG_FUNCTION_ARGS)
Definition: acl.c:751
void initialize_acl(void)
Definition: acl.c:4884
Datum has_sequence_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:2116
Datum has_table_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:1999
Datum has_server_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:4064
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:4315
Datum has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2740
Datum has_server_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3984
Datum aclinsert(PG_FUNCTION_ARGS)
Definition: acl.c:1569
static AclMode convert_function_priv_string(text *priv_type_text)
Definition: acl.c:3554
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:1712
bool is_admin_of_role(Oid member, Oid role)
Definition: acl.c:5258
Datum has_column_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2820
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:4682
Datum has_language_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3582
Datum has_schema_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3782
Datum aclitem_eq(PG_FUNCTION_ARGS)
Definition: acl.c:731
Datum has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4234
Datum makeaclitem(PG_FUNCTION_ARGS)
Definition: acl.c:1611
Datum has_table_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:1976
Datum has_server_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4034
Datum has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2638
Datum has_language_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3690
static int column_privilege_check(Oid tableoid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: acl.c:2515
static Oid convert_type_name(text *typename)
Definition: acl.c:4543
char * get_rolespec_name(const RoleSpec *role)
Definition: acl.c:5533
Oid select_best_admin(Oid member, Oid role)
Definition: acl.c:5283
Datum aclexplode(PG_FUNCTION_ARGS)
Definition: acl.c:1768
static Oid convert_database_name(text *databasename)
Definition: acl.c:3127
Datum aclitemout(PG_FUNCTION_ARGS)
Definition: acl.c:629
Oid get_role_oid_or_public(const char *rolname)
Definition: acl.c:5432
Datum has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3223
Datum has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3304
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:4605
Datum has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3253
#define ROLES_LIST_BLOOM_THRESHOLD
Definition: acl.c:88
Datum has_database_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:2993
static uint32 cached_db_hash
Definition: acl.c:80
Datum has_type_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:4383
Datum has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2555
Datum pg_has_role_name(PG_FUNCTION_ARGS)
Definition: acl.c:4708
Datum has_sequence_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:2182
static AclMode convert_type_priv_string(text *priv_type_text)
Definition: acl.c:4564
Datum has_tablespace_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:4210
static AclMode convert_table_priv_string(text *priv_type_text)
Definition: acl.c:2041
static AclMode convert_server_priv_string(text *priv_type_text)
Definition: acl.c:4156
Datum has_table_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:1922
Datum has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3173
Datum has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4292
static Acl * recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs, Oid ownerId, DropBehavior behavior)
Definition: acl.c:1279
static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: acl.c:4914
Datum has_database_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3017
static Oid convert_schema_name(text *schemaname)
Definition: acl.c:3942
Datum has_column_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2764
static void putid(char *p, const char *s)
Definition: acl.c:201
Datum has_schema_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3890
static void check_circularity(const Acl *old_acl, const AclItem *mod_aip, Oid ownerId)
Definition: acl.c:1199
static bool has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
Definition: acl.c:4592
bool is_member_of_role(Oid member, Oid role)
Definition: acl.c:5208
Datum has_sequence_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2217
Datum has_database_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3075
static Oid convert_foreign_data_wrapper_name(text *fdwname)
Definition: acl.c:3333
Datum has_language_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3662
static AclMode convert_database_priv_string(text *priv_type_text)
Definition: acl.c:3139
Datum has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3199
Datum has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2793
Datum has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2847
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:4433
Datum has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:2369
Datum has_server_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4092
Datum has_language_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3632
Datum has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3281
Datum has_schema_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3832
Datum has_function_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3373
void select_best_grantor(Oid roleId, AclMode privileges, const Acl *acl, Oid ownerId, Oid *grantorId, AclMode *grantOptions)
Definition: acl.c:5338
Datum has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2311
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5236
Datum has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:2145
Datum has_schema_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3808
Datum acldefault_sql(PG_FUNCTION_ARGS)
Definition: acl.c:903
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5128
static Oid convert_language_name(text *languagename)
Definition: acl.c:3742
Datum has_language_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3713
static AclMode convert_any_priv_string(text *priv_type_text, const priv_map *privileges)
Definition: acl.c:1664
Datum has_database_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3098
Datum has_function_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3399
int aclmembers(const Acl *acl, Oid **roleids)
Definition: acl.c:1517
Datum has_language_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3608
Acl * aclconcat(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:460
Acl * aclcopy(const Acl *orig_acl)
Definition: acl.c:440
Datum has_server_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:4010
bool member_can_set_role(Oid member, Oid role)
Definition: acl.c:5162
Datum aclremove(PG_FUNCTION_ARGS)
Definition: acl.c:1579
Datum has_function_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3453
void aclitemsort(Acl *acl)
Definition: acl.c:528
Datum has_table_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:1950
Datum has_function_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3504
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1365
static Oid convert_server_name(text *servername)
Definition: acl.c:4144
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition: acl.c:786
static Oid convert_tablespace_name(text *tablespacename)
Definition: acl.c:4344
Acl * make_empty_acl(void)
Definition: acl.c:431
Datum has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2584
static AclMode convert_parameter_priv_string(text *priv_text)
Definition: acl.c:4653
static Oid convert_table_name(text *tablename)
Definition: acl.c:2026
Datum has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2611
static int count_one_bits(AclMode mask)
Definition: acl.c:5298
static AclMode convert_tablespace_priv_string(text *priv_type_text)
Definition: acl.c:4356
static AclMode convert_language_priv_string(text *priv_type_text)
Definition: acl.c:3754
Datum aclitemin(PG_FUNCTION_ARGS)
Definition: acl.c:598
static AclMode convert_sequence_priv_string(text *priv_type_text)
Definition: acl.c:2278
Datum pg_has_role_id(PG_FUNCTION_ARGS)
Definition: acl.c:4756
Datum has_parameter_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4635
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1096
static Acl * allocacl(int n)
Definition: acl.c:409
static AttrNumber convert_column_name(Oid tableoid, text *column)
Definition: acl.c:2875
static AclMode convert_role_priv_string(text *priv_type_text)
Definition: acl.c:4831
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5414
static Oid cached_role[]
Definition: acl.c:78
Datum has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:4184
Datum has_parameter_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:4621
Datum has_any_column_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:2341
Datum has_sequence_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2085
Datum has_function_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3423
Datum has_type_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4514
Datum has_server_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4115
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
Definition: acl.c:4854
Datum has_function_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3481
Datum has_table_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:1898
Datum has_type_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4491
Datum has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2690
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5185
static const char * aclparse(const char *s, AclItem *aip, Node *escontext)
Definition: acl.c:253
void check_rolespec_name(const RoleSpec *role, const char *detail_msg)
Definition: acl.c:5555
Datum has_type_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:4409
static List * cached_roles[]
Definition: acl.c:79
static AclMode aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1454
Datum has_tablespace_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:4264
Datum pg_has_role_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4732
Datum aclcontains(PG_FUNCTION_ARGS)
Definition: acl.c:1589
static Oid convert_function_name(text *functionname)
Definition: acl.c:3533
Datum has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2663
Datum has_schema_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3913
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5448
Datum has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2437
Datum has_database_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2967
Datum has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2715
static AclMode convert_schema_priv_string(text *priv_type_text)
Definition: acl.c:3954
static List * roles_is_member_of(Oid roleid, enum RoleRecurseType type, Oid admin_of, Oid *admin_role)
Definition: acl.c:4996
Datum has_table_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:1872
Datum has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:2464
static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text)
Definition: acl.c:3345
static List * roles_list_append(List *roles_list, bloom_filter **bf, Oid role)
Definition: acl.c:4936
Datum has_database_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3047
static int aclitemComparator(const void *arg1, const void *arg2)
Definition: acl.c:707
Datum has_type_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:4463
Datum has_any_column_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:2404
Datum pg_has_role_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4778
Acl * aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
Definition: acl.c:484
Datum has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:2245
HeapTuple get_rolespec_tuple(const RoleSpec *role)
Definition: acl.c:5487
static AclMode convert_column_priv_string(text *priv_type_text)
Definition: acl.c:2933
#define ACL_CREATE_CHR
Definition: acl.h:146
#define PG_RETURN_ACLITEM_P(x)
Definition: acl.h:118
#define ACL_ALL_RIGHTS_STR
Definition: acl.h:154
#define ACL_SET_CHR
Definition: acl.h:149
#define ACL_REFERENCES_CHR
Definition: acl.h:142
#define ACLITEM_ALL_GOPTION_BITS
Definition: acl.h:88
#define ACL_SIZE(ACL)
Definition: acl.h:111
#define PG_GETARG_ACLITEM_P(n)
Definition: acl.h:117
#define ACL_DAT(ACL)
Definition: acl.h:109
#define ACL_ALL_RIGHTS_FOREIGN_SERVER
Definition: acl.h:164
#define ACL_TRUNCATE_CHR
Definition: acl.h:141
#define ACL_ALL_RIGHTS_TABLESPACE
Definition: acl.h:170
AclResult
Definition: acl.h:182
@ ACLCHECK_NO_PRIV
Definition: acl.h:184
@ ACLCHECK_OK
Definition: acl.h:183
#define ACLITEM_GET_PRIVS(item)
Definition: acl.h:66
#define ACL_ALL_RIGHTS_PARAMETER_ACL
Definition: acl.h:168
#define ACL_SELECT_CHR
Definition: acl.h:138
#define ACL_ALL_RIGHTS_SCHEMA
Definition: acl.h:169
#define ACL_EXECUTE_CHR
Definition: acl.h:144
#define ACL_MODECHG_DEL
Definition: acl.h:130
#define ACL_DELETE_CHR
Definition: acl.h:140
#define ACL_ALL_RIGHTS_SEQUENCE
Definition: acl.h:161
#define ACL_ALL_RIGHTS_DATABASE
Definition: acl.h:162
#define ACL_MODECHG_ADD
Definition: acl.h:129
#define ACL_OPTION_TO_PRIVS(privs)
Definition: acl.h:71
#define ACL_INSERT_CHR
Definition: acl.h:137
#define ACL_UPDATE_CHR
Definition: acl.h:139
#define ACL_ALL_RIGHTS_FUNCTION
Definition: acl.h:165
#define ACL_N_SIZE(N)
Definition: acl.h:110
#define ACL_ALL_RIGHTS_LANGUAGE
Definition: acl.h:166
#define ACL_ALL_RIGHTS_TYPE
Definition: acl.h:171
#define ACL_ALTER_SYSTEM_CHR
Definition: acl.h:150
#define ACL_ALL_RIGHTS_FDW
Definition: acl.h:163
#define ACLITEM_SET_PRIVS_GOPTIONS(item, privs, goptions)
Definition: acl.h:82
#define ACL_NUM(ACL)
Definition: acl.h:108
#define ACL_USAGE_CHR
Definition: acl.h:145
#define PG_GETARG_ACL_P(n)
Definition: acl.h:122
#define ACLITEM_GET_GOPTIONS(item)
Definition: acl.h:67
#define ACLITEM_GET_RIGHTS(item)
Definition: acl.h:68
#define ACL_ALL_RIGHTS_RELATION
Definition: acl.h:160
#define ACL_MODECHG_EQL
Definition: acl.h:131
#define ACL_ID_PUBLIC
Definition: acl.h:46
#define ACL_CONNECT_CHR
Definition: acl.h:148
#define ACL_ALL_RIGHTS_LARGEOBJECT
Definition: acl.h:167
AclMaskHow
Definition: acl.h:175
@ ACLMASK_ANY
Definition: acl.h:177
@ ACLMASK_ALL
Definition: acl.h:176
#define PG_RETURN_ACL_P(x)
Definition: acl.h:124
#define ACL_TRIGGER_CHR
Definition: acl.h:143
#define ACL_CREATE_TEMP_CHR
Definition: acl.h:147
#define ACL_GRANT_OPTION_FOR(privs)
Definition: acl.h:70
#define ACLITEM_SET_RIGHTS(item, rights)
Definition: acl.h:79
#define ACL_MAINTAIN_CHR
Definition: acl.h:151
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3886
AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:4089
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3961
AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
Definition: aclchk.c:3950
AclResult pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
Definition: aclchk.c:4104
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3876
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3920
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4079
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
#define ARR_LBOUND(a)
Definition: array.h:296
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
void bloom_free(bloom_filter *filter)
Definition: bloomfilter.c:126
bloom_filter * bloom_create(int64 total_elems, int bloom_work_mem, uint64 seed)
Definition: bloomfilter.c:87
bool bloom_lacks_element(bloom_filter *filter, unsigned char *elem, size_t len)
Definition: bloomfilter.c:157
void bloom_add_element(bloom_filter *filter, unsigned char *elem, size_t len)
Definition: bloomfilter.c:135
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:733
unsigned int uint32
Definition: c.h:493
#define PointerIsValid(pointer)
Definition: c.h:750
#define OidIsValid(objectId)
Definition: c.h:762
size_t Size
Definition: c.h:592
bool IsReservedName(const char *name)
Definition: catalog.c:217
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3106
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1232
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereturn(context, dummy_value,...)
Definition: elog.h:276
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2158
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_UINT32(x)
Definition: fmgr.h:355
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_GETARG_CHAR(n)
Definition: fmgr.h:273
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define PG_GETARG_INT16(n)
Definition: fmgr.h:271
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:694
Oid get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok)
Definition: foreign.c:671
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
int work_mem
Definition: globals.c:128
Oid MyDatabaseId
Definition: globals.c:91
static Datum hash_uint32_extended(uint32 k, uint64 seed)
Definition: hashfn.h:49
static const FormData_pg_attribute a1
Definition: heap.c:142
static const FormData_pg_attribute a2
Definition: heap.c:156
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define funcname
Definition: indent_codes.h:69
int remaining
Definition: informix.c:673
#define read(a, b, c)
Definition: win32.h:13
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1516
int a
Definition: isn.c:69
int j
Definition: isn.c:74
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
List * list_copy(const List *oldlist)
Definition: list.c:1573
void list_free(List *list)
Definition: list.c:1546
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
#define NoLock
Definition: lockdefs.h:34
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1981
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1906
char * pstrdup(const char *in)
Definition: mcxt.c:1683
void pfree(void *pointer)
Definition: mcxt.c:1508
MemoryContext TopMemoryContext
Definition: mcxt.c:137
void * palloc0(Size size)
Definition: mcxt.c:1334
void * palloc(Size size)
Definition: mcxt.c:1304
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:454
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:980
Oid GetUserId(void)
Definition: miscinit.c:514
Oid GetSessionUserId(void)
Definition: miscinit.c:548
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3520
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3539
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
int oid_cmp(const void *p1, const void *p2)
Definition: oid.c:258
@ ROLESPEC_CURRENT_USER
Definition: parsenodes.h:395
@ ROLESPEC_CSTRING
Definition: parsenodes.h:393
@ ROLESPEC_SESSION_USER
Definition: parsenodes.h:396
@ ROLESPEC_CURRENT_ROLE
Definition: parsenodes.h:394
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:397
#define ACL_CREATE_TEMP
Definition: parsenodes.h:86
#define ACL_SET
Definition: parsenodes.h:88
#define ACL_DELETE
Definition: parsenodes.h:79
uint64 AclMode
Definition: parsenodes.h:74
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define ACL_INSERT
Definition: parsenodes.h:76
#define ACL_NO_RIGHTS
Definition: parsenodes.h:92
#define ACL_UPDATE
Definition: parsenodes.h:78
DropBehavior
Definition: parsenodes.h:2251
@ DROP_CASCADE
Definition: parsenodes.h:2253
@ DROP_RESTRICT
Definition: parsenodes.h:2252
ObjectType
Definition: parsenodes.h:2178
@ OBJECT_FDW
Definition: parsenodes.h:2195
@ OBJECT_SCHEMA
Definition: parsenodes.h:2215
@ OBJECT_DOMAIN
Definition: parsenodes.h:2191
@ OBJECT_COLUMN
Definition: parsenodes.h:2185
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2221
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2201
@ OBJECT_DATABASE
Definition: parsenodes.h:2188
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2216
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2200
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2196
@ OBJECT_TABLE
Definition: parsenodes.h:2220
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2206
@ OBJECT_TYPE
Definition: parsenodes.h:2228
@ OBJECT_FUNCTION
Definition: parsenodes.h:2198
#define ACL_CONNECT
Definition: parsenodes.h:87
#define ACL_ALTER_SYSTEM
Definition: parsenodes.h:89
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define ACL_SELECT
Definition: parsenodes.h:77
#define ACL_TRUNCATE
Definition: parsenodes.h:80
#define ACL_EXECUTE
Definition: parsenodes.h:83
#define ACL_CREATE
Definition: parsenodes.h:85
#define ACL_TRIGGER
Definition: parsenodes.h:82
#define N_ACL_RIGHTS
Definition: parsenodes.h:91
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
FormData_pg_auth_members * Form_pg_auth_members
NameData rolname
Definition: pg_authid.h:34
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
void * arg
static PgChecksumMode mode
Definition: pg_checksums.c:56
#define NAMEDATALEN
const void size_t len
FormData_pg_database * Form_pg_database
Definition: pg_database.h:96
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define foreach_oid(var, lst)
Definition: pg_list.h:471
#define lfirst_oid(lc)
Definition: pg_list.h:174
NameData typname
Definition: pg_type.h:41
const char * username
Definition: pgbench.c:296
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define sprintf
Definition: port.h:240
#define qsort(a, b, c, d)
Definition: port.h:449
uintptr_t Datum
Definition: postgres.h:64
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static Datum UInt64GetDatum(uint64 X)
Definition: postgres.h:436
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
Oid get_language_oid(const char *langname, bool missing_ok)
Definition: proclang.c:226
static size_t qunique(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *))
Definition: qunique.h:21
MemoryContextSwitchTo(old_ctx)
Datum regtypein(PG_FUNCTION_ARGS)
Definition: regproc.c:1176
Datum regprocedurein(PG_FUNCTION_ARGS)
Definition: regproc.c:224
static pg_noinline void Size size
Definition: slab.c:607
char * dbname
Definition: streamutil.c:52
Definition: acl.h:55
Oid ai_grantee
Definition: acl.h:56
AclMode ai_privs
Definition: acl.h:58
Oid ai_grantor
Definition: acl.h:57
Oid elemtype
Definition: array.h:97
int ndim
Definition: array.h:95
int32 dataoffset
Definition: array.h:96
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
Definition: pg_list.h:54
Definition: nodes.h:129
RoleSpecType roletype
Definition: parsenodes.h:403
char * rolename
Definition: parsenodes.h:404
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:180
int n_members
Definition: catcache.h:178
HeapTupleData tuple
Definition: catcache.h:123
Definition: c.h:728
Definition: acl.c:53
const char * name
Definition: acl.c:54
AclMode value
Definition: acl.c:55
Definition: c.h:674
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:229
#define ReleaseSysCacheList(x)
Definition: syscache.h:129
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:122
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:113
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:104
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3399
char * text_to_cstring(const text *t)
Definition: varlena.c:217
const char * type
const char * name