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