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