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