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