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