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