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