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