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