Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
acl.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * acl.c
4 * Basic access control list data structures manipulation routines.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/utils/adt/acl.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres.h"
16
17#include <ctype.h>
18
19#include "access/htup_details.h"
20#include "catalog/catalog.h"
21#include "catalog/namespace.h"
23#include "catalog/pg_authid.h"
24#include "catalog/pg_class.h"
25#include "catalog/pg_database.h"
28#include "catalog/pg_language.h"
31#include "catalog/pg_proc.h"
33#include "catalog/pg_type.h"
34#include "commands/proclang.h"
35#include "commands/tablespace.h"
36#include "common/hashfn.h"
37#include "foreign/foreign.h"
38#include "funcapi.h"
39#include "lib/bloomfilter.h"
40#include "lib/qunique.h"
41#include "miscadmin.h"
43#include "utils/acl.h"
44#include "utils/array.h"
45#include "utils/builtins.h"
46#include "utils/catcache.h"
47#include "utils/inval.h"
48#include "utils/lsyscache.h"
49#include "utils/memutils.h"
50#include "utils/snapmgr.h"
51#include "utils/syscache.h"
52#include "utils/varlena.h"
53
54typedef struct
55{
56 const char *name;
58} priv_map;
59
60/*
61 * We frequently need to test whether a given role is a member of some other
62 * role. In most of these tests the "given role" is the same, namely the
63 * active current user. So we can optimize it by keeping cached lists of all
64 * the roles the "given role" is a member of, directly or indirectly.
65 *
66 * Possibly this mechanism should be generalized to allow caching membership
67 * info for multiple roles?
68 *
69 * Each element of cached_roles is an OID list of constituent roles for the
70 * corresponding element of cached_role (always including the cached_role
71 * itself). There's a separate cache for each RoleRecurseType, with the
72 * corresponding semantics.
73 */
75{
76 ROLERECURSE_MEMBERS = 0, /* recurse unconditionally */
77 ROLERECURSE_PRIVS = 1, /* recurse through inheritable grants */
78 ROLERECURSE_SETROLE = 2 /* recurse through grants with set_option */
79};
81static List *cached_roles[] = {NIL, NIL, NIL};
83
84/*
85 * If the list of roles gathered by roles_is_member_of() grows larger than the
86 * below threshold, a Bloom filter is created to speed up list membership
87 * checks. This threshold is set arbitrarily high to avoid the overhead of
88 * creating the Bloom filter until it seems likely to provide a net benefit.
89 */
90#define ROLES_LIST_BLOOM_THRESHOLD 1024
91
92static const char *getid(const char *s, char *n, Node *escontext);
93static void putid(char *p, const char *s);
94static Acl *allocacl(int n);
95static void check_acl(const Acl *acl);
96static const char *aclparse(const char *s, AclItem *aip, Node *escontext);
97static bool aclitem_match(const AclItem *a1, const AclItem *a2);
98static int aclitemComparator(const void *arg1, const void *arg2);
99static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
100 Oid ownerId);
101static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
102 Oid ownerId, DropBehavior behavior);
103
104static AclMode convert_any_priv_string(text *priv_type_text,
105 const priv_map *privileges);
106
107static Oid convert_table_name(text *tablename);
108static AclMode convert_table_priv_string(text *priv_type_text);
109static AclMode convert_sequence_priv_string(text *priv_type_text);
110static AttrNumber convert_column_name(Oid tableoid, text *column);
111static AclMode convert_column_priv_string(text *priv_type_text);
112static Oid convert_database_name(text *databasename);
113static AclMode convert_database_priv_string(text *priv_type_text);
116static Oid convert_function_name(text *functionname);
117static AclMode convert_function_priv_string(text *priv_type_text);
118static Oid convert_language_name(text *languagename);
119static AclMode convert_language_priv_string(text *priv_type_text);
120static Oid convert_schema_name(text *schemaname);
121static AclMode convert_schema_priv_string(text *priv_type_text);
122static Oid convert_server_name(text *servername);
123static AclMode convert_server_priv_string(text *priv_type_text);
124static Oid convert_tablespace_name(text *tablespacename);
125static AclMode convert_tablespace_priv_string(text *priv_type_text);
126static Oid convert_type_name(text *typename);
127static AclMode convert_type_priv_string(text *priv_type_text);
129static AclMode convert_largeobject_priv_string(text *priv_type_text);
130static AclMode convert_role_priv_string(text *priv_type_text);
131static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
132
133static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
134
135
136/*
137 * Test whether an identifier char can be left unquoted in ACLs.
138 *
139 * Formerly, we used isalnum() even on non-ASCII characters, resulting in
140 * unportable behavior. To ensure dump compatibility with old versions,
141 * we now treat high-bit-set characters as always requiring quoting during
142 * putid(), but getid() will always accept them without quotes.
143 */
144static inline bool
145is_safe_acl_char(unsigned char c, bool is_getid)
146{
147 if (IS_HIGHBIT_SET(c))
148 return is_getid;
149 return isalnum(c) || c == '_';
150}
151
152/*
153 * getid
154 * Consumes the first alphanumeric string (identifier) found in string
155 * 's', ignoring any leading white space. If it finds a double quote
156 * it returns the word inside the quotes.
157 *
158 * RETURNS:
159 * the string position in 's' that points to the next non-space character
160 * in 's', after any quotes. Also:
161 * - loads the identifier into 'n'. (If no identifier is found, 'n'
162 * contains an empty string.) 'n' must be NAMEDATALEN bytes.
163 *
164 * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
165 * in which case we log the error there and return NULL.
166 */
167static const char *
168getid(const char *s, char *n, Node *escontext)
169{
170 int len = 0;
171 bool in_quotes = false;
172
173 Assert(s && n);
174
175 while (isspace((unsigned char) *s))
176 s++;
177 for (;
178 *s != '\0' &&
179 (in_quotes || *s == '"' || is_safe_acl_char(*s, true));
180 s++)
181 {
182 if (*s == '"')
183 {
184 if (!in_quotes)
185 {
186 in_quotes = true;
187 continue;
188 }
189 /* safe to look at next char (could be '\0' though) */
190 if (*(s + 1) != '"')
191 {
192 in_quotes = false;
193 continue;
194 }
195 /* it's an escaped double quote; skip the escaping char */
196 s++;
197 }
198
199 /* Add the character to the string */
200 if (len >= NAMEDATALEN - 1)
201 ereturn(escontext, NULL,
202 (errcode(ERRCODE_NAME_TOO_LONG),
203 errmsg("identifier too long"),
204 errdetail("Identifier must be less than %d characters.",
205 NAMEDATALEN)));
206
207 n[len++] = *s;
208 }
209 n[len] = '\0';
210 while (isspace((unsigned char) *s))
211 s++;
212 return s;
213}
214
215/*
216 * Write a role name at *p, adding double quotes if needed.
217 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
218 * This needs to be kept in sync with dequoteAclUserName in pg_dump/dumputils.c
219 */
220static void
221putid(char *p, const char *s)
222{
223 const char *src;
224 bool safe = true;
225
226 /* Detect whether we need to use double quotes */
227 for (src = s; *src; src++)
228 {
229 if (!is_safe_acl_char(*src, false))
230 {
231 safe = false;
232 break;
233 }
234 }
235 if (!safe)
236 *p++ = '"';
237 for (src = s; *src; src++)
238 {
239 /* A double quote character in a username is encoded as "" */
240 if (*src == '"')
241 *p++ = '"';
242 *p++ = *src;
243 }
244 if (!safe)
245 *p++ = '"';
246 *p = '\0';
247}
248
249/*
250 * aclparse
251 * Consumes and parses an ACL specification of the form:
252 * [group|user] [A-Za-z0-9]*=[rwaR]*
253 * from string 's', ignoring any leading white space or white space
254 * between the optional id type keyword (group|user) and the actual
255 * ACL specification.
256 *
257 * The group|user decoration is unnecessary in the roles world,
258 * but we still accept it for backward compatibility.
259 *
260 * This routine is called by the parser as well as aclitemin(), hence
261 * the added generality.
262 *
263 * RETURNS:
264 * the string position in 's' immediately following the ACL
265 * specification. Also:
266 * - loads the structure pointed to by 'aip' with the appropriate
267 * UID/GID, id type identifier and mode type values.
268 *
269 * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
270 * in which case we log the error there and return NULL.
271 */
272static const char *
273aclparse(const char *s, AclItem *aip, Node *escontext)
274{
275 AclMode privs,
276 goption,
277 read;
278 char name[NAMEDATALEN];
279 char name2[NAMEDATALEN];
280
281 Assert(s && aip);
282
283 s = getid(s, name, escontext);
284 if (s == NULL)
285 return NULL;
286 if (*s != '=')
287 {
288 /* we just read a keyword, not a name */
289 if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
290 ereturn(escontext, NULL,
291 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
292 errmsg("unrecognized key word: \"%s\"", name),
293 errhint("ACL key word must be \"group\" or \"user\".")));
294 /* move s to the name beyond the keyword */
295 s = getid(s, name, escontext);
296 if (s == NULL)
297 return NULL;
298 if (name[0] == '\0')
299 ereturn(escontext, NULL,
300 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
301 errmsg("missing name"),
302 errhint("A name must follow the \"group\" or \"user\" key word.")));
303 }
304
305 if (*s != '=')
306 ereturn(escontext, NULL,
307 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
308 errmsg("missing \"=\" sign")));
309
310 privs = goption = ACL_NO_RIGHTS;
311
312 for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
313 {
314 switch (*s)
315 {
316 case '*':
317 goption |= read;
318 break;
319 case ACL_INSERT_CHR:
321 break;
322 case ACL_SELECT_CHR:
324 break;
325 case ACL_UPDATE_CHR:
327 break;
328 case ACL_DELETE_CHR:
330 break;
331 case ACL_TRUNCATE_CHR:
333 break;
336 break;
337 case ACL_TRIGGER_CHR:
339 break;
340 case ACL_EXECUTE_CHR:
342 break;
343 case ACL_USAGE_CHR:
344 read = ACL_USAGE;
345 break;
346 case ACL_CREATE_CHR:
348 break;
351 break;
352 case ACL_CONNECT_CHR:
354 break;
355 case ACL_SET_CHR:
356 read = ACL_SET;
357 break;
360 break;
361 case ACL_MAINTAIN_CHR:
363 break;
364 default:
365 ereturn(escontext, NULL,
366 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
367 errmsg("invalid mode character: must be one of \"%s\"",
369 }
370
371 privs |= read;
372 }
373
374 if (name[0] == '\0')
376 else
377 {
378 aip->ai_grantee = get_role_oid(name, true);
379 if (!OidIsValid(aip->ai_grantee))
380 ereturn(escontext, NULL,
381 (errcode(ERRCODE_UNDEFINED_OBJECT),
382 errmsg("role \"%s\" does not exist", name)));
383 }
384
385 /*
386 * XXX Allow a degree of backward compatibility by defaulting the grantor
387 * to the superuser.
388 */
389 if (*s == '/')
390 {
391 s = getid(s + 1, name2, escontext);
392 if (s == NULL)
393 return NULL;
394 if (name2[0] == '\0')
395 ereturn(escontext, NULL,
396 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
397 errmsg("a name must follow the \"/\" sign")));
398 aip->ai_grantor = get_role_oid(name2, true);
399 if (!OidIsValid(aip->ai_grantor))
400 ereturn(escontext, NULL,
401 (errcode(ERRCODE_UNDEFINED_OBJECT),
402 errmsg("role \"%s\" does not exist", name2)));
403 }
404 else
405 {
406 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
408 (errcode(ERRCODE_INVALID_GRANTOR),
409 errmsg("defaulting grantor to user ID %u",
410 BOOTSTRAP_SUPERUSERID)));
411 }
412
413 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
414
415 return s;
416}
417
418/*
419 * allocacl
420 * Allocates storage for a new Acl with 'n' entries.
421 *
422 * RETURNS:
423 * the new Acl
424 */
425static Acl *
427{
428 Acl *new_acl;
429 Size size;
430
431 if (n < 0)
432 elog(ERROR, "invalid size: %d", n);
433 size = ACL_N_SIZE(n);
434 new_acl = (Acl *) palloc0(size);
435 SET_VARSIZE(new_acl, size);
436 new_acl->ndim = 1;
437 new_acl->dataoffset = 0; /* we never put in any nulls */
438 new_acl->elemtype = ACLITEMOID;
439 ARR_LBOUND(new_acl)[0] = 1;
440 ARR_DIMS(new_acl)[0] = n;
441 return new_acl;
442}
443
444/*
445 * Create a zero-entry ACL
446 */
447Acl *
449{
450 return allocacl(0);
451}
452
453/*
454 * Copy an ACL
455 */
456Acl *
457aclcopy(const Acl *orig_acl)
458{
459 Acl *result_acl;
460
461 result_acl = allocacl(ACL_NUM(orig_acl));
462
463 memcpy(ACL_DAT(result_acl),
464 ACL_DAT(orig_acl),
465 ACL_NUM(orig_acl) * sizeof(AclItem));
466
467 return result_acl;
468}
469
470/*
471 * Concatenate two ACLs
472 *
473 * This is a bit cheesy, since we may produce an ACL with redundant entries.
474 * Be careful what the result is used for!
475 */
476Acl *
477aclconcat(const Acl *left_acl, const Acl *right_acl)
478{
479 Acl *result_acl;
480
481 result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
482
483 memcpy(ACL_DAT(result_acl),
484 ACL_DAT(left_acl),
485 ACL_NUM(left_acl) * sizeof(AclItem));
486
487 memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
488 ACL_DAT(right_acl),
489 ACL_NUM(right_acl) * sizeof(AclItem));
490
491 return result_acl;
492}
493
494/*
495 * Merge two ACLs
496 *
497 * This produces a properly merged ACL with no redundant entries.
498 * Returns NULL on NULL input.
499 */
500Acl *
501aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
502{
503 Acl *result_acl;
504 AclItem *aip;
505 int i,
506 num;
507
508 /* Check for cases where one or both are empty/null */
509 if (left_acl == NULL || ACL_NUM(left_acl) == 0)
510 {
511 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
512 return NULL;
513 else
514 return aclcopy(right_acl);
515 }
516 else
517 {
518 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
519 return aclcopy(left_acl);
520 }
521
522 /* Merge them the hard way, one item at a time */
523 result_acl = aclcopy(left_acl);
524
525 aip = ACL_DAT(right_acl);
526 num = ACL_NUM(right_acl);
527
528 for (i = 0; i < num; i++, aip++)
529 {
530 Acl *tmp_acl;
531
532 tmp_acl = aclupdate(result_acl, aip, ACL_MODECHG_ADD,
533 ownerId, DROP_RESTRICT);
534 pfree(result_acl);
535 result_acl = tmp_acl;
536 }
537
538 return result_acl;
539}
540
541/*
542 * Sort the items in an ACL (into an arbitrary but consistent order)
543 */
544void
546{
547 if (acl != NULL && ACL_NUM(acl) > 1)
548 qsort(ACL_DAT(acl), ACL_NUM(acl), sizeof(AclItem), aclitemComparator);
549}
550
551/*
552 * Check if two ACLs are exactly equal
553 *
554 * This will not detect equality if the two arrays contain the same items
555 * in different orders. To handle that case, sort both inputs first,
556 * using aclitemsort().
557 */
558bool
559aclequal(const Acl *left_acl, const Acl *right_acl)
560{
561 /* Check for cases where one or both are empty/null */
562 if (left_acl == NULL || ACL_NUM(left_acl) == 0)
563 {
564 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
565 return true;
566 else
567 return false;
568 }
569 else
570 {
571 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
572 return false;
573 }
574
575 if (ACL_NUM(left_acl) != ACL_NUM(right_acl))
576 return false;
577
578 if (memcmp(ACL_DAT(left_acl),
579 ACL_DAT(right_acl),
580 ACL_NUM(left_acl) * sizeof(AclItem)) == 0)
581 return true;
582
583 return false;
584}
585
586/*
587 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
588 */
589static void
590check_acl(const Acl *acl)
591{
592 if (ARR_ELEMTYPE(acl) != ACLITEMOID)
594 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
595 errmsg("ACL array contains wrong data type")));
596 if (ARR_NDIM(acl) != 1)
598 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
599 errmsg("ACL arrays must be one-dimensional")));
600 if (ARR_HASNULL(acl))
602 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
603 errmsg("ACL arrays must not contain null values")));
604}
605
606/*
607 * aclitemin
608 * Allocates storage for, and fills in, a new AclItem given a string
609 * 's' that contains an ACL specification. See aclparse for details.
610 *
611 * RETURNS:
612 * the new AclItem
613 */
614Datum
616{
617 const char *s = PG_GETARG_CSTRING(0);
618 Node *escontext = fcinfo->context;
619 AclItem *aip;
620
621 aip = (AclItem *) palloc(sizeof(AclItem));
622
623 s = aclparse(s, aip, escontext);
624 if (s == NULL)
626
627 while (isspace((unsigned char) *s))
628 ++s;
629 if (*s)
630 ereturn(escontext, (Datum) 0,
631 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
632 errmsg("extra garbage at the end of the ACL specification")));
633
635}
636
637/*
638 * aclitemout
639 * Allocates storage for, and fills in, a new null-delimited string
640 * containing a formatted ACL specification. See aclparse for details.
641 *
642 * RETURNS:
643 * the new string
644 */
645Datum
647{
649 char *p;
650 char *out;
651 HeapTuple htup;
652 unsigned i;
653
654 out = palloc(strlen("=/") +
655 2 * N_ACL_RIGHTS +
656 2 * (2 * NAMEDATALEN + 2) +
657 1);
658
659 p = out;
660 *p = '\0';
661
662 if (aip->ai_grantee != ACL_ID_PUBLIC)
663 {
664 htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantee));
665 if (HeapTupleIsValid(htup))
666 {
668 ReleaseSysCache(htup);
669 }
670 else
671 {
672 /* Generate numeric OID if we don't find an entry */
673 sprintf(p, "%u", aip->ai_grantee);
674 }
675 }
676 while (*p)
677 ++p;
678
679 *p++ = '=';
680
681 for (i = 0; i < N_ACL_RIGHTS; ++i)
682 {
683 if (ACLITEM_GET_PRIVS(*aip) & (UINT64CONST(1) << i))
684 *p++ = ACL_ALL_RIGHTS_STR[i];
685 if (ACLITEM_GET_GOPTIONS(*aip) & (UINT64CONST(1) << i))
686 *p++ = '*';
687 }
688
689 *p++ = '/';
690 *p = '\0';
691
692 htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantor));
693 if (HeapTupleIsValid(htup))
694 {
696 ReleaseSysCache(htup);
697 }
698 else
699 {
700 /* Generate numeric OID if we don't find an entry */
701 sprintf(p, "%u", aip->ai_grantor);
702 }
703
705}
706
707/*
708 * aclitem_match
709 * Two AclItems are considered to match iff they have the same
710 * grantee and grantor; the privileges are ignored.
711 */
712static bool
714{
715 return a1->ai_grantee == a2->ai_grantee &&
716 a1->ai_grantor == a2->ai_grantor;
717}
718
719/*
720 * aclitemComparator
721 * qsort comparison function for AclItems
722 */
723static int
724aclitemComparator(const void *arg1, const void *arg2)
725{
726 const AclItem *a1 = (const AclItem *) arg1;
727 const AclItem *a2 = (const AclItem *) arg2;
728
729 if (a1->ai_grantee > a2->ai_grantee)
730 return 1;
731 if (a1->ai_grantee < a2->ai_grantee)
732 return -1;
733 if (a1->ai_grantor > a2->ai_grantor)
734 return 1;
735 if (a1->ai_grantor < a2->ai_grantor)
736 return -1;
737 if (a1->ai_privs > a2->ai_privs)
738 return 1;
739 if (a1->ai_privs < a2->ai_privs)
740 return -1;
741 return 0;
742}
743
744/*
745 * aclitem equality operator
746 */
747Datum
749{
752 bool result;
753
754 result = a1->ai_privs == a2->ai_privs &&
755 a1->ai_grantee == a2->ai_grantee &&
756 a1->ai_grantor == a2->ai_grantor;
757 PG_RETURN_BOOL(result);
758}
759
760/*
761 * aclitem hash function
762 *
763 * We make aclitems hashable not so much because anyone is likely to hash
764 * them, as because we want array equality to work on aclitem arrays, and
765 * with the typcache mechanism we must have a hash or btree opclass.
766 */
767Datum
769{
771
772 /* not very bright, but avoids any issue of padding in struct */
773 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
774}
775
776/*
777 * 64-bit hash function for aclitem.
778 *
779 * Similar to hash_aclitem, but accepts a seed and returns a uint64 value.
780 */
781Datum
783{
785 uint64 seed = PG_GETARG_INT64(1);
786 uint32 sum = (uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor);
787
788 return (seed == 0) ? UInt64GetDatum(sum) : hash_uint32_extended(sum, seed);
789}
790
791/*
792 * acldefault() --- create an ACL describing default access permissions
793 *
794 * Change this routine if you want to alter the default access policy for
795 * newly-created objects (or any object with a NULL acl entry). When
796 * you make a change here, don't forget to update the GRANT man page,
797 * which explains all the default permissions.
798 *
799 * Note that these are the hard-wired "defaults" that are used in the
800 * absence of any pg_default_acl entry.
801 */
802Acl *
803acldefault(ObjectType objtype, Oid ownerId)
804{
805 AclMode world_default;
806 AclMode owner_default;
807 int nacl;
808 Acl *acl;
809 AclItem *aip;
810
811 switch (objtype)
812 {
813 case OBJECT_COLUMN:
814 /* by default, columns have no extra privileges */
815 world_default = ACL_NO_RIGHTS;
816 owner_default = ACL_NO_RIGHTS;
817 break;
818 case OBJECT_TABLE:
819 world_default = ACL_NO_RIGHTS;
820 owner_default = ACL_ALL_RIGHTS_RELATION;
821 break;
822 case OBJECT_SEQUENCE:
823 world_default = ACL_NO_RIGHTS;
824 owner_default = ACL_ALL_RIGHTS_SEQUENCE;
825 break;
826 case OBJECT_DATABASE:
827 /* for backwards compatibility, grant some rights by default */
828 world_default = ACL_CREATE_TEMP | ACL_CONNECT;
829 owner_default = ACL_ALL_RIGHTS_DATABASE;
830 break;
831 case OBJECT_FUNCTION:
832 /* Grant EXECUTE by default, for now */
833 world_default = ACL_EXECUTE;
834 owner_default = ACL_ALL_RIGHTS_FUNCTION;
835 break;
836 case OBJECT_LANGUAGE:
837 /* Grant USAGE by default, for now */
838 world_default = ACL_USAGE;
839 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
840 break;
842 world_default = ACL_NO_RIGHTS;
843 owner_default = ACL_ALL_RIGHTS_LARGEOBJECT;
844 break;
845 case OBJECT_SCHEMA:
846 world_default = ACL_NO_RIGHTS;
847 owner_default = ACL_ALL_RIGHTS_SCHEMA;
848 break;
850 world_default = ACL_NO_RIGHTS;
851 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
852 break;
853 case OBJECT_FDW:
854 world_default = ACL_NO_RIGHTS;
855 owner_default = ACL_ALL_RIGHTS_FDW;
856 break;
858 world_default = ACL_NO_RIGHTS;
859 owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
860 break;
861 case OBJECT_DOMAIN:
862 case OBJECT_TYPE:
863 world_default = ACL_USAGE;
864 owner_default = ACL_ALL_RIGHTS_TYPE;
865 break;
867 world_default = ACL_NO_RIGHTS;
868 owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
869 break;
870 default:
871 elog(ERROR, "unrecognized object type: %d", (int) objtype);
872 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
873 owner_default = ACL_NO_RIGHTS;
874 break;
875 }
876
877 nacl = 0;
878 if (world_default != ACL_NO_RIGHTS)
879 nacl++;
880 if (owner_default != ACL_NO_RIGHTS)
881 nacl++;
882
883 acl = allocacl(nacl);
884 aip = ACL_DAT(acl);
885
886 if (world_default != ACL_NO_RIGHTS)
887 {
889 aip->ai_grantor = ownerId;
890 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
891 aip++;
892 }
893
894 /*
895 * Note that the owner's entry shows all ordinary privileges but no grant
896 * options. This is because his grant options come "from the system" and
897 * not from his own efforts. (The SQL spec says that the owner's rights
898 * come from a "_SYSTEM" authid.) However, we do consider that the
899 * owner's ordinary privileges are self-granted; this lets him revoke
900 * them. We implement the owner's grant options without any explicit
901 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
902 * wherever we are testing grant options.
903 */
904 if (owner_default != ACL_NO_RIGHTS)
905 {
906 aip->ai_grantee = ownerId;
907 aip->ai_grantor = ownerId;
908 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
909 }
910
911 return acl;
912}
913
914
915/*
916 * SQL-accessible version of acldefault(). Hackish mapping from "char" type to
917 * OBJECT_* values.
918 */
919Datum
921{
922 char objtypec = PG_GETARG_CHAR(0);
923 Oid owner = PG_GETARG_OID(1);
924 ObjectType objtype = 0;
925
926 switch (objtypec)
927 {
928 case 'c':
929 objtype = OBJECT_COLUMN;
930 break;
931 case 'r':
932 objtype = OBJECT_TABLE;
933 break;
934 case 's':
935 objtype = OBJECT_SEQUENCE;
936 break;
937 case 'd':
938 objtype = OBJECT_DATABASE;
939 break;
940 case 'f':
941 objtype = OBJECT_FUNCTION;
942 break;
943 case 'l':
944 objtype = OBJECT_LANGUAGE;
945 break;
946 case 'L':
947 objtype = OBJECT_LARGEOBJECT;
948 break;
949 case 'n':
950 objtype = OBJECT_SCHEMA;
951 break;
952 case 'p':
953 objtype = OBJECT_PARAMETER_ACL;
954 break;
955 case 't':
956 objtype = OBJECT_TABLESPACE;
957 break;
958 case 'F':
959 objtype = OBJECT_FDW;
960 break;
961 case 'S':
962 objtype = OBJECT_FOREIGN_SERVER;
963 break;
964 case 'T':
965 objtype = OBJECT_TYPE;
966 break;
967 default:
968 elog(ERROR, "unrecognized object type abbreviation: %c", objtypec);
969 }
970
971 PG_RETURN_ACL_P(acldefault(objtype, owner));
972}
973
974
975/*
976 * Update an ACL array to add or remove specified privileges.
977 *
978 * old_acl: the input ACL array
979 * mod_aip: defines the privileges to be added, removed, or substituted
980 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
981 * ownerId: Oid of object owner
982 * behavior: RESTRICT or CASCADE behavior for recursive removal
983 *
984 * ownerid and behavior are only relevant when the update operation specifies
985 * deletion of grant options.
986 *
987 * The result is a modified copy; the input object is not changed.
988 *
989 * NB: caller is responsible for having detoasted the input ACL, if needed.
990 */
991Acl *
992aclupdate(const Acl *old_acl, const AclItem *mod_aip,
993 int modechg, Oid ownerId, DropBehavior behavior)
994{
995 Acl *new_acl = NULL;
996 AclItem *old_aip,
997 *new_aip = NULL;
998 AclMode old_rights,
999 old_goptions,
1000 new_rights,
1001 new_goptions;
1002 int dst,
1003 num;
1004
1005 /* Caller probably already checked old_acl, but be safe */
1006 check_acl(old_acl);
1007
1008 /* If granting grant options, check for circularity */
1009 if (modechg != ACL_MODECHG_DEL &&
1011 check_circularity(old_acl, mod_aip, ownerId);
1012
1013 num = ACL_NUM(old_acl);
1014 old_aip = ACL_DAT(old_acl);
1015
1016 /*
1017 * Search the ACL for an existing entry for this grantee and grantor. If
1018 * one exists, just modify the entry in-place (well, in the same position,
1019 * since we actually return a copy); otherwise, insert the new entry at
1020 * the end.
1021 */
1022
1023 for (dst = 0; dst < num; ++dst)
1024 {
1025 if (aclitem_match(mod_aip, old_aip + dst))
1026 {
1027 /* found a match, so modify existing item */
1028 new_acl = allocacl(num);
1029 new_aip = ACL_DAT(new_acl);
1030 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
1031 break;
1032 }
1033 }
1034
1035 if (dst == num)
1036 {
1037 /* need to append a new item */
1038 new_acl = allocacl(num + 1);
1039 new_aip = ACL_DAT(new_acl);
1040 memcpy(new_aip, old_aip, num * sizeof(AclItem));
1041
1042 /* initialize the new entry with no permissions */
1043 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
1044 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
1045 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
1047 num++; /* set num to the size of new_acl */
1048 }
1049
1050 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
1051 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
1052
1053 /* apply the specified permissions change */
1054 switch (modechg)
1055 {
1056 case ACL_MODECHG_ADD:
1057 ACLITEM_SET_RIGHTS(new_aip[dst],
1058 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
1059 break;
1060 case ACL_MODECHG_DEL:
1061 ACLITEM_SET_RIGHTS(new_aip[dst],
1062 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
1063 break;
1064 case ACL_MODECHG_EQL:
1065 ACLITEM_SET_RIGHTS(new_aip[dst],
1066 ACLITEM_GET_RIGHTS(*mod_aip));
1067 break;
1068 }
1069
1070 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
1071 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
1072
1073 /*
1074 * If the adjusted entry has no permissions, delete it from the list.
1075 */
1076 if (new_rights == ACL_NO_RIGHTS)
1077 {
1078 memmove(new_aip + dst,
1079 new_aip + dst + 1,
1080 (num - dst - 1) * sizeof(AclItem));
1081 /* Adjust array size to be 'num - 1' items */
1082 ARR_DIMS(new_acl)[0] = num - 1;
1083 SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
1084 }
1085
1086 /*
1087 * Remove abandoned privileges (cascading revoke). Currently we can only
1088 * handle this when the grantee is not PUBLIC.
1089 */
1090 if ((old_goptions & ~new_goptions) != 0)
1091 {
1092 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
1093 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
1094 (old_goptions & ~new_goptions),
1095 ownerId, behavior);
1096 }
1097
1098 return new_acl;
1099}
1100
1101/*
1102 * Update an ACL array to reflect a change of owner to the parent object
1103 *
1104 * old_acl: the input ACL array (must not be NULL)
1105 * oldOwnerId: Oid of the old object owner
1106 * newOwnerId: Oid of the new object owner
1107 *
1108 * The result is a modified copy; the input object is not changed.
1109 *
1110 * NB: caller is responsible for having detoasted the input ACL, if needed.
1111 *
1112 * Note: the name of this function is a bit of a misnomer, since it will
1113 * happily make the specified role substitution whether the old role is
1114 * really the owner of the parent object or merely mentioned in its ACL.
1115 * But the vast majority of callers use it in connection with ALTER OWNER
1116 * operations, so we'll keep the name.
1117 */
1118Acl *
1119aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
1120{
1121 Acl *new_acl;
1122 AclItem *new_aip;
1123 AclItem *old_aip;
1124 AclItem *dst_aip;
1125 AclItem *src_aip;
1126 AclItem *targ_aip;
1127 bool newpresent = false;
1128 int dst,
1129 src,
1130 targ,
1131 num;
1132
1133 check_acl(old_acl);
1134
1135 /*
1136 * Make a copy of the given ACL, substituting new owner ID for old
1137 * wherever it appears as either grantor or grantee. Also note if the new
1138 * owner ID is already present.
1139 */
1140 num = ACL_NUM(old_acl);
1141 old_aip = ACL_DAT(old_acl);
1142 new_acl = allocacl(num);
1143 new_aip = ACL_DAT(new_acl);
1144 memcpy(new_aip, old_aip, num * sizeof(AclItem));
1145 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
1146 {
1147 if (dst_aip->ai_grantor == oldOwnerId)
1148 dst_aip->ai_grantor = newOwnerId;
1149 else if (dst_aip->ai_grantor == newOwnerId)
1150 newpresent = true;
1151 if (dst_aip->ai_grantee == oldOwnerId)
1152 dst_aip->ai_grantee = newOwnerId;
1153 else if (dst_aip->ai_grantee == newOwnerId)
1154 newpresent = true;
1155 }
1156
1157 /*
1158 * If the old ACL contained any references to the new owner, then we may
1159 * now have generated an ACL containing duplicate entries. Find them and
1160 * merge them so that there are not duplicates. (This is relatively
1161 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
1162 * be the normal case.)
1163 *
1164 * To simplify deletion of duplicate entries, we temporarily leave them in
1165 * the array but set their privilege masks to zero; when we reach such an
1166 * entry it's just skipped. (Thus, a side effect of this code will be to
1167 * remove privilege-free entries, should there be any in the input.) dst
1168 * is the next output slot, targ is the currently considered input slot
1169 * (always >= dst), and src scans entries to the right of targ looking for
1170 * duplicates. Once an entry has been emitted to dst it is known
1171 * duplicate-free and need not be considered anymore.
1172 */
1173 if (newpresent)
1174 {
1175 dst = 0;
1176 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
1177 {
1178 /* ignore if deleted in an earlier pass */
1179 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
1180 continue;
1181 /* find and merge any duplicates */
1182 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
1183 src++, src_aip++)
1184 {
1185 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
1186 continue;
1187 if (aclitem_match(targ_aip, src_aip))
1188 {
1189 ACLITEM_SET_RIGHTS(*targ_aip,
1190 ACLITEM_GET_RIGHTS(*targ_aip) |
1191 ACLITEM_GET_RIGHTS(*src_aip));
1192 /* mark the duplicate deleted */
1194 }
1195 }
1196 /* and emit to output */
1197 new_aip[dst] = *targ_aip;
1198 dst++;
1199 }
1200 /* Adjust array size to be 'dst' items */
1201 ARR_DIMS(new_acl)[0] = dst;
1202 SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
1203 }
1204
1205 return new_acl;
1206}
1207
1208
1209/*
1210 * When granting grant options, we must disallow attempts to set up circular
1211 * chains of grant options. Suppose A (the object owner) grants B some
1212 * privileges with grant option, and B re-grants them to C. If C could
1213 * grant the privileges to B as well, then A would be unable to effectively
1214 * revoke the privileges from B, since recursive_revoke would consider that
1215 * B still has 'em from C.
1216 *
1217 * We check for this by recursively deleting all grant options belonging to
1218 * the target grantee, and then seeing if the would-be grantor still has the
1219 * grant option or not.
1220 */
1221static void
1222check_circularity(const Acl *old_acl, const AclItem *mod_aip,
1223 Oid ownerId)
1224{
1225 Acl *acl;
1226 AclItem *aip;
1227 int i,
1228 num;
1229 AclMode own_privs;
1230
1231 check_acl(old_acl);
1232
1233 /*
1234 * For now, grant options can only be granted to roles, not PUBLIC.
1235 * Otherwise we'd have to work a bit harder here.
1236 */
1237 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
1238
1239 /* The owner always has grant options, no need to check */
1240 if (mod_aip->ai_grantor == ownerId)
1241 return;
1242
1243 /* Make a working copy */
1244 acl = allocacl(ACL_NUM(old_acl));
1245 memcpy(acl, old_acl, ACL_SIZE(old_acl));
1246
1247 /* Zap all grant options of target grantee, plus what depends on 'em */
1248cc_restart:
1249 num = ACL_NUM(acl);
1250 aip = ACL_DAT(acl);
1251 for (i = 0; i < num; i++)
1252 {
1253 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
1255 {
1256 Acl *new_acl;
1257
1258 /* We'll actually zap ordinary privs too, but no matter */
1259 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
1260 ownerId, DROP_CASCADE);
1261
1262 pfree(acl);
1263 acl = new_acl;
1264
1265 goto cc_restart;
1266 }
1267 }
1268
1269 /* Now we can compute grantor's independently-derived privileges */
1270 own_privs = aclmask(acl,
1271 mod_aip->ai_grantor,
1272 ownerId,
1274 ACLMASK_ALL);
1275 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
1276
1277 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
1278 ereport(ERROR,
1279 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1280 errmsg("grant options cannot be granted back to your own grantor")));
1281
1282 pfree(acl);
1283}
1284
1285
1286/*
1287 * Ensure that no privilege is "abandoned". A privilege is abandoned
1288 * if the user that granted the privilege loses the grant option. (So
1289 * the chain through which it was granted is broken.) Either the
1290 * abandoned privileges are revoked as well, or an error message is
1291 * printed, depending on the drop behavior option.
1292 *
1293 * acl: the input ACL list
1294 * grantee: the user from whom some grant options have been revoked
1295 * revoke_privs: the grant options being revoked
1296 * ownerId: Oid of object owner
1297 * behavior: RESTRICT or CASCADE behavior for recursive removal
1298 *
1299 * The input Acl object is pfree'd if replaced.
1300 */
1301static Acl *
1303 Oid grantee,
1304 AclMode revoke_privs,
1305 Oid ownerId,
1306 DropBehavior behavior)
1307{
1308 AclMode still_has;
1309 AclItem *aip;
1310 int i,
1311 num;
1312
1313 check_acl(acl);
1314
1315 /* The owner can never truly lose grant options, so short-circuit */
1316 if (grantee == ownerId)
1317 return acl;
1318
1319 /* The grantee might still have some grant options via another grantor */
1320 still_has = aclmask(acl, grantee, ownerId,
1321 ACL_GRANT_OPTION_FOR(revoke_privs),
1322 ACLMASK_ALL);
1323 revoke_privs &= ~ACL_OPTION_TO_PRIVS(still_has);
1324 if (revoke_privs == ACL_NO_RIGHTS)
1325 return acl;
1326
1327restart:
1328 num = ACL_NUM(acl);
1329 aip = ACL_DAT(acl);
1330 for (i = 0; i < num; i++)
1331 {
1332 if (aip[i].ai_grantor == grantee
1333 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1334 {
1335 AclItem mod_acl;
1336 Acl *new_acl;
1337
1338 if (behavior == DROP_RESTRICT)
1339 ereport(ERROR,
1340 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1341 errmsg("dependent privileges exist"),
1342 errhint("Use CASCADE to revoke them too.")));
1343
1344 mod_acl.ai_grantor = grantee;
1345 mod_acl.ai_grantee = aip[i].ai_grantee;
1347 revoke_privs,
1348 revoke_privs);
1349
1350 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1351 ownerId, behavior);
1352
1353 pfree(acl);
1354 acl = new_acl;
1355
1356 goto restart;
1357 }
1358 }
1359
1360 return acl;
1361}
1362
1363
1364/*
1365 * aclmask --- compute bitmask of all privileges held by roleid.
1366 *
1367 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1368 * held by the given roleid according to the given ACL list, ANDed
1369 * with 'mask'. (The point of passing 'mask' is to let the routine
1370 * exit early if all privileges of interest have been found.)
1371 *
1372 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1373 * is known true. (This lets us exit soonest in cases where the
1374 * caller is only going to test for zero or nonzero result.)
1375 *
1376 * Usage patterns:
1377 *
1378 * To see if any of a set of privileges are held:
1379 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1380 *
1381 * To see if all of a set of privileges are held:
1382 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1383 *
1384 * To determine exactly which of a set of privileges are held:
1385 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1386 */
1387AclMode
1388aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1389 AclMode mask, AclMaskHow how)
1390{
1391 AclMode result;
1393 AclItem *aidat;
1394 int i,
1395 num;
1396
1397 /*
1398 * Null ACL should not happen, since caller should have inserted
1399 * appropriate default
1400 */
1401 if (acl == NULL)
1402 elog(ERROR, "null ACL");
1403
1404 check_acl(acl);
1405
1406 /* Quick exit for mask == 0 */
1407 if (mask == 0)
1408 return 0;
1409
1410 result = 0;
1411
1412 /* Owner always implicitly has all grant options */
1413 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1414 has_privs_of_role(roleid, ownerId))
1415 {
1416 result = mask & ACLITEM_ALL_GOPTION_BITS;
1417 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1418 return result;
1419 }
1420
1421 num = ACL_NUM(acl);
1422 aidat = ACL_DAT(acl);
1423
1424 /*
1425 * Check privileges granted directly to roleid or to public
1426 */
1427 for (i = 0; i < num; i++)
1428 {
1429 AclItem *aidata = &aidat[i];
1430
1431 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1432 aidata->ai_grantee == roleid)
1433 {
1434 result |= aidata->ai_privs & mask;
1435 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1436 return result;
1437 }
1438 }
1439
1440 /*
1441 * Check privileges granted indirectly via role memberships. We do this in
1442 * a separate pass to minimize expensive indirect membership tests. In
1443 * particular, it's worth testing whether a given ACL entry grants any
1444 * privileges still of interest before we perform the has_privs_of_role
1445 * test.
1446 */
1447 remaining = mask & ~result;
1448 for (i = 0; i < num; i++)
1449 {
1450 AclItem *aidata = &aidat[i];
1451
1452 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1453 aidata->ai_grantee == roleid)
1454 continue; /* already checked it */
1455
1456 if ((aidata->ai_privs & remaining) &&
1457 has_privs_of_role(roleid, aidata->ai_grantee))
1458 {
1459 result |= aidata->ai_privs & mask;
1460 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1461 return result;
1462 remaining = mask & ~result;
1463 }
1464 }
1465
1466 return result;
1467}
1468
1469
1470/*
1471 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1472 *
1473 * This is exactly like aclmask() except that we consider only privileges
1474 * held *directly* by roleid, not those inherited via role membership.
1475 */
1476static AclMode
1477aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1478 AclMode mask, AclMaskHow how)
1479{
1480 AclMode result;
1481 AclItem *aidat;
1482 int i,
1483 num;
1484
1485 /*
1486 * Null ACL should not happen, since caller should have inserted
1487 * appropriate default
1488 */
1489 if (acl == NULL)
1490 elog(ERROR, "null ACL");
1491
1492 check_acl(acl);
1493
1494 /* Quick exit for mask == 0 */
1495 if (mask == 0)
1496 return 0;
1497
1498 result = 0;
1499
1500 /* Owner always implicitly has all grant options */
1501 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1502 roleid == ownerId)
1503 {
1504 result = mask & ACLITEM_ALL_GOPTION_BITS;
1505 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1506 return result;
1507 }
1508
1509 num = ACL_NUM(acl);
1510 aidat = ACL_DAT(acl);
1511
1512 /*
1513 * Check privileges granted directly to roleid (and not to public)
1514 */
1515 for (i = 0; i < num; i++)
1516 {
1517 AclItem *aidata = &aidat[i];
1518
1519 if (aidata->ai_grantee == roleid)
1520 {
1521 result |= aidata->ai_privs & mask;
1522 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1523 return result;
1524 }
1525 }
1526
1527 return result;
1528}
1529
1530
1531/*
1532 * aclmembers
1533 * Find out all the roleids mentioned in an Acl.
1534 * Note that we do not distinguish grantors from grantees.
1535 *
1536 * *roleids is set to point to a palloc'd array containing distinct OIDs
1537 * in sorted order. The length of the array is the function result.
1538 */
1539int
1540aclmembers(const Acl *acl, Oid **roleids)
1541{
1542 Oid *list;
1543 const AclItem *acldat;
1544 int i,
1545 j;
1546
1547 if (acl == NULL || ACL_NUM(acl) == 0)
1548 {
1549 *roleids = NULL;
1550 return 0;
1551 }
1552
1553 check_acl(acl);
1554
1555 /* Allocate the worst-case space requirement */
1556 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1557 acldat = ACL_DAT(acl);
1558
1559 /*
1560 * Walk the ACL collecting mentioned RoleIds.
1561 */
1562 j = 0;
1563 for (i = 0; i < ACL_NUM(acl); i++)
1564 {
1565 const AclItem *ai = &acldat[i];
1566
1567 if (ai->ai_grantee != ACL_ID_PUBLIC)
1568 list[j++] = ai->ai_grantee;
1569 /* grantor is currently never PUBLIC, but let's check anyway */
1570 if (ai->ai_grantor != ACL_ID_PUBLIC)
1571 list[j++] = ai->ai_grantor;
1572 }
1573
1574 /* Sort the array */
1575 qsort(list, j, sizeof(Oid), oid_cmp);
1576
1577 /*
1578 * We could repalloc the array down to minimum size, but it's hardly worth
1579 * it since it's only transient memory.
1580 */
1581 *roleids = list;
1582
1583 /* Remove duplicates from the array */
1584 return qunique(list, j, sizeof(Oid), oid_cmp);
1585}
1586
1587
1588/*
1589 * aclinsert (exported function)
1590 */
1591Datum
1593{
1594 ereport(ERROR,
1595 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1596 errmsg("aclinsert is no longer supported")));
1597
1598 PG_RETURN_NULL(); /* keep compiler quiet */
1599}
1600
1601Datum
1603{
1604 ereport(ERROR,
1605 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1606 errmsg("aclremove is no longer supported")));
1607
1608 PG_RETURN_NULL(); /* keep compiler quiet */
1609}
1610
1611Datum
1613{
1614 Acl *acl = PG_GETARG_ACL_P(0);
1615 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1616 AclItem *aidat;
1617 int i,
1618 num;
1619
1620 check_acl(acl);
1621 num = ACL_NUM(acl);
1622 aidat = ACL_DAT(acl);
1623 for (i = 0; i < num; ++i)
1624 {
1625 if (aip->ai_grantee == aidat[i].ai_grantee &&
1626 aip->ai_grantor == aidat[i].ai_grantor &&
1627 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1628 PG_RETURN_BOOL(true);
1629 }
1630 PG_RETURN_BOOL(false);
1631}
1632
1633Datum
1635{
1636 Oid grantee = PG_GETARG_OID(0);
1637 Oid grantor = PG_GETARG_OID(1);
1638 text *privtext = PG_GETARG_TEXT_PP(2);
1639 bool goption = PG_GETARG_BOOL(3);
1640 AclItem *result;
1641 AclMode priv;
1642 static const priv_map any_priv_map[] = {
1643 {"SELECT", ACL_SELECT},
1644 {"INSERT", ACL_INSERT},
1645 {"UPDATE", ACL_UPDATE},
1646 {"DELETE", ACL_DELETE},
1647 {"TRUNCATE", ACL_TRUNCATE},
1648 {"REFERENCES", ACL_REFERENCES},
1649 {"TRIGGER", ACL_TRIGGER},
1650 {"EXECUTE", ACL_EXECUTE},
1651 {"USAGE", ACL_USAGE},
1652 {"CREATE", ACL_CREATE},
1653 {"TEMP", ACL_CREATE_TEMP},
1654 {"TEMPORARY", ACL_CREATE_TEMP},
1655 {"CONNECT", ACL_CONNECT},
1656 {"SET", ACL_SET},
1657 {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
1658 {"MAINTAIN", ACL_MAINTAIN},
1659 {NULL, 0}
1660 };
1661
1662 priv = convert_any_priv_string(privtext, any_priv_map);
1663
1664 result = (AclItem *) palloc(sizeof(AclItem));
1665
1666 result->ai_grantee = grantee;
1667 result->ai_grantor = grantor;
1668
1669 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1670 (goption ? priv : ACL_NO_RIGHTS));
1671
1672 PG_RETURN_ACLITEM_P(result);
1673}
1674
1675
1676/*
1677 * convert_any_priv_string: recognize privilege strings for has_foo_privilege
1678 *
1679 * We accept a comma-separated list of case-insensitive privilege names,
1680 * producing a bitmask of the OR'd privilege bits. We are liberal about
1681 * whitespace between items, not so much about whitespace within items.
1682 * The allowed privilege names are given as an array of priv_map structs,
1683 * terminated by one with a NULL name pointer.
1684 */
1685static AclMode
1687 const priv_map *privileges)
1688{
1689 AclMode result = 0;
1690 char *priv_type = text_to_cstring(priv_type_text);
1691 char *chunk;
1692 char *next_chunk;
1693
1694 /* We rely on priv_type being a private, modifiable string */
1695 for (chunk = priv_type; chunk; chunk = next_chunk)
1696 {
1697 int chunk_len;
1698 const priv_map *this_priv;
1699
1700 /* Split string at commas */
1701 next_chunk = strchr(chunk, ',');
1702 if (next_chunk)
1703 *next_chunk++ = '\0';
1704
1705 /* Drop leading/trailing whitespace in this chunk */
1706 while (*chunk && isspace((unsigned char) *chunk))
1707 chunk++;
1708 chunk_len = strlen(chunk);
1709 while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
1710 chunk_len--;
1711 chunk[chunk_len] = '\0';
1712
1713 /* Match to the privileges list */
1714 for (this_priv = privileges; this_priv->name; this_priv++)
1715 {
1716 if (pg_strcasecmp(this_priv->name, chunk) == 0)
1717 {
1718 result |= this_priv->value;
1719 break;
1720 }
1721 }
1722 if (!this_priv->name)
1723 ereport(ERROR,
1724 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1725 errmsg("unrecognized privilege type: \"%s\"", chunk)));
1726 }
1727
1728 pfree(priv_type);
1729 return result;
1730}
1731
1732
1733static const char *
1735{
1736 switch (aclright)
1737 {
1738 case ACL_INSERT:
1739 return "INSERT";
1740 case ACL_SELECT:
1741 return "SELECT";
1742 case ACL_UPDATE:
1743 return "UPDATE";
1744 case ACL_DELETE:
1745 return "DELETE";
1746 case ACL_TRUNCATE:
1747 return "TRUNCATE";
1748 case ACL_REFERENCES:
1749 return "REFERENCES";
1750 case ACL_TRIGGER:
1751 return "TRIGGER";
1752 case ACL_EXECUTE:
1753 return "EXECUTE";
1754 case ACL_USAGE:
1755 return "USAGE";
1756 case ACL_CREATE:
1757 return "CREATE";
1758 case ACL_CREATE_TEMP:
1759 return "TEMPORARY";
1760 case ACL_CONNECT:
1761 return "CONNECT";
1762 case ACL_SET:
1763 return "SET";
1764 case ACL_ALTER_SYSTEM:
1765 return "ALTER SYSTEM";
1766 case ACL_MAINTAIN:
1767 return "MAINTAIN";
1768 default:
1769 elog(ERROR, "unrecognized aclright: %d", aclright);
1770 return NULL;
1771 }
1772}
1773
1774
1775/*----------
1776 * Convert an aclitem[] to a table.
1777 *
1778 * Example:
1779 *
1780 * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
1781 *
1782 * returns the table
1783 *
1784 * {{ OID(joe), 0::OID, 'SELECT', false },
1785 * { OID(joe), OID(foo), 'INSERT', true },
1786 * { OID(joe), OID(foo), 'UPDATE', false }}
1787 *----------
1788 */
1789Datum
1791{
1792 Acl *acl = PG_GETARG_ACL_P(0);
1793 FuncCallContext *funcctx;
1794 int *idx;
1795 AclItem *aidat;
1796
1797 if (SRF_IS_FIRSTCALL())
1798 {
1799 TupleDesc tupdesc;
1800 MemoryContext oldcontext;
1801
1802 check_acl(acl);
1803
1804 funcctx = SRF_FIRSTCALL_INIT();
1805 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1806
1807 /*
1808 * build tupdesc for result tuples (matches out parameters in pg_proc
1809 * entry)
1810 */
1811 tupdesc = CreateTemplateTupleDesc(4);
1812 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
1813 OIDOID, -1, 0);
1814 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
1815 OIDOID, -1, 0);
1816 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
1817 TEXTOID, -1, 0);
1818 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
1819 BOOLOID, -1, 0);
1820
1821 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1822
1823 /* allocate memory for user context */
1824 idx = (int *) palloc(sizeof(int[2]));
1825 idx[0] = 0; /* ACL array item index */
1826 idx[1] = -1; /* privilege type counter */
1827 funcctx->user_fctx = idx;
1828
1829 MemoryContextSwitchTo(oldcontext);
1830 }
1831
1832 funcctx = SRF_PERCALL_SETUP();
1833 idx = (int *) funcctx->user_fctx;
1834 aidat = ACL_DAT(acl);
1835
1836 /* need test here in case acl has no items */
1837 while (idx[0] < ACL_NUM(acl))
1838 {
1839 AclItem *aidata;
1840 AclMode priv_bit;
1841
1842 idx[1]++;
1843 if (idx[1] == N_ACL_RIGHTS)
1844 {
1845 idx[1] = 0;
1846 idx[0]++;
1847 if (idx[0] >= ACL_NUM(acl)) /* done */
1848 break;
1849 }
1850 aidata = &aidat[idx[0]];
1851 priv_bit = UINT64CONST(1) << idx[1];
1852
1853 if (ACLITEM_GET_PRIVS(*aidata) & priv_bit)
1854 {
1855 Datum result;
1856 Datum values[4];
1857 bool nulls[4] = {0};
1858 HeapTuple tuple;
1859
1860 values[0] = ObjectIdGetDatum(aidata->ai_grantor);
1861 values[1] = ObjectIdGetDatum(aidata->ai_grantee);
1863 values[3] = BoolGetDatum((ACLITEM_GET_GOPTIONS(*aidata) & priv_bit) != 0);
1864
1865 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1866 result = HeapTupleGetDatum(tuple);
1867
1868 SRF_RETURN_NEXT(funcctx, result);
1869 }
1870 }
1871
1872 SRF_RETURN_DONE(funcctx);
1873}
1874
1875
1876/*
1877 * has_table_privilege variants
1878 * These are all named "has_table_privilege" at the SQL level.
1879 * They take various combinations of relation name, relation OID,
1880 * user name, user OID, or implicit user = current_user.
1881 *
1882 * The result is a boolean value: true if user has the indicated
1883 * privilege, false if not. The variants that take a relation OID
1884 * return NULL if the OID doesn't exist (rather than failing, as
1885 * they did before Postgres 8.4).
1886 */
1887
1888/*
1889 * has_table_privilege_name_name
1890 * Check user privileges on a table given
1891 * name username, text tablename, and text priv name.
1892 */
1893Datum
1895{
1896 Name rolename = PG_GETARG_NAME(0);
1897 text *tablename = PG_GETARG_TEXT_PP(1);
1898 text *priv_type_text = PG_GETARG_TEXT_PP(2);
1899 Oid roleid;
1900 Oid tableoid;
1901 AclMode mode;
1902 AclResult aclresult;
1903
1904 roleid = get_role_oid_or_public(NameStr(*rolename));
1905 tableoid = convert_table_name(tablename);
1906 mode = convert_table_priv_string(priv_type_text);
1907
1908 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1909
1910 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1911}
1912
1913/*
1914 * has_table_privilege_name
1915 * Check user privileges on a table given
1916 * text tablename and text priv name.
1917 * current_user is assumed
1918 */
1919Datum
1921{
1922 text *tablename = PG_GETARG_TEXT_PP(0);
1923 text *priv_type_text = PG_GETARG_TEXT_PP(1);
1924 Oid roleid;
1925 Oid tableoid;
1926 AclMode mode;
1927 AclResult aclresult;
1928
1929 roleid = GetUserId();
1930 tableoid = convert_table_name(tablename);
1931 mode = convert_table_priv_string(priv_type_text);
1932
1933 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1934
1935 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1936}
1937
1938/*
1939 * has_table_privilege_name_id
1940 * Check user privileges on a table given
1941 * name usename, table oid, and text priv name.
1942 */
1943Datum
1945{
1947 Oid tableoid = PG_GETARG_OID(1);
1948 text *priv_type_text = PG_GETARG_TEXT_PP(2);
1949 Oid roleid;
1950 AclMode mode;
1951 AclResult aclresult;
1952 bool is_missing = false;
1953
1955 mode = convert_table_priv_string(priv_type_text);
1956
1957 aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
1958
1959 if (is_missing)
1961
1962 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1963}
1964
1965/*
1966 * has_table_privilege_id
1967 * Check user privileges on a table given
1968 * table oid, and text priv name.
1969 * current_user is assumed
1970 */
1971Datum
1973{
1974 Oid tableoid = PG_GETARG_OID(0);
1975 text *priv_type_text = PG_GETARG_TEXT_PP(1);
1976 Oid roleid;
1977 AclMode mode;
1978 AclResult aclresult;
1979 bool is_missing = false;
1980
1981 roleid = GetUserId();
1982 mode = convert_table_priv_string(priv_type_text);
1983
1984 aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
1985
1986 if (is_missing)
1988
1989 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1990}
1991
1992/*
1993 * has_table_privilege_id_name
1994 * Check user privileges on a table given
1995 * roleid, text tablename, and text priv name.
1996 */
1997Datum
1999{
2000 Oid roleid = PG_GETARG_OID(0);
2001 text *tablename = PG_GETARG_TEXT_PP(1);
2002 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2003 Oid tableoid;
2004 AclMode mode;
2005 AclResult aclresult;
2006
2007 tableoid = convert_table_name(tablename);
2008 mode = convert_table_priv_string(priv_type_text);
2009
2010 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2011
2012 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2013}
2014
2015/*
2016 * has_table_privilege_id_id
2017 * Check user privileges on a table given
2018 * roleid, table oid, and text priv name.
2019 */
2020Datum
2022{
2023 Oid roleid = PG_GETARG_OID(0);
2024 Oid tableoid = PG_GETARG_OID(1);
2025 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2026 AclMode mode;
2027 AclResult aclresult;
2028 bool is_missing = false;
2029
2030 mode = convert_table_priv_string(priv_type_text);
2031
2032 aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2033
2034 if (is_missing)
2036
2037 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2038}
2039
2040/*
2041 * Support routines for has_table_privilege family.
2042 */
2043
2044/*
2045 * Given a table name expressed as a string, look it up and return Oid
2046 */
2047static Oid
2049{
2050 RangeVar *relrv;
2051
2053
2054 /* We might not even have permissions on this relation; don't lock it. */
2055 return RangeVarGetRelid(relrv, NoLock, false);
2056}
2057
2058/*
2059 * convert_table_priv_string
2060 * Convert text string to AclMode value.
2061 */
2062static AclMode
2064{
2065 static const priv_map table_priv_map[] = {
2066 {"SELECT", ACL_SELECT},
2067 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2068 {"INSERT", ACL_INSERT},
2069 {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2070 {"UPDATE", ACL_UPDATE},
2071 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2072 {"DELETE", ACL_DELETE},
2073 {"DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE)},
2074 {"TRUNCATE", ACL_TRUNCATE},
2075 {"TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE)},
2076 {"REFERENCES", ACL_REFERENCES},
2077 {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2078 {"TRIGGER", ACL_TRIGGER},
2079 {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
2080 {"MAINTAIN", ACL_MAINTAIN},
2081 {"MAINTAIN WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_MAINTAIN)},
2082 {NULL, 0}
2083 };
2084
2085 return convert_any_priv_string(priv_type_text, table_priv_map);
2086}
2087
2088/*
2089 * has_sequence_privilege variants
2090 * These are all named "has_sequence_privilege" at the SQL level.
2091 * They take various combinations of relation name, relation OID,
2092 * user name, user OID, or implicit user = current_user.
2093 *
2094 * The result is a boolean value: true if user has the indicated
2095 * privilege, false if not. The variants that take a relation OID
2096 * return NULL if the OID doesn't exist.
2097 */
2098
2099/*
2100 * has_sequence_privilege_name_name
2101 * Check user privileges on a sequence given
2102 * name username, text sequencename, and text priv name.
2103 */
2104Datum
2106{
2107 Name rolename = PG_GETARG_NAME(0);
2108 text *sequencename = PG_GETARG_TEXT_PP(1);
2109 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2110 Oid roleid;
2111 Oid sequenceoid;
2112 AclMode mode;
2113 AclResult aclresult;
2114
2115 roleid = get_role_oid_or_public(NameStr(*rolename));
2116 mode = convert_sequence_priv_string(priv_type_text);
2117 sequenceoid = convert_table_name(sequencename);
2118 if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2119 ereport(ERROR,
2120 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2121 errmsg("\"%s\" is not a sequence",
2122 text_to_cstring(sequencename))));
2123
2124 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2125
2126 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2127}
2128
2129/*
2130 * has_sequence_privilege_name
2131 * Check user privileges on a sequence given
2132 * text sequencename and text priv name.
2133 * current_user is assumed
2134 */
2135Datum
2137{
2138 text *sequencename = PG_GETARG_TEXT_PP(0);
2139 text *priv_type_text = PG_GETARG_TEXT_PP(1);
2140 Oid roleid;
2141 Oid sequenceoid;
2142 AclMode mode;
2143 AclResult aclresult;
2144
2145 roleid = GetUserId();
2146 mode = convert_sequence_priv_string(priv_type_text);
2147 sequenceoid = convert_table_name(sequencename);
2148 if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2149 ereport(ERROR,
2150 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2151 errmsg("\"%s\" is not a sequence",
2152 text_to_cstring(sequencename))));
2153
2154 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2155
2156 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2157}
2158
2159/*
2160 * has_sequence_privilege_name_id
2161 * Check user privileges on a sequence given
2162 * name usename, sequence oid, and text priv name.
2163 */
2164Datum
2166{
2168 Oid sequenceoid = PG_GETARG_OID(1);
2169 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2170 Oid roleid;
2171 AclMode mode;
2172 AclResult aclresult;
2173 char relkind;
2174 bool is_missing = false;
2175
2177 mode = convert_sequence_priv_string(priv_type_text);
2178 relkind = get_rel_relkind(sequenceoid);
2179 if (relkind == '\0')
2181 else if (relkind != RELKIND_SEQUENCE)
2182 ereport(ERROR,
2183 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2184 errmsg("\"%s\" is not a sequence",
2185 get_rel_name(sequenceoid))));
2186
2187 aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2188
2189 if (is_missing)
2191
2192 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2193}
2194
2195/*
2196 * has_sequence_privilege_id
2197 * Check user privileges on a sequence given
2198 * sequence oid, and text priv name.
2199 * current_user is assumed
2200 */
2201Datum
2203{
2204 Oid sequenceoid = PG_GETARG_OID(0);
2205 text *priv_type_text = PG_GETARG_TEXT_PP(1);
2206 Oid roleid;
2207 AclMode mode;
2208 AclResult aclresult;
2209 char relkind;
2210 bool is_missing = false;
2211
2212 roleid = GetUserId();
2213 mode = convert_sequence_priv_string(priv_type_text);
2214 relkind = get_rel_relkind(sequenceoid);
2215 if (relkind == '\0')
2217 else if (relkind != RELKIND_SEQUENCE)
2218 ereport(ERROR,
2219 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2220 errmsg("\"%s\" is not a sequence",
2221 get_rel_name(sequenceoid))));
2222
2223 aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2224
2225 if (is_missing)
2227
2228 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2229}
2230
2231/*
2232 * has_sequence_privilege_id_name
2233 * Check user privileges on a sequence given
2234 * roleid, text sequencename, and text priv name.
2235 */
2236Datum
2238{
2239 Oid roleid = PG_GETARG_OID(0);
2240 text *sequencename = PG_GETARG_TEXT_PP(1);
2241 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2242 Oid sequenceoid;
2243 AclMode mode;
2244 AclResult aclresult;
2245
2246 mode = convert_sequence_priv_string(priv_type_text);
2247 sequenceoid = convert_table_name(sequencename);
2248 if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2249 ereport(ERROR,
2250 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2251 errmsg("\"%s\" is not a sequence",
2252 text_to_cstring(sequencename))));
2253
2254 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2255
2256 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2257}
2258
2259/*
2260 * has_sequence_privilege_id_id
2261 * Check user privileges on a sequence given
2262 * roleid, sequence oid, and text priv name.
2263 */
2264Datum
2266{
2267 Oid roleid = PG_GETARG_OID(0);
2268 Oid sequenceoid = PG_GETARG_OID(1);
2269 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2270 AclMode mode;
2271 AclResult aclresult;
2272 char relkind;
2273 bool is_missing = false;
2274
2275 mode = convert_sequence_priv_string(priv_type_text);
2276 relkind = get_rel_relkind(sequenceoid);
2277 if (relkind == '\0')
2279 else if (relkind != RELKIND_SEQUENCE)
2280 ereport(ERROR,
2281 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2282 errmsg("\"%s\" is not a sequence",
2283 get_rel_name(sequenceoid))));
2284
2285 aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2286
2287 if (is_missing)
2289
2290 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2291}
2292
2293/*
2294 * convert_sequence_priv_string
2295 * Convert text string to AclMode value.
2296 */
2297static AclMode
2299{
2300 static const priv_map sequence_priv_map[] = {
2301 {"USAGE", ACL_USAGE},
2302 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
2303 {"SELECT", ACL_SELECT},
2304 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2305 {"UPDATE", ACL_UPDATE},
2306 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2307 {NULL, 0}
2308 };
2309
2310 return convert_any_priv_string(priv_type_text, sequence_priv_map);
2311}
2312
2313
2314/*
2315 * has_any_column_privilege variants
2316 * These are all named "has_any_column_privilege" at the SQL level.
2317 * They take various combinations of relation name, relation OID,
2318 * user name, user OID, or implicit user = current_user.
2319 *
2320 * The result is a boolean value: true if user has the indicated
2321 * privilege for any column of the table, false if not. The variants
2322 * that take a relation OID return NULL if the OID doesn't exist.
2323 */
2324
2325/*
2326 * has_any_column_privilege_name_name
2327 * Check user privileges on any column of a table given
2328 * name username, text tablename, and text priv name.
2329 */
2330Datum
2332{
2333 Name rolename = PG_GETARG_NAME(0);
2334 text *tablename = PG_GETARG_TEXT_PP(1);
2335 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2336 Oid roleid;
2337 Oid tableoid;
2338 AclMode mode;
2339 AclResult aclresult;
2340
2341 roleid = get_role_oid_or_public(NameStr(*rolename));
2342 tableoid = convert_table_name(tablename);
2343 mode = convert_column_priv_string(priv_type_text);
2344
2345 /* First check at table level, then examine each column if needed */
2346 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2347 if (aclresult != ACLCHECK_OK)
2348 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2349 ACLMASK_ANY);
2350
2351 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2352}
2353
2354/*
2355 * has_any_column_privilege_name
2356 * Check user privileges on any column of a table given
2357 * text tablename and text priv name.
2358 * current_user is assumed
2359 */
2360Datum
2362{
2363 text *tablename = PG_GETARG_TEXT_PP(0);
2364 text *priv_type_text = PG_GETARG_TEXT_PP(1);
2365 Oid roleid;
2366 Oid tableoid;
2367 AclMode mode;
2368 AclResult aclresult;
2369
2370 roleid = GetUserId();
2371 tableoid = convert_table_name(tablename);
2372 mode = convert_column_priv_string(priv_type_text);
2373
2374 /* First check at table level, then examine each column if needed */
2375 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2376 if (aclresult != ACLCHECK_OK)
2377 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2378 ACLMASK_ANY);
2379
2380 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2381}
2382
2383/*
2384 * has_any_column_privilege_name_id
2385 * Check user privileges on any column of a table given
2386 * name usename, table oid, and text priv name.
2387 */
2388Datum
2390{
2392 Oid tableoid = PG_GETARG_OID(1);
2393 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2394 Oid roleid;
2395 AclMode mode;
2396 AclResult aclresult;
2397 bool is_missing = false;
2398
2400 mode = convert_column_priv_string(priv_type_text);
2401
2402 /* First check at table level, then examine each column if needed */
2403 aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2404 if (aclresult != ACLCHECK_OK)
2405 {
2406 if (is_missing)
2408 aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2409 ACLMASK_ANY, &is_missing);
2410 if (is_missing)
2412 }
2413
2414 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2415}
2416
2417/*
2418 * has_any_column_privilege_id
2419 * Check user privileges on any column of a table given
2420 * table oid, and text priv name.
2421 * current_user is assumed
2422 */
2423Datum
2425{
2426 Oid tableoid = PG_GETARG_OID(0);
2427 text *priv_type_text = PG_GETARG_TEXT_PP(1);
2428 Oid roleid;
2429 AclMode mode;
2430 AclResult aclresult;
2431 bool is_missing = false;
2432
2433 roleid = GetUserId();
2434 mode = convert_column_priv_string(priv_type_text);
2435
2436 /* First check at table level, then examine each column if needed */
2437 aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2438 if (aclresult != ACLCHECK_OK)
2439 {
2440 if (is_missing)
2442 aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2443 ACLMASK_ANY, &is_missing);
2444 if (is_missing)
2446 }
2447
2448 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2449}
2450
2451/*
2452 * has_any_column_privilege_id_name
2453 * Check user privileges on any column of a table given
2454 * roleid, text tablename, and text priv name.
2455 */
2456Datum
2458{
2459 Oid roleid = PG_GETARG_OID(0);
2460 text *tablename = PG_GETARG_TEXT_PP(1);
2461 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2462 Oid tableoid;
2463 AclMode mode;
2464 AclResult aclresult;
2465
2466 tableoid = convert_table_name(tablename);
2467 mode = convert_column_priv_string(priv_type_text);
2468
2469 /* First check at table level, then examine each column if needed */
2470 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2471 if (aclresult != ACLCHECK_OK)
2472 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2473 ACLMASK_ANY);
2474
2475 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2476}
2477
2478/*
2479 * has_any_column_privilege_id_id
2480 * Check user privileges on any column of a table given
2481 * roleid, table oid, and text priv name.
2482 */
2483Datum
2485{
2486 Oid roleid = PG_GETARG_OID(0);
2487 Oid tableoid = PG_GETARG_OID(1);
2488 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2489 AclMode mode;
2490 AclResult aclresult;
2491 bool is_missing = false;
2492
2493 mode = convert_column_priv_string(priv_type_text);
2494
2495 /* First check at table level, then examine each column if needed */
2496 aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2497 if (aclresult != ACLCHECK_OK)
2498 {
2499 if (is_missing)
2501 aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2502 ACLMASK_ANY, &is_missing);
2503 if (is_missing)
2505 }
2506
2507 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2508}
2509
2510
2511/*
2512 * has_column_privilege variants
2513 * These are all named "has_column_privilege" at the SQL level.
2514 * They take various combinations of relation name, relation OID,
2515 * column name, column attnum, user name, user OID, or
2516 * implicit user = current_user.
2517 *
2518 * The result is a boolean value: true if user has the indicated
2519 * privilege, false if not. The variants that take a relation OID
2520 * return NULL (rather than throwing an error) if that relation OID
2521 * doesn't exist. Likewise, the variants that take an integer attnum
2522 * return NULL (rather than throwing an error) if there is no such
2523 * pg_attribute entry. All variants return NULL if an attisdropped
2524 * column is selected. These rules are meant to avoid unnecessary
2525 * failures in queries that scan pg_attribute.
2526 */
2527
2528/*
2529 * column_privilege_check: check column privileges, but don't throw an error
2530 * for dropped column or table
2531 *
2532 * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
2533 */
2534static int
2536 Oid roleid, AclMode mode)
2537{
2538 AclResult aclresult;
2539 bool is_missing = false;
2540
2541 /*
2542 * If convert_column_name failed, we can just return -1 immediately.
2543 */
2545 return -1;
2546
2547 /*
2548 * Check for column-level privileges first. This serves in part as a check
2549 * on whether the column even exists, so we need to do it before checking
2550 * table-level privilege.
2551 */
2552 aclresult = pg_attribute_aclcheck_ext(tableoid, attnum, roleid,
2553 mode, &is_missing);
2554 if (aclresult == ACLCHECK_OK)
2555 return 1;
2556 else if (is_missing)
2557 return -1;
2558
2559 /* Next check if we have the privilege at the table level */
2560 aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2561 if (aclresult == ACLCHECK_OK)
2562 return 1;
2563 else if (is_missing)
2564 return -1;
2565 else
2566 return 0;
2567}
2568
2569/*
2570 * has_column_privilege_name_name_name
2571 * Check user privileges on a column given
2572 * name username, text tablename, text colname, and text priv name.
2573 */
2574Datum
2576{
2577 Name rolename = PG_GETARG_NAME(0);
2578 text *tablename = PG_GETARG_TEXT_PP(1);
2579 text *column = PG_GETARG_TEXT_PP(2);
2580 text *priv_type_text = PG_GETARG_TEXT_PP(3);
2581 Oid roleid;
2582 Oid tableoid;
2583 AttrNumber colattnum;
2584 AclMode mode;
2585 int privresult;
2586
2587 roleid = get_role_oid_or_public(NameStr(*rolename));
2588 tableoid = convert_table_name(tablename);
2589 colattnum = convert_column_name(tableoid, column);
2590 mode = convert_column_priv_string(priv_type_text);
2591
2592 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2593 if (privresult < 0)
2595 PG_RETURN_BOOL(privresult);
2596}
2597
2598/*
2599 * has_column_privilege_name_name_attnum
2600 * Check user privileges on a column given
2601 * name username, text tablename, int attnum, and text priv name.
2602 */
2603Datum
2605{
2606 Name rolename = PG_GETARG_NAME(0);
2607 text *tablename = PG_GETARG_TEXT_PP(1);
2608 AttrNumber colattnum = PG_GETARG_INT16(2);
2609 text *priv_type_text = PG_GETARG_TEXT_PP(3);
2610 Oid roleid;
2611 Oid tableoid;
2612 AclMode mode;
2613 int privresult;
2614
2615 roleid = get_role_oid_or_public(NameStr(*rolename));
2616 tableoid = convert_table_name(tablename);
2617 mode = convert_column_priv_string(priv_type_text);
2618
2619 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2620 if (privresult < 0)
2622 PG_RETURN_BOOL(privresult);
2623}
2624
2625/*
2626 * has_column_privilege_name_id_name
2627 * Check user privileges on a column given
2628 * name username, table oid, text colname, and text priv name.
2629 */
2630Datum
2632{
2634 Oid tableoid = PG_GETARG_OID(1);
2635 text *column = PG_GETARG_TEXT_PP(2);
2636 text *priv_type_text = PG_GETARG_TEXT_PP(3);
2637 Oid roleid;
2638 AttrNumber colattnum;
2639 AclMode mode;
2640 int privresult;
2641
2643 colattnum = convert_column_name(tableoid, column);
2644 mode = convert_column_priv_string(priv_type_text);
2645
2646 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2647 if (privresult < 0)
2649 PG_RETURN_BOOL(privresult);
2650}
2651
2652/*
2653 * has_column_privilege_name_id_attnum
2654 * Check user privileges on a column given
2655 * name username, table oid, int attnum, and text priv name.
2656 */
2657Datum
2659{
2661 Oid tableoid = PG_GETARG_OID(1);
2662 AttrNumber colattnum = PG_GETARG_INT16(2);
2663 text *priv_type_text = PG_GETARG_TEXT_PP(3);
2664 Oid roleid;
2665 AclMode mode;
2666 int privresult;
2667
2669 mode = convert_column_priv_string(priv_type_text);
2670
2671 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2672 if (privresult < 0)
2674 PG_RETURN_BOOL(privresult);
2675}
2676
2677/*
2678 * has_column_privilege_id_name_name
2679 * Check user privileges on a column given
2680 * oid roleid, text tablename, text colname, and text priv name.
2681 */
2682Datum
2684{
2685 Oid roleid = PG_GETARG_OID(0);
2686 text *tablename = PG_GETARG_TEXT_PP(1);
2687 text *column = PG_GETARG_TEXT_PP(2);
2688 text *priv_type_text = PG_GETARG_TEXT_PP(3);
2689 Oid tableoid;
2690 AttrNumber colattnum;
2691 AclMode mode;
2692 int privresult;
2693
2694 tableoid = convert_table_name(tablename);
2695 colattnum = convert_column_name(tableoid, column);
2696 mode = convert_column_priv_string(priv_type_text);
2697
2698 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2699 if (privresult < 0)
2701 PG_RETURN_BOOL(privresult);
2702}
2703
2704/*
2705 * has_column_privilege_id_name_attnum
2706 * Check user privileges on a column given
2707 * oid roleid, text tablename, int attnum, and text priv name.
2708 */
2709Datum
2711{
2712 Oid roleid = PG_GETARG_OID(0);
2713 text *tablename = PG_GETARG_TEXT_PP(1);
2714 AttrNumber colattnum = PG_GETARG_INT16(2);
2715 text *priv_type_text = PG_GETARG_TEXT_PP(3);
2716 Oid tableoid;
2717 AclMode mode;
2718 int privresult;
2719
2720 tableoid = convert_table_name(tablename);
2721 mode = convert_column_priv_string(priv_type_text);
2722
2723 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2724 if (privresult < 0)
2726 PG_RETURN_BOOL(privresult);
2727}
2728
2729/*
2730 * has_column_privilege_id_id_name
2731 * Check user privileges on a column given
2732 * oid roleid, table oid, text colname, and text priv name.
2733 */
2734Datum
2736{
2737 Oid roleid = PG_GETARG_OID(0);
2738 Oid tableoid = PG_GETARG_OID(1);
2739 text *column = PG_GETARG_TEXT_PP(2);
2740 text *priv_type_text = PG_GETARG_TEXT_PP(3);
2741 AttrNumber colattnum;
2742 AclMode mode;
2743 int privresult;
2744
2745 colattnum = convert_column_name(tableoid, column);
2746 mode = convert_column_priv_string(priv_type_text);
2747
2748 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2749 if (privresult < 0)
2751 PG_RETURN_BOOL(privresult);
2752}
2753
2754/*
2755 * has_column_privilege_id_id_attnum
2756 * Check user privileges on a column given
2757 * oid roleid, table oid, int attnum, and text priv name.
2758 */
2759Datum
2761{
2762 Oid roleid = PG_GETARG_OID(0);
2763 Oid tableoid = PG_GETARG_OID(1);
2764 AttrNumber colattnum = PG_GETARG_INT16(2);
2765 text *priv_type_text = PG_GETARG_TEXT_PP(3);
2766 AclMode mode;
2767 int privresult;
2768
2769 mode = convert_column_priv_string(priv_type_text);
2770
2771 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2772 if (privresult < 0)
2774 PG_RETURN_BOOL(privresult);
2775}
2776
2777/*
2778 * has_column_privilege_name_name
2779 * Check user privileges on a column given
2780 * text tablename, text colname, and text priv name.
2781 * current_user is assumed
2782 */
2783Datum
2785{
2786 text *tablename = PG_GETARG_TEXT_PP(0);
2787 text *column = PG_GETARG_TEXT_PP(1);
2788 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2789 Oid roleid;
2790 Oid tableoid;
2791 AttrNumber colattnum;
2792 AclMode mode;
2793 int privresult;
2794
2795 roleid = GetUserId();
2796 tableoid = convert_table_name(tablename);
2797 colattnum = convert_column_name(tableoid, column);
2798 mode = convert_column_priv_string(priv_type_text);
2799
2800 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2801 if (privresult < 0)
2803 PG_RETURN_BOOL(privresult);
2804}
2805
2806/*
2807 * has_column_privilege_name_attnum
2808 * Check user privileges on a column given
2809 * text tablename, int attnum, and text priv name.
2810 * current_user is assumed
2811 */
2812Datum
2814{
2815 text *tablename = PG_GETARG_TEXT_PP(0);
2816 AttrNumber colattnum = PG_GETARG_INT16(1);
2817 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2818 Oid roleid;
2819 Oid tableoid;
2820 AclMode mode;
2821 int privresult;
2822
2823 roleid = GetUserId();
2824 tableoid = convert_table_name(tablename);
2825 mode = convert_column_priv_string(priv_type_text);
2826
2827 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2828 if (privresult < 0)
2830 PG_RETURN_BOOL(privresult);
2831}
2832
2833/*
2834 * has_column_privilege_id_name
2835 * Check user privileges on a column given
2836 * table oid, text colname, and text priv name.
2837 * current_user is assumed
2838 */
2839Datum
2841{
2842 Oid tableoid = PG_GETARG_OID(0);
2843 text *column = PG_GETARG_TEXT_PP(1);
2844 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2845 Oid roleid;
2846 AttrNumber colattnum;
2847 AclMode mode;
2848 int privresult;
2849
2850 roleid = GetUserId();
2851 colattnum = convert_column_name(tableoid, column);
2852 mode = convert_column_priv_string(priv_type_text);
2853
2854 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2855 if (privresult < 0)
2857 PG_RETURN_BOOL(privresult);
2858}
2859
2860/*
2861 * has_column_privilege_id_attnum
2862 * Check user privileges on a column given
2863 * table oid, int attnum, and text priv name.
2864 * current_user is assumed
2865 */
2866Datum
2868{
2869 Oid tableoid = PG_GETARG_OID(0);
2870 AttrNumber colattnum = PG_GETARG_INT16(1);
2871 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2872 Oid roleid;
2873 AclMode mode;
2874 int privresult;
2875
2876 roleid = GetUserId();
2877 mode = convert_column_priv_string(priv_type_text);
2878
2879 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2880 if (privresult < 0)
2882 PG_RETURN_BOOL(privresult);
2883}
2884
2885/*
2886 * Support routines for has_column_privilege family.
2887 */
2888
2889/*
2890 * Given a table OID and a column name expressed as a string, look it up
2891 * and return the column number. Returns InvalidAttrNumber in cases
2892 * where caller should return NULL instead of failing.
2893 */
2894static AttrNumber
2895convert_column_name(Oid tableoid, text *column)
2896{
2897 char *colname;
2898 HeapTuple attTuple;
2900
2901 colname = text_to_cstring(column);
2902
2903 /*
2904 * We don't use get_attnum() here because it will report that dropped
2905 * columns don't exist. We need to treat dropped columns differently from
2906 * nonexistent columns.
2907 */
2908 attTuple = SearchSysCache2(ATTNAME,
2909 ObjectIdGetDatum(tableoid),
2910 CStringGetDatum(colname));
2911 if (HeapTupleIsValid(attTuple))
2912 {
2913 Form_pg_attribute attributeForm;
2914
2915 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
2916 /* We want to return NULL for dropped columns */
2917 if (attributeForm->attisdropped)
2919 else
2920 attnum = attributeForm->attnum;
2921 ReleaseSysCache(attTuple);
2922 }
2923 else
2924 {
2925 char *tablename = get_rel_name(tableoid);
2926
2927 /*
2928 * If the table OID is bogus, or it's just been dropped, we'll get
2929 * NULL back. In such cases we want has_column_privilege to return
2930 * NULL too, so just return InvalidAttrNumber.
2931 */
2932 if (tablename != NULL)
2933 {
2934 /* tableoid exists, colname does not, so throw error */
2935 ereport(ERROR,
2936 (errcode(ERRCODE_UNDEFINED_COLUMN),
2937 errmsg("column \"%s\" of relation \"%s\" does not exist",
2938 colname, tablename)));
2939 }
2940 /* tableoid doesn't exist, so act like attisdropped case */
2942 }
2943
2944 pfree(colname);
2945 return attnum;
2946}
2947
2948/*
2949 * convert_column_priv_string
2950 * Convert text string to AclMode value.
2951 */
2952static AclMode
2954{
2955 static const priv_map column_priv_map[] = {
2956 {"SELECT", ACL_SELECT},
2957 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2958 {"INSERT", ACL_INSERT},
2959 {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2960 {"UPDATE", ACL_UPDATE},
2961 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2962 {"REFERENCES", ACL_REFERENCES},
2963 {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2964 {NULL, 0}
2965 };
2966
2967 return convert_any_priv_string(priv_type_text, column_priv_map);
2968}
2969
2970
2971/*
2972 * has_database_privilege variants
2973 * These are all named "has_database_privilege" at the SQL level.
2974 * They take various combinations of database name, database OID,
2975 * user name, user OID, or implicit user = current_user.
2976 *
2977 * The result is a boolean value: true if user has the indicated
2978 * privilege, false if not, or NULL if object doesn't exist.
2979 */
2980
2981/*
2982 * has_database_privilege_name_name
2983 * Check user privileges on a database given
2984 * name username, text databasename, and text priv name.
2985 */
2986Datum
2988{
2990 text *databasename = PG_GETARG_TEXT_PP(1);
2991 text *priv_type_text = PG_GETARG_TEXT_PP(2);
2992 Oid roleid;
2993 Oid databaseoid;
2994 AclMode mode;
2995 AclResult aclresult;
2996
2998 databaseoid = convert_database_name(databasename);
2999 mode = convert_database_priv_string(priv_type_text);
3000
3001 aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3002
3003 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3004}
3005
3006/*
3007 * has_database_privilege_name
3008 * Check user privileges on a database given
3009 * text databasename and text priv name.
3010 * current_user is assumed
3011 */
3012Datum
3014{
3015 text *databasename = PG_GETARG_TEXT_PP(0);
3016 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3017 Oid roleid;
3018 Oid databaseoid;
3019 AclMode mode;
3020 AclResult aclresult;
3021
3022 roleid = GetUserId();
3023 databaseoid = convert_database_name(databasename);
3024 mode = convert_database_priv_string(priv_type_text);
3025
3026 aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3027
3028 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3029}
3030
3031/*
3032 * has_database_privilege_name_id
3033 * Check user privileges on a database given
3034 * name usename, database oid, and text priv name.
3035 */
3036Datum
3038{
3040 Oid databaseoid = PG_GETARG_OID(1);
3041 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3042 Oid roleid;
3043 AclMode mode;
3044 AclResult aclresult;
3045 bool is_missing = false;
3046
3048 mode = convert_database_priv_string(priv_type_text);
3049
3050 aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3051 roleid, mode,
3052 &is_missing);
3053
3054 if (is_missing)
3056
3057 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3058}
3059
3060/*
3061 * has_database_privilege_id
3062 * Check user privileges on a database given
3063 * database oid, and text priv name.
3064 * current_user is assumed
3065 */
3066Datum
3068{
3069 Oid databaseoid = PG_GETARG_OID(0);
3070 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3071 Oid roleid;
3072 AclMode mode;
3073 AclResult aclresult;
3074 bool is_missing = false;
3075
3076 roleid = GetUserId();
3077 mode = convert_database_priv_string(priv_type_text);
3078
3079 aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3080 roleid, mode,
3081 &is_missing);
3082
3083 if (is_missing)
3085
3086 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3087}
3088
3089/*
3090 * has_database_privilege_id_name
3091 * Check user privileges on a database given
3092 * roleid, text databasename, and text priv name.
3093 */
3094Datum
3096{
3097 Oid roleid = PG_GETARG_OID(0);
3098 text *databasename = PG_GETARG_TEXT_PP(1);
3099 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3100 Oid databaseoid;
3101 AclMode mode;
3102 AclResult aclresult;
3103
3104 databaseoid = convert_database_name(databasename);
3105 mode = convert_database_priv_string(priv_type_text);
3106
3107 aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3108
3109 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3110}
3111
3112/*
3113 * has_database_privilege_id_id
3114 * Check user privileges on a database given
3115 * roleid, database oid, and text priv name.
3116 */
3117Datum
3119{
3120 Oid roleid = PG_GETARG_OID(0);
3121 Oid databaseoid = PG_GETARG_OID(1);
3122 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3123 AclMode mode;
3124 AclResult aclresult;
3125 bool is_missing = false;
3126
3127 mode = convert_database_priv_string(priv_type_text);
3128
3129 aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3130 roleid, mode,
3131 &is_missing);
3132
3133 if (is_missing)
3135
3136 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3137}
3138
3139/*
3140 * Support routines for has_database_privilege family.
3141 */
3142
3143/*
3144 * Given a database name expressed as a string, look it up and return Oid
3145 */
3146static Oid
3148{
3149 char *dbname = text_to_cstring(databasename);
3150
3151 return get_database_oid(dbname, false);
3152}
3153
3154/*
3155 * convert_database_priv_string
3156 * Convert text string to AclMode value.
3157 */
3158static AclMode
3160{
3161 static const priv_map database_priv_map[] = {
3162 {"CREATE", ACL_CREATE},
3163 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
3164 {"TEMPORARY", ACL_CREATE_TEMP},
3165 {"TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
3166 {"TEMP", ACL_CREATE_TEMP},
3167 {"TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
3168 {"CONNECT", ACL_CONNECT},
3169 {"CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT)},
3170 {NULL, 0}
3171 };
3172
3173 return convert_any_priv_string(priv_type_text, database_priv_map);
3174}
3175
3176
3177/*
3178 * has_foreign_data_wrapper_privilege variants
3179 * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
3180 * They take various combinations of foreign-data wrapper name,
3181 * fdw OID, user name, user OID, or implicit user = current_user.
3182 *
3183 * The result is a boolean value: true if user has the indicated
3184 * privilege, false if not.
3185 */
3186
3187/*
3188 * has_foreign_data_wrapper_privilege_name_name
3189 * Check user privileges on a foreign-data wrapper given
3190 * name username, text fdwname, and text priv name.
3191 */
3192Datum
3194{
3196 text *fdwname = PG_GETARG_TEXT_PP(1);
3197 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3198 Oid roleid;
3199 Oid fdwid;
3200 AclMode mode;
3201 AclResult aclresult;
3202
3204 fdwid = convert_foreign_data_wrapper_name(fdwname);
3206
3207 aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3208
3209 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3210}
3211
3212/*
3213 * has_foreign_data_wrapper_privilege_name
3214 * Check user privileges on a foreign-data wrapper given
3215 * text fdwname and text priv name.
3216 * current_user is assumed
3217 */
3218Datum
3220{
3221 text *fdwname = PG_GETARG_TEXT_PP(0);
3222 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3223 Oid roleid;
3224 Oid fdwid;
3225 AclMode mode;
3226 AclResult aclresult;
3227
3228 roleid = GetUserId();
3229 fdwid = convert_foreign_data_wrapper_name(fdwname);
3231
3232 aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3233
3234 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3235}
3236
3237/*
3238 * has_foreign_data_wrapper_privilege_name_id
3239 * Check user privileges on a foreign-data wrapper given
3240 * name usename, foreign-data wrapper oid, and text priv name.
3241 */
3242Datum
3244{
3246 Oid fdwid = PG_GETARG_OID(1);
3247 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3248 Oid roleid;
3249 AclMode mode;
3250 AclResult aclresult;
3251 bool is_missing = false;
3252
3255
3256 aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3257 roleid, mode,
3258 &is_missing);
3259
3260 if (is_missing)
3262
3263 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3264}
3265
3266/*
3267 * has_foreign_data_wrapper_privilege_id
3268 * Check user privileges on a foreign-data wrapper given
3269 * foreign-data wrapper oid, and text priv name.
3270 * current_user is assumed
3271 */
3272Datum
3274{
3275 Oid fdwid = PG_GETARG_OID(0);
3276 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3277 Oid roleid;
3278 AclMode mode;
3279 AclResult aclresult;
3280 bool is_missing = false;
3281
3282 roleid = GetUserId();
3284
3285 aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3286 roleid, mode,
3287 &is_missing);
3288
3289 if (is_missing)
3291
3292 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3293}
3294
3295/*
3296 * has_foreign_data_wrapper_privilege_id_name
3297 * Check user privileges on a foreign-data wrapper given
3298 * roleid, text fdwname, and text priv name.
3299 */
3300Datum
3302{
3303 Oid roleid = PG_GETARG_OID(0);
3304 text *fdwname = PG_GETARG_TEXT_PP(1);
3305 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3306 Oid fdwid;
3307 AclMode mode;
3308 AclResult aclresult;
3309
3310 fdwid = convert_foreign_data_wrapper_name(fdwname);
3312
3313 aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3314
3315 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3316}
3317
3318/*
3319 * has_foreign_data_wrapper_privilege_id_id
3320 * Check user privileges on a foreign-data wrapper given
3321 * roleid, fdw oid, and text priv name.
3322 */
3323Datum
3325{
3326 Oid roleid = PG_GETARG_OID(0);
3327 Oid fdwid = PG_GETARG_OID(1);
3328 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3329 AclMode mode;
3330 AclResult aclresult;
3331 bool is_missing = false;
3332
3334
3335 aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3336 roleid, mode,
3337 &is_missing);
3338
3339 if (is_missing)
3341
3342 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3343}
3344
3345/*
3346 * Support routines for has_foreign_data_wrapper_privilege family.
3347 */
3348
3349/*
3350 * Given a FDW name expressed as a string, look it up and return Oid
3351 */
3352static Oid
3354{
3355 char *fdwstr = text_to_cstring(fdwname);
3356
3357 return get_foreign_data_wrapper_oid(fdwstr, false);
3358}
3359
3360/*
3361 * convert_foreign_data_wrapper_priv_string
3362 * Convert text string to AclMode value.
3363 */
3364static AclMode
3366{
3367 static const priv_map foreign_data_wrapper_priv_map[] = {
3368 {"USAGE", ACL_USAGE},
3369 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3370 {NULL, 0}
3371 };
3372
3373 return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
3374}
3375
3376
3377/*
3378 * has_function_privilege variants
3379 * These are all named "has_function_privilege" at the SQL level.
3380 * They take various combinations of function name, function OID,
3381 * user name, user OID, or implicit user = current_user.
3382 *
3383 * The result is a boolean value: true if user has the indicated
3384 * privilege, false if not, or NULL if object doesn't exist.
3385 */
3386
3387/*
3388 * has_function_privilege_name_name
3389 * Check user privileges on a function given
3390 * name username, text functionname, and text priv name.
3391 */
3392Datum
3394{
3396 text *functionname = PG_GETARG_TEXT_PP(1);
3397 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3398 Oid roleid;
3399 Oid functionoid;
3400 AclMode mode;
3401 AclResult aclresult;
3402
3404 functionoid = convert_function_name(functionname);
3405 mode = convert_function_priv_string(priv_type_text);
3406
3407 aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3408
3409 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3410}
3411
3412/*
3413 * has_function_privilege_name
3414 * Check user privileges on a function given
3415 * text functionname and text priv name.
3416 * current_user is assumed
3417 */
3418Datum
3420{
3421 text *functionname = PG_GETARG_TEXT_PP(0);
3422 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3423 Oid roleid;
3424 Oid functionoid;
3425 AclMode mode;
3426 AclResult aclresult;
3427
3428 roleid = GetUserId();
3429 functionoid = convert_function_name(functionname);
3430 mode = convert_function_priv_string(priv_type_text);
3431
3432 aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3433
3434 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3435}
3436
3437/*
3438 * has_function_privilege_name_id
3439 * Check user privileges on a function given
3440 * name usename, function oid, and text priv name.
3441 */
3442Datum
3444{
3446 Oid functionoid = PG_GETARG_OID(1);
3447 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3448 Oid roleid;
3449 AclMode mode;
3450 AclResult aclresult;
3451 bool is_missing = false;
3452
3454 mode = convert_function_priv_string(priv_type_text);
3455
3456 aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3457 roleid, mode,
3458 &is_missing);
3459
3460 if (is_missing)
3462
3463 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3464}
3465
3466/*
3467 * has_function_privilege_id
3468 * Check user privileges on a function given
3469 * function oid, and text priv name.
3470 * current_user is assumed
3471 */
3472Datum
3474{
3475 Oid functionoid = PG_GETARG_OID(0);
3476 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3477 Oid roleid;
3478 AclMode mode;
3479 AclResult aclresult;
3480 bool is_missing = false;
3481
3482 roleid = GetUserId();
3483 mode = convert_function_priv_string(priv_type_text);
3484
3485 aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3486 roleid, mode,
3487 &is_missing);
3488
3489 if (is_missing)
3491
3492 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3493}
3494
3495/*
3496 * has_function_privilege_id_name
3497 * Check user privileges on a function given
3498 * roleid, text functionname, and text priv name.
3499 */
3500Datum
3502{
3503 Oid roleid = PG_GETARG_OID(0);
3504 text *functionname = PG_GETARG_TEXT_PP(1);
3505 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3506 Oid functionoid;
3507 AclMode mode;
3508 AclResult aclresult;
3509
3510 functionoid = convert_function_name(functionname);
3511 mode = convert_function_priv_string(priv_type_text);
3512
3513 aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3514
3515 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3516}
3517
3518/*
3519 * has_function_privilege_id_id
3520 * Check user privileges on a function given
3521 * roleid, function oid, and text priv name.
3522 */
3523Datum
3525{
3526 Oid roleid = PG_GETARG_OID(0);
3527 Oid functionoid = PG_GETARG_OID(1);
3528 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3529 AclMode mode;
3530 AclResult aclresult;
3531 bool is_missing = false;
3532
3533 mode = convert_function_priv_string(priv_type_text);
3534
3535 aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3536 roleid, mode,
3537 &is_missing);
3538
3539 if (is_missing)
3541
3542 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3543}
3544
3545/*
3546 * Support routines for has_function_privilege family.
3547 */
3548
3549/*
3550 * Given a function name expressed as a string, look it up and return Oid
3551 */
3552static Oid
3554{
3555 char *funcname = text_to_cstring(functionname);
3556 Oid oid;
3557
3560
3561 if (!OidIsValid(oid))
3562 ereport(ERROR,
3563 (errcode(ERRCODE_UNDEFINED_FUNCTION),
3564 errmsg("function \"%s\" does not exist", funcname)));
3565
3566 return oid;
3567}
3568
3569/*
3570 * convert_function_priv_string
3571 * Convert text string to AclMode value.
3572 */
3573static AclMode
3575{
3576 static const priv_map function_priv_map[] = {
3577 {"EXECUTE", ACL_EXECUTE},
3578 {"EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE)},
3579 {NULL, 0}
3580 };
3581
3582 return convert_any_priv_string(priv_type_text, function_priv_map);
3583}
3584
3585
3586/*
3587 * has_language_privilege variants
3588 * These are all named "has_language_privilege" at the SQL level.
3589 * They take various combinations of language name, language OID,
3590 * user name, user OID, or implicit user = current_user.
3591 *
3592 * The result is a boolean value: true if user has the indicated
3593 * privilege, false if not, or NULL if object doesn't exist.
3594 */
3595
3596/*
3597 * has_language_privilege_name_name
3598 * Check user privileges on a language given
3599 * name username, text languagename, and text priv name.
3600 */
3601Datum
3603{
3605 text *languagename = PG_GETARG_TEXT_PP(1);
3606 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3607 Oid roleid;
3608 Oid languageoid;
3609 AclMode mode;
3610 AclResult aclresult;
3611
3613 languageoid = convert_language_name(languagename);
3614 mode = convert_language_priv_string(priv_type_text);
3615
3616 aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3617
3618 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3619}
3620
3621/*
3622 * has_language_privilege_name
3623 * Check user privileges on a language given
3624 * text languagename and text priv name.
3625 * current_user is assumed
3626 */
3627Datum
3629{
3630 text *languagename = PG_GETARG_TEXT_PP(0);
3631 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3632 Oid roleid;
3633 Oid languageoid;
3634 AclMode mode;
3635 AclResult aclresult;
3636
3637 roleid = GetUserId();
3638 languageoid = convert_language_name(languagename);
3639 mode = convert_language_priv_string(priv_type_text);
3640
3641 aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3642
3643 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3644}
3645
3646/*
3647 * has_language_privilege_name_id
3648 * Check user privileges on a language given
3649 * name usename, language oid, and text priv name.
3650 */
3651Datum
3653{
3655 Oid languageoid = PG_GETARG_OID(1);
3656 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3657 Oid roleid;
3658 AclMode mode;
3659 AclResult aclresult;
3660 bool is_missing = false;
3661
3663 mode = convert_language_priv_string(priv_type_text);
3664
3665 aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3666 roleid, mode,
3667 &is_missing);
3668
3669 if (is_missing)
3671
3672 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3673}
3674
3675/*
3676 * has_language_privilege_id
3677 * Check user privileges on a language given
3678 * language oid, and text priv name.
3679 * current_user is assumed
3680 */
3681Datum
3683{
3684 Oid languageoid = PG_GETARG_OID(0);
3685 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3686 Oid roleid;
3687 AclMode mode;
3688 AclResult aclresult;
3689 bool is_missing = false;
3690
3691 roleid = GetUserId();
3692 mode = convert_language_priv_string(priv_type_text);
3693
3694 aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3695 roleid, mode,
3696 &is_missing);
3697
3698 if (is_missing)
3700
3701 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3702}
3703
3704/*
3705 * has_language_privilege_id_name
3706 * Check user privileges on a language given
3707 * roleid, text languagename, and text priv name.
3708 */
3709Datum
3711{
3712 Oid roleid = PG_GETARG_OID(0);
3713 text *languagename = PG_GETARG_TEXT_PP(1);
3714 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3715 Oid languageoid;
3716 AclMode mode;
3717 AclResult aclresult;
3718
3719 languageoid = convert_language_name(languagename);
3720 mode = convert_language_priv_string(priv_type_text);
3721
3722 aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3723
3724 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3725}
3726
3727/*
3728 * has_language_privilege_id_id
3729 * Check user privileges on a language given
3730 * roleid, language oid, and text priv name.
3731 */
3732Datum
3734{
3735 Oid roleid = PG_GETARG_OID(0);
3736 Oid languageoid = PG_GETARG_OID(1);
3737 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3738 AclMode mode;
3739 AclResult aclresult;
3740 bool is_missing = false;
3741
3742 mode = convert_language_priv_string(priv_type_text);
3743
3744 aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3745 roleid, mode,
3746 &is_missing);
3747
3748 if (is_missing)
3750
3751 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3752}
3753
3754/*
3755 * Support routines for has_language_privilege family.
3756 */
3757
3758/*
3759 * Given a language name expressed as a string, look it up and return Oid
3760 */
3761static Oid
3763{
3764 char *langname = text_to_cstring(languagename);
3765
3766 return get_language_oid(langname, false);
3767}
3768
3769/*
3770 * convert_language_priv_string
3771 * Convert text string to AclMode value.
3772 */
3773static AclMode
3775{
3776 static const priv_map language_priv_map[] = {
3777 {"USAGE", ACL_USAGE},
3778 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3779 {NULL, 0}
3780 };
3781
3782 return convert_any_priv_string(priv_type_text, language_priv_map);
3783}
3784
3785
3786/*
3787 * has_schema_privilege variants
3788 * These are all named "has_schema_privilege" at the SQL level.
3789 * They take various combinations of schema name, schema OID,
3790 * user name, user OID, or implicit user = current_user.
3791 *
3792 * The result is a boolean value: true if user has the indicated
3793 * privilege, false if not, or NULL if object doesn't exist.
3794 */
3795
3796/*
3797 * has_schema_privilege_name_name
3798 * Check user privileges on a schema given
3799 * name username, text schemaname, and text priv name.
3800 */
3801Datum
3803{
3805 text *schemaname = PG_GETARG_TEXT_PP(1);
3806 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3807 Oid roleid;
3808 Oid schemaoid;
3809 AclMode mode;
3810 AclResult aclresult;
3811
3813 schemaoid = convert_schema_name(schemaname);
3814 mode = convert_schema_priv_string(priv_type_text);
3815
3816 aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3817
3818 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3819}
3820
3821/*
3822 * has_schema_privilege_name
3823 * Check user privileges on a schema given
3824 * text schemaname and text priv name.
3825 * current_user is assumed
3826 */
3827Datum
3829{
3830 text *schemaname = PG_GETARG_TEXT_PP(0);
3831 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3832 Oid roleid;
3833 Oid schemaoid;
3834 AclMode mode;
3835 AclResult aclresult;
3836
3837 roleid = GetUserId();
3838 schemaoid = convert_schema_name(schemaname);
3839 mode = convert_schema_priv_string(priv_type_text);
3840
3841 aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3842
3843 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3844}
3845
3846/*
3847 * has_schema_privilege_name_id
3848 * Check user privileges on a schema given
3849 * name usename, schema oid, and text priv name.
3850 */
3851Datum
3853{
3855 Oid schemaoid = PG_GETARG_OID(1);
3856 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3857 Oid roleid;
3858 AclMode mode;
3859 AclResult aclresult;
3860 bool is_missing = false;
3861
3863 mode = convert_schema_priv_string(priv_type_text);
3864
3865 aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3866 roleid, mode,
3867 &is_missing);
3868
3869 if (is_missing)
3871
3872 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3873}
3874
3875/*
3876 * has_schema_privilege_id
3877 * Check user privileges on a schema given
3878 * schema oid, and text priv name.
3879 * current_user is assumed
3880 */
3881Datum
3883{
3884 Oid schemaoid = PG_GETARG_OID(0);
3885 text *priv_type_text = PG_GETARG_TEXT_PP(1);
3886 Oid roleid;
3887 AclMode mode;
3888 AclResult aclresult;
3889 bool is_missing = false;
3890
3891 roleid = GetUserId();
3892 mode = convert_schema_priv_string(priv_type_text);
3893
3894 aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3895 roleid, mode,
3896 &is_missing);
3897
3898 if (is_missing)
3900
3901 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3902}
3903
3904/*
3905 * has_schema_privilege_id_name
3906 * Check user privileges on a schema given
3907 * roleid, text schemaname, and text priv name.
3908 */
3909Datum
3911{
3912 Oid roleid = PG_GETARG_OID(0);
3913 text *schemaname = PG_GETARG_TEXT_PP(1);
3914 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3915 Oid schemaoid;
3916 AclMode mode;
3917 AclResult aclresult;
3918
3919 schemaoid = convert_schema_name(schemaname);
3920 mode = convert_schema_priv_string(priv_type_text);
3921
3922 aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3923
3924 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3925}
3926
3927/*
3928 * has_schema_privilege_id_id
3929 * Check user privileges on a schema given
3930 * roleid, schema oid, and text priv name.
3931 */
3932Datum
3934{
3935 Oid roleid = PG_GETARG_OID(0);
3936 Oid schemaoid = PG_GETARG_OID(1);
3937 text *priv_type_text = PG_GETARG_TEXT_PP(2);
3938 AclMode mode;
3939 AclResult aclresult;
3940 bool is_missing = false;
3941
3942 mode = convert_schema_priv_string(priv_type_text);
3943
3944 aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3945 roleid, mode,
3946 &is_missing);
3947
3948 if (is_missing)
3950
3951 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3952}
3953
3954/*
3955 * Support routines for has_schema_privilege family.
3956 */
3957
3958/*
3959 * Given a schema name expressed as a string, look it up and return Oid
3960 */
3961static Oid
3963{
3964 char *nspname = text_to_cstring(schemaname);
3965
3966 return get_namespace_oid(nspname, false);
3967}
3968
3969/*
3970 * convert_schema_priv_string
3971 * Convert text string to AclMode value.
3972 */
3973static AclMode
3975{
3976 static const priv_map schema_priv_map[] = {
3977 {"CREATE", ACL_CREATE},
3978 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
3979 {"USAGE", ACL_USAGE},
3980 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3981 {NULL, 0}
3982 };
3983
3984 return convert_any_priv_string(priv_type_text, schema_priv_map);
3985}
3986
3987
3988/*
3989 * has_server_privilege variants
3990 * These are all named "has_server_privilege" at the SQL level.
3991 * They take various combinations of foreign server name,
3992 * server OID, user name, user OID, or implicit user = current_user.
3993 *
3994 * The result is a boolean value: true if user has the indicated
3995 * privilege, false if not.
3996 */
3997
3998/*
3999 * has_server_privilege_name_name
4000 * Check user privileges on a foreign server given
4001 * name username, text servername, and text priv name.
4002 */
4003Datum
4005{
4007 text *servername = PG_GETARG_TEXT_PP(1);
4008 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4009 Oid roleid;
4010 Oid serverid;
4011 AclMode mode;
4012 AclResult aclresult;
4013
4015 serverid = convert_server_name(servername);
4016 mode = convert_server_priv_string(priv_type_text);
4017
4018 aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4019
4020 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4021}
4022
4023/*
4024 * has_server_privilege_name
4025 * Check user privileges on a foreign server given
4026 * text servername and text priv name.
4027 * current_user is assumed
4028 */
4029Datum
4031{
4032 text *servername = PG_GETARG_TEXT_PP(0);
4033 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4034 Oid roleid;
4035 Oid serverid;
4036 AclMode mode;
4037 AclResult aclresult;
4038
4039 roleid = GetUserId();
4040 serverid = convert_server_name(servername);
4041 mode = convert_server_priv_string(priv_type_text);
4042
4043 aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4044
4045 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4046}
4047
4048/*
4049 * has_server_privilege_name_id
4050 * Check user privileges on a foreign server given
4051 * name usename, foreign server oid, and text priv name.
4052 */
4053Datum
4055{
4057 Oid serverid = PG_GETARG_OID(1);
4058 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4059 Oid roleid;
4060 AclMode mode;
4061 AclResult aclresult;
4062 bool is_missing = false;
4063
4065 mode = convert_server_priv_string(priv_type_text);
4066
4067 aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4068 roleid, mode,
4069 &is_missing);
4070
4071 if (is_missing)
4073
4074 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4075}
4076
4077/*
4078 * has_server_privilege_id
4079 * Check user privileges on a foreign server given
4080 * server oid, and text priv name.
4081 * current_user is assumed
4082 */
4083Datum
4085{
4086 Oid serverid = PG_GETARG_OID(0);
4087 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4088 Oid roleid;
4089 AclMode mode;
4090 AclResult aclresult;
4091 bool is_missing = false;
4092
4093 roleid = GetUserId();
4094 mode = convert_server_priv_string(priv_type_text);
4095
4096 aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4097 roleid, mode,
4098 &is_missing);
4099
4100 if (is_missing)
4102
4103 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4104}
4105
4106/*
4107 * has_server_privilege_id_name
4108 * Check user privileges on a foreign server given
4109 * roleid, text servername, and text priv name.
4110 */
4111Datum
4113{
4114 Oid roleid = PG_GETARG_OID(0);
4115 text *servername = PG_GETARG_TEXT_PP(1);
4116 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4117 Oid serverid;
4118 AclMode mode;
4119 AclResult aclresult;
4120
4121 serverid = convert_server_name(servername);
4122 mode = convert_server_priv_string(priv_type_text);
4123
4124 aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4125
4126 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4127}
4128
4129/*
4130 * has_server_privilege_id_id
4131 * Check user privileges on a foreign server given
4132 * roleid, server oid, and text priv name.
4133 */
4134Datum
4136{
4137 Oid roleid = PG_GETARG_OID(0);
4138 Oid serverid = PG_GETARG_OID(1);
4139 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4140 AclMode mode;
4141 AclResult aclresult;
4142 bool is_missing = false;
4143
4144 mode = convert_server_priv_string(priv_type_text);
4145
4146 aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4147 roleid, mode,
4148 &is_missing);
4149
4150 if (is_missing)
4152
4153 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4154}
4155
4156/*
4157 * Support routines for has_server_privilege family.
4158 */
4159
4160/*
4161 * Given a server name expressed as a string, look it up and return Oid
4162 */
4163static Oid
4165{
4166 char *serverstr = text_to_cstring(servername);
4167
4168 return get_foreign_server_oid(serverstr, false);
4169}
4170
4171/*
4172 * convert_server_priv_string
4173 * Convert text string to AclMode value.
4174 */
4175static AclMode
4177{
4178 static const priv_map server_priv_map[] = {
4179 {"USAGE", ACL_USAGE},
4180 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4181 {NULL, 0}
4182 };
4183
4184 return convert_any_priv_string(priv_type_text, server_priv_map);
4185}
4186
4187
4188/*
4189 * has_tablespace_privilege variants
4190 * These are all named "has_tablespace_privilege" at the SQL level.
4191 * They take various combinations of tablespace name, tablespace OID,
4192 * user name, user OID, or implicit user = current_user.
4193 *
4194 * The result is a boolean value: true if user has the indicated
4195 * privilege, false if not.
4196 */
4197
4198/*
4199 * has_tablespace_privilege_name_name
4200 * Check user privileges on a tablespace given
4201 * name username, text tablespacename, and text priv name.
4202 */
4203Datum
4205{
4207 text *tablespacename = PG_GETARG_TEXT_PP(1);
4208 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4209 Oid roleid;
4210 Oid tablespaceoid;
4211 AclMode mode;
4212 AclResult aclresult;
4213
4215 tablespaceoid = convert_tablespace_name(tablespacename);
4216 mode = convert_tablespace_priv_string(priv_type_text);
4217
4218 aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4219
4220 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4221}
4222
4223/*
4224 * has_tablespace_privilege_name
4225 * Check user privileges on a tablespace given
4226 * text tablespacename and text priv name.
4227 * current_user is assumed
4228 */
4229Datum
4231{
4232 text *tablespacename = PG_GETARG_TEXT_PP(0);
4233 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4234 Oid roleid;
4235 Oid tablespaceoid;
4236 AclMode mode;
4237 AclResult aclresult;
4238
4239 roleid = GetUserId();
4240 tablespaceoid = convert_tablespace_name(tablespacename);
4241 mode = convert_tablespace_priv_string(priv_type_text);
4242
4243 aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4244
4245 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4246}
4247
4248/*
4249 * has_tablespace_privilege_name_id
4250 * Check user privileges on a tablespace given
4251 * name usename, tablespace oid, and text priv name.
4252 */
4253Datum
4255{
4257 Oid tablespaceoid = PG_GETARG_OID(1);
4258 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4259 Oid roleid;
4260 AclMode mode;
4261 AclResult aclresult;
4262 bool is_missing = false;
4263
4265 mode = convert_tablespace_priv_string(priv_type_text);
4266
4267 aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4268 roleid, mode,
4269 &is_missing);
4270
4271 if (is_missing)
4273
4274 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4275}
4276
4277/*
4278 * has_tablespace_privilege_id
4279 * Check user privileges on a tablespace given
4280 * tablespace oid, and text priv name.
4281 * current_user is assumed
4282 */
4283Datum
4285{
4286 Oid tablespaceoid = PG_GETARG_OID(0);
4287 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4288 Oid roleid;
4289 AclMode mode;
4290 AclResult aclresult;
4291 bool is_missing = false;
4292
4293 roleid = GetUserId();
4294 mode = convert_tablespace_priv_string(priv_type_text);
4295
4296 aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4297 roleid, mode,
4298 &is_missing);
4299
4300 if (is_missing)
4302
4303 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4304}
4305
4306/*
4307 * has_tablespace_privilege_id_name
4308 * Check user privileges on a tablespace given
4309 * roleid, text tablespacename, and text priv name.
4310 */
4311Datum
4313{
4314 Oid roleid = PG_GETARG_OID(0);
4315 text *tablespacename = PG_GETARG_TEXT_PP(1);
4316 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4317 Oid tablespaceoid;
4318 AclMode mode;
4319 AclResult aclresult;
4320
4321 tablespaceoid = convert_tablespace_name(tablespacename);
4322 mode = convert_tablespace_priv_string(priv_type_text);
4323
4324 aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4325
4326 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4327}
4328
4329/*
4330 * has_tablespace_privilege_id_id
4331 * Check user privileges on a tablespace given
4332 * roleid, tablespace oid, and text priv name.
4333 */
4334Datum
4336{
4337 Oid roleid = PG_GETARG_OID(0);
4338 Oid tablespaceoid = PG_GETARG_OID(1);
4339 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4340 AclMode mode;
4341 AclResult aclresult;
4342 bool is_missing = false;
4343
4344 mode = convert_tablespace_priv_string(priv_type_text);
4345
4346 aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4347 roleid, mode,
4348 &is_missing);
4349
4350 if (is_missing)
4352
4353 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4354}
4355
4356/*
4357 * Support routines for has_tablespace_privilege family.
4358 */
4359
4360/*
4361 * Given a tablespace name expressed as a string, look it up and return Oid
4362 */
4363static Oid
4365{
4366 char *spcname = text_to_cstring(tablespacename);
4367
4368 return get_tablespace_oid(spcname, false);
4369}
4370
4371/*
4372 * convert_tablespace_priv_string
4373 * Convert text string to AclMode value.
4374 */
4375static AclMode
4377{
4378 static const priv_map tablespace_priv_map[] = {
4379 {"CREATE", ACL_CREATE},
4380 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4381 {NULL, 0}
4382 };
4383
4384 return convert_any_priv_string(priv_type_text, tablespace_priv_map);
4385}
4386
4387/*
4388 * has_type_privilege variants
4389 * These are all named "has_type_privilege" at the SQL level.
4390 * They take various combinations of type name, type OID,
4391 * user name, user OID, or implicit user = current_user.
4392 *
4393 * The result is a boolean value: true if user has the indicated
4394 * privilege, false if not, or NULL if object doesn't exist.
4395 */
4396
4397/*
4398 * has_type_privilege_name_name
4399 * Check user privileges on a type given
4400 * name username, text typename, and text priv name.
4401 */
4402Datum
4404{
4406 text *typename = PG_GETARG_TEXT_PP(1);
4407 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4408 Oid roleid;
4409 Oid typeoid;
4410 AclMode mode;
4411 AclResult aclresult;
4412
4414 typeoid = convert_type_name(typename);
4415 mode = convert_type_priv_string(priv_type_text);
4416
4417 aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4418
4419 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4420}
4421
4422/*
4423 * has_type_privilege_name
4424 * Check user privileges on a type given
4425 * text typename and text priv name.
4426 * current_user is assumed
4427 */
4428Datum
4430{
4431 text *typename = PG_GETARG_TEXT_PP(0);
4432 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4433 Oid roleid;
4434 Oid typeoid;
4435 AclMode mode;
4436 AclResult aclresult;
4437
4438 roleid = GetUserId();
4439 typeoid = convert_type_name(typename);
4440 mode = convert_type_priv_string(priv_type_text);
4441
4442 aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4443
4444 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4445}
4446
4447/*
4448 * has_type_privilege_name_id
4449 * Check user privileges on a type given
4450 * name usename, type oid, and text priv name.
4451 */
4452Datum
4454{
4456 Oid typeoid = PG_GETARG_OID(1);
4457 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4458 Oid roleid;
4459 AclMode mode;
4460 AclResult aclresult;
4461 bool is_missing = false;
4462
4464 mode = convert_type_priv_string(priv_type_text);
4465
4466 aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4467 roleid, mode,
4468 &is_missing);
4469
4470 if (is_missing)
4472
4473 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4474}
4475
4476/*
4477 * has_type_privilege_id
4478 * Check user privileges on a type given
4479 * type oid, and text priv name.
4480 * current_user is assumed
4481 */
4482Datum
4484{
4485 Oid typeoid = PG_GETARG_OID(0);
4486 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4487 Oid roleid;
4488 AclMode mode;
4489 AclResult aclresult;
4490 bool is_missing = false;
4491
4492 roleid = GetUserId();
4493 mode = convert_type_priv_string(priv_type_text);
4494
4495 aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4496 roleid, mode,
4497 &is_missing);
4498
4499 if (is_missing)
4501
4502 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4503}
4504
4505/*
4506 * has_type_privilege_id_name
4507 * Check user privileges on a type given
4508 * roleid, text typename, and text priv name.
4509 */
4510Datum
4512{
4513 Oid roleid = PG_GETARG_OID(0);
4514 text *typename = PG_GETARG_TEXT_PP(1);
4515 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4516 Oid typeoid;
4517 AclMode mode;
4518 AclResult aclresult;
4519
4520 typeoid = convert_type_name(typename);
4521 mode = convert_type_priv_string(priv_type_text);
4522
4523 aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4524
4525 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4526}
4527
4528/*
4529 * has_type_privilege_id_id
4530 * Check user privileges on a type given
4531 * roleid, type oid, and text priv name.
4532 */
4533Datum
4535{
4536 Oid roleid = PG_GETARG_OID(0);
4537 Oid typeoid = PG_GETARG_OID(1);
4538 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4539 AclMode mode;
4540 AclResult aclresult;
4541 bool is_missing = false;
4542
4543 mode = convert_type_priv_string(priv_type_text);
4544
4545 aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4546 roleid, mode,
4547 &is_missing);
4548
4549 if (is_missing)
4551
4552 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4553}
4554
4555/*
4556 * Support routines for has_type_privilege family.
4557 */
4558
4559/*
4560 * Given a type name expressed as a string, look it up and return Oid
4561 */
4562static Oid
4564{
4565 char *typname = text_to_cstring(typename);
4566 Oid oid;
4567
4570
4571 if (!OidIsValid(oid))
4572 ereport(ERROR,
4573 (errcode(ERRCODE_UNDEFINED_OBJECT),
4574 errmsg("type \"%s\" does not exist", typname)));
4575
4576 return oid;
4577}
4578
4579/*
4580 * convert_type_priv_string
4581 * Convert text string to AclMode value.
4582 */
4583static AclMode
4585{
4586 static const priv_map type_priv_map[] = {
4587 {"USAGE", ACL_USAGE},
4588 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4589 {NULL, 0}
4590 };
4591
4592 return convert_any_priv_string(priv_type_text, type_priv_map);
4593}
4594
4595/*
4596 * has_parameter_privilege variants
4597 * These are all named "has_parameter_privilege" at the SQL level.
4598 * They take various combinations of parameter name with
4599 * user name, user OID, or implicit user = current_user.
4600 *
4601 * The result is a boolean value: true if user has been granted
4602 * the indicated privilege or false if not.
4603 */
4604
4605/*
4606 * has_param_priv_byname
4607 *
4608 * Helper function to check user privileges on a parameter given the
4609 * role by Oid, parameter by text name, and privileges as AclMode.
4610 */
4611static bool
4612has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
4613{
4614 char *paramstr = text_to_cstring(parameter);
4615
4616 return pg_parameter_aclcheck(paramstr, roleid, priv) == ACLCHECK_OK;
4617}
4618
4619/*
4620 * has_parameter_privilege_name_name
4621 * Check user privileges on a parameter given name username, text
4622 * parameter, and text priv name.
4623 */
4624Datum
4626{
4628 text *parameter = PG_GETARG_TEXT_PP(1);
4631
4632 PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
4633}
4634
4635/*
4636 * has_parameter_privilege_name
4637 * Check user privileges on a parameter given text parameter and text priv
4638 * name. current_user is assumed
4639 */
4640Datum
4642{
4643 text *parameter = PG_GETARG_TEXT_PP(0);
4645
4646 PG_RETURN_BOOL(has_param_priv_byname(GetUserId(), parameter, priv));
4647}
4648
4649/*
4650 * has_parameter_privilege_id_name
4651 * Check user privileges on a parameter given roleid, text parameter, and
4652 * text priv name.
4653 */
4654Datum
4656{
4657 Oid roleid = PG_GETARG_OID(0);
4658 text *parameter = PG_GETARG_TEXT_PP(1);
4660
4661 PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
4662}
4663
4664/*
4665 * Support routines for has_parameter_privilege family.
4666 */
4667
4668/*
4669 * convert_parameter_priv_string
4670 * Convert text string to AclMode value.
4671 */
4672static AclMode
4674{
4675 static const priv_map parameter_priv_map[] = {
4676 {"SET", ACL_SET},
4677 {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SET)},
4678 {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
4679 {"ALTER SYSTEM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ALTER_SYSTEM)},
4680 {NULL, 0}
4681 };
4682
4683 return convert_any_priv_string(priv_text, parameter_priv_map);
4684}
4685
4686/*
4687 * has_largeobject_privilege variants
4688 * These are all named "has_largeobject_privilege" at the SQL level.
4689 * They take various combinations of large object OID with
4690 * user name, user OID, or implicit user = current_user.
4691 *
4692 * The result is a boolean value: true if user has the indicated
4693 * privilege, false if not, or NULL if object doesn't exist.
4694 */
4695
4696/*
4697 * has_lo_priv_byid
4698 *
4699 * Helper function to check user privileges on a large object given the
4700 * role by Oid, large object by Oid, and privileges as AclMode.
4701 */
4702static bool
4703has_lo_priv_byid(Oid roleid, Oid lobjId, AclMode priv, bool *is_missing)
4704{
4705 Snapshot snapshot = NULL;
4706 AclResult aclresult;
4707
4708 if (priv & ACL_UPDATE)
4709 snapshot = NULL;
4710 else
4711 snapshot = GetActiveSnapshot();
4712
4713 if (!LargeObjectExistsWithSnapshot(lobjId, snapshot))
4714 {
4715 Assert(is_missing != NULL);
4716 *is_missing = true;
4717 return false;
4718 }
4719
4721 return true;
4722
4723 aclresult = pg_largeobject_aclcheck_snapshot(lobjId,
4724 roleid,
4725 priv,
4726 snapshot);
4727 return aclresult == ACLCHECK_OK;
4728}
4729
4730/*
4731 * has_largeobject_privilege_name_id
4732 * Check user privileges on a large object given
4733 * name username, large object oid, and text priv name.
4734 */
4735Datum
4737{
4740 Oid lobjId = PG_GETARG_OID(1);
4741 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4742 AclMode mode;
4743 bool is_missing = false;
4744 bool result;
4745
4746 mode = convert_largeobject_priv_string(priv_type_text);
4747 result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4748
4749 if (is_missing)
4751
4752 PG_RETURN_BOOL(result);
4753}
4754
4755/*
4756 * has_largeobject_privilege_id
4757 * Check user privileges on a large object given
4758 * large object oid, and text priv name.
4759 * current_user is assumed
4760 */
4761Datum
4763{
4764 Oid lobjId = PG_GETARG_OID(0);
4765 Oid roleid = GetUserId();
4766 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4767 AclMode mode;
4768 bool is_missing = false;
4769 bool result;
4770
4771 mode = convert_largeobject_priv_string(priv_type_text);
4772 result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4773
4774 if (is_missing)
4776
4777 PG_RETURN_BOOL(result);
4778}
4779
4780/*
4781 * has_largeobject_privilege_id_id
4782 * Check user privileges on a large object given
4783 * roleid, large object oid, and text priv name.
4784 */
4785Datum
4787{
4788 Oid roleid = PG_GETARG_OID(0);
4789 Oid lobjId = PG_GETARG_OID(1);
4790 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4791 AclMode mode;
4792 bool is_missing = false;
4793 bool result;
4794
4795 mode = convert_largeobject_priv_string(priv_type_text);
4796 result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4797
4798 if (is_missing)
4800
4801 PG_RETURN_BOOL(result);
4802}
4803
4804/*
4805 * convert_largeobject_priv_string
4806 * Convert text string to AclMode value.
4807 */
4808static AclMode
4810{
4811 static const priv_map largeobject_priv_map[] = {
4812 {"SELECT", ACL_SELECT},
4813 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
4814 {"UPDATE", ACL_UPDATE},
4815 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
4816 {NULL, 0}
4817 };
4818
4819 return convert_any_priv_string(priv_type_text, largeobject_priv_map);
4820}
4821
4822/*
4823 * pg_has_role variants
4824 * These are all named "pg_has_role" at the SQL level.
4825 * They take various combinations of role name, role OID,
4826 * user name, user OID, or implicit user = current_user.
4827 *
4828 * The result is a boolean value: true if user has the indicated
4829 * privilege, false if not.
4830 */
4831
4832/*
4833 * pg_has_role_name_name
4834 * Check user privileges on a role given
4835 * name username, name rolename, and text priv name.
4836 */
4837Datum
4839{
4841 Name rolename = PG_GETARG_NAME(1);
4842 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4843 Oid roleid;
4844 Oid roleoid;
4845 AclMode mode;
4846 AclResult aclresult;
4847
4848 roleid = get_role_oid(NameStr(*username), false);
4849 roleoid = get_role_oid(NameStr(*rolename), false);
4850 mode = convert_role_priv_string(priv_type_text);
4851
4852 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4853
4854 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4855}
4856
4857/*
4858 * pg_has_role_name
4859 * Check user privileges on a role given
4860 * name rolename and text priv name.
4861 * current_user is assumed
4862 */
4863Datum
4865{
4866 Name rolename = PG_GETARG_NAME(0);
4867 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4868 Oid roleid;
4869 Oid roleoid;
4870 AclMode mode;
4871 AclResult aclresult;
4872
4873 roleid = GetUserId();
4874 roleoid = get_role_oid(NameStr(*rolename), false);
4875 mode = convert_role_priv_string(priv_type_text);
4876
4877 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4878
4879 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4880}
4881
4882/*
4883 * pg_has_role_name_id
4884 * Check user privileges on a role given
4885 * name usename, role oid, and text priv name.
4886 */
4887Datum
4889{
4891 Oid roleoid = PG_GETARG_OID(1);
4892 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4893 Oid roleid;
4894 AclMode mode;
4895 AclResult aclresult;
4896
4897 roleid = get_role_oid(NameStr(*username), false);
4898 mode = convert_role_priv_string(priv_type_text);
4899
4900 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4901
4902 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4903}
4904
4905/*
4906 * pg_has_role_id
4907 * Check user privileges on a role given
4908 * role oid, and text priv name.
4909 * current_user is assumed
4910 */
4911Datum
4913{
4914 Oid roleoid = PG_GETARG_OID(0);
4915 text *priv_type_text = PG_GETARG_TEXT_PP(1);
4916 Oid roleid;
4917 AclMode mode;
4918 AclResult aclresult;
4919
4920 roleid = GetUserId();
4921 mode = convert_role_priv_string(priv_type_text);
4922
4923 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4924
4925 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4926}
4927
4928/*
4929 * pg_has_role_id_name
4930 * Check user privileges on a role given
4931 * roleid, name rolename, and text priv name.
4932 */
4933Datum
4935{
4936 Oid roleid = PG_GETARG_OID(0);
4937 Name rolename = PG_GETARG_NAME(1);
4938 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4939 Oid roleoid;
4940 AclMode mode;
4941 AclResult aclresult;
4942
4943 roleoid = get_role_oid(NameStr(*rolename), false);
4944 mode = convert_role_priv_string(priv_type_text);
4945
4946 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4947
4948 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4949}
4950
4951/*
4952 * pg_has_role_id_id
4953 * Check user privileges on a role given
4954 * roleid, role oid, and text priv name.
4955 */
4956Datum
4958{
4959 Oid roleid = PG_GETARG_OID(0);
4960 Oid roleoid = PG_GETARG_OID(1);
4961 text *priv_type_text = PG_GETARG_TEXT_PP(2);
4962 AclMode mode;
4963 AclResult aclresult;
4964
4965 mode = convert_role_priv_string(priv_type_text);
4966
4967 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4968
4969 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4970}
4971
4972/*
4973 * Support routines for pg_has_role family.
4974 */
4975
4976/*
4977 * convert_role_priv_string
4978 * Convert text string to AclMode value.
4979 *
4980 * We use USAGE to denote whether the privileges of the role are accessible
4981 * (has_privs_of_role), MEMBER to denote is_member, and MEMBER WITH GRANT
4982 * (or ADMIN) OPTION to denote is_admin. There is no ACL bit corresponding
4983 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
4984 * is shared only with pg_role_aclcheck, below.
4985 */
4986static AclMode
4988{
4989 static const priv_map role_priv_map[] = {
4990 {"USAGE", ACL_USAGE},
4991 {"MEMBER", ACL_CREATE},
4992 {"SET", ACL_SET},
4993 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4994 {"USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4995 {"MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4996 {"MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4997 {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4998 {"SET WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4999 {NULL, 0}
5000 };
5001
5002 return convert_any_priv_string(priv_type_text, role_priv_map);
5003}
5004
5005/*
5006 * pg_role_aclcheck
5007 * Quick-and-dirty support for pg_has_role
5008 */
5009static AclResult
5011{
5013 {
5014 if (is_admin_of_role(roleid, role_oid))
5015 return ACLCHECK_OK;
5016 }
5017 if (mode & ACL_CREATE)
5018 {
5019 if (is_member_of_role(roleid, role_oid))
5020 return ACLCHECK_OK;
5021 }
5022 if (mode & ACL_USAGE)
5023 {
5024 if (has_privs_of_role(roleid, role_oid))
5025 return ACLCHECK_OK;
5026 }
5027 if (mode & ACL_SET)
5028 {
5029 if (member_can_set_role(roleid, role_oid))
5030 return ACLCHECK_OK;
5031 }
5032 return ACLCHECK_NO_PRIV;
5033}
5034
5035
5036/*
5037 * initialization function (called by InitPostgres)
5038 */
5039void
5041{
5043 {
5045 GetSysCacheHashValue1(DATABASEOID,
5047
5048 /*
5049 * In normal mode, set a callback on any syscache invalidation of rows
5050 * of pg_auth_members (for roles_is_member_of()) pg_database (for
5051 * roles_is_member_of())
5052 */
5053 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
5055 (Datum) 0);
5058 (Datum) 0);
5061 (Datum) 0);
5062 }
5063}
5064
5065/*
5066 * RoleMembershipCacheCallback
5067 * Syscache inval callback function
5068 */
5069static void
5071{
5072 if (cacheid == DATABASEOID &&
5073 hashvalue != cached_db_hash &&
5074 hashvalue != 0)
5075 {
5076 return; /* ignore pg_database changes for other DBs */
5077 }
5078
5079 /* Force membership caches to be recomputed on next use */
5083}
5084
5085/*
5086 * A helper function for roles_is_member_of() that provides an optimized
5087 * implementation of list_append_unique_oid() via a Bloom filter. The caller
5088 * (i.e., roles_is_member_of()) is responsible for freeing bf once it is done
5089 * using this function.
5090 */
5091static inline List *
5092roles_list_append(List *roles_list, bloom_filter **bf, Oid role)
5093{
5094 unsigned char *roleptr = (unsigned char *) &role;
5095
5096 /*
5097 * If there is a previously-created Bloom filter, use it to try to
5098 * determine whether the role is missing from the list. If it says yes,
5099 * that's a hard fact and we can go ahead and add the role. If it says
5100 * no, that's only probabilistic and we'd better search the list. Without
5101 * a filter, we must always do an ordinary linear search through the
5102 * existing list.
5103 */
5104 if ((*bf && bloom_lacks_element(*bf, roleptr, sizeof(Oid))) ||
5105 !list_member_oid(roles_list, role))
5106 {
5107 /*
5108 * If the list is large, we take on the overhead of creating and
5109 * populating a Bloom filter to speed up future calls to this
5110 * function.
5111 */
5112 if (*bf == NULL &&
5114 {
5116 foreach_oid(roleid, roles_list)
5117 bloom_add_element(*bf, (unsigned char *) &roleid, sizeof(Oid));
5118 }
5119
5120 /*
5121 * Finally, add the role to the list and the Bloom filter, if it
5122 * exists.
5123 */
5124 roles_list = lappend_oid(roles_list, role);
5125 if (*bf)
5126 bloom_add_element(*bf, roleptr, sizeof(Oid));
5127 }
5128
5129 return roles_list;
5130}
5131
5132/*
5133 * Get a list of roles that the specified roleid is a member of
5134 *
5135 * Type ROLERECURSE_MEMBERS recurses through all grants; ROLERECURSE_PRIVS
5136 * recurses only through inheritable grants; and ROLERECURSE_SETROLE recurses
5137 * only through grants with set_option.
5138 *
5139 * Since indirect membership testing is relatively expensive, we cache
5140 * a list of memberships. Hence, the result is only guaranteed good until
5141 * the next call of roles_is_member_of()!
5142 *
5143 * For the benefit of select_best_grantor, the result is defined to be
5144 * in breadth-first order, ie, closer relationships earlier.
5145 *
5146 * If admin_of is not InvalidOid, this function sets *admin_role, either
5147 * to the OID of the first role in the result list that directly possesses
5148 * ADMIN OPTION on the role corresponding to admin_of, or to InvalidOid if
5149 * there is no such role.
5150 */
5151static List *
5153 Oid admin_of, Oid *admin_role)
5154{
5155 Oid dba;
5156 List *roles_list;
5157 ListCell *l;
5158 List *new_cached_roles;
5159 MemoryContext oldctx;
5160 bloom_filter *bf = NULL;
5161
5162 Assert(OidIsValid(admin_of) == (admin_role != NULL));
5163 if (admin_role != NULL)
5164 *admin_role = InvalidOid;
5165
5166 /* If cache is valid and ADMIN OPTION not sought, just return the list */
5167 if (cached_role[type] == roleid && !OidIsValid(admin_of) &&
5169 return cached_roles[type];
5170
5171 /*
5172 * Role expansion happens in a non-database backend when guc.c checks
5173 * ROLE_PG_READ_ALL_SETTINGS for a physical walsender SHOW command. In
5174 * that case, no role gets pg_database_owner.
5175 */
5177 dba = InvalidOid;
5178 else
5179 {
5180 HeapTuple dbtup;
5181
5182 dbtup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
5183 if (!HeapTupleIsValid(dbtup))
5184 elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
5185 dba = ((Form_pg_database) GETSTRUCT(dbtup))->datdba;
5186 ReleaseSysCache(dbtup);
5187 }
5188
5189 /*
5190 * Find all the roles that roleid is a member of, including multi-level
5191 * recursion. The role itself will always be the first element of the
5192 * resulting list.
5193 *
5194 * Each element of the list is scanned to see if it adds any indirect
5195 * memberships. We can use a single list as both the record of
5196 * already-found memberships and the agenda of roles yet to be scanned.
5197 * This is a bit tricky but works because the foreach() macro doesn't
5198 * fetch the next list element until the bottom of the loop.
5199 */
5200 roles_list = list_make1_oid(roleid);
5201
5202 foreach(l, roles_list)
5203 {
5204 Oid memberid = lfirst_oid(l);
5205 CatCList *memlist;
5206 int i;
5207
5208 /* Find roles that memberid is directly a member of */
5209 memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
5210 ObjectIdGetDatum(memberid));
5211 for (i = 0; i < memlist->n_members; i++)
5212 {
5213 HeapTuple tup = &memlist->members[i]->tuple;
5215 Oid otherid = form->roleid;
5216
5217 /*
5218 * While otherid==InvalidOid shouldn't appear in the catalog, the
5219 * OidIsValid() avoids crashing if that arises.
5220 */
5221 if (otherid == admin_of && form->admin_option &&
5222 OidIsValid(admin_of) && !OidIsValid(*admin_role))
5223 *admin_role = memberid;
5224
5225 /* If we're supposed to ignore non-heritable grants, do so. */
5226 if (type == ROLERECURSE_PRIVS && !form->inherit_option)
5227 continue;
5228
5229 /* If we're supposed to ignore non-SET grants, do so. */
5230 if (type == ROLERECURSE_SETROLE && !form->set_option)
5231 continue;
5232
5233 /*
5234 * Even though there shouldn't be any loops in the membership
5235 * graph, we must test for having already seen this role. It is
5236 * legal for instance to have both A->B and A->C->B.
5237 */
5238 roles_list = roles_list_append(roles_list, &bf, otherid);
5239 }
5240 ReleaseSysCacheList(memlist);
5241
5242 /* implement pg_database_owner implicit membership */
5243 if (memberid == dba && OidIsValid(dba))
5244 roles_list = roles_list_append(roles_list, &bf,
5245 ROLE_PG_DATABASE_OWNER);
5246 }
5247
5248 /*
5249 * Free the Bloom filter created by roles_list_append(), if there is one.
5250 */
5251 if (bf)
5252 bloom_free(bf);
5253
5254 /*
5255 * Copy the completed list into TopMemoryContext so it will persist.
5256 */
5258 new_cached_roles = list_copy(roles_list);
5259 MemoryContextSwitchTo(oldctx);
5260 list_free(roles_list);
5261
5262 /*
5263 * Now safe to assign to state variable
5264 */
5265 cached_role[type] = InvalidOid; /* just paranoia */
5267 cached_roles[type] = new_cached_roles;
5268 cached_role[type] = roleid;
5269
5270 /* And now we can return the answer */
5271 return cached_roles[type];
5272}
5273
5274
5275/*
5276 * Does member have the privileges of role (directly or indirectly)?
5277 *
5278 * This is defined not to recurse through grants that are not inherited,
5279 * and only inherited grants confer the associated privileges automatically.
5280 *
5281 * See also member_can_set_role, below.
5282 */
5283bool
5285{
5286 /* Fast path for simple case */
5287 if (member == role)
5288 return true;
5289
5290 /* Superusers have every privilege, so are part of every role */
5291 if (superuser_arg(member))
5292 return true;
5293
5294 /*
5295 * Find all the roles that member has the privileges of, including
5296 * multi-level recursion, then see if target role is any one of them.
5297 */
5299 InvalidOid, NULL),
5300 role);
5301}
5302
5303/*
5304 * Can member use SET ROLE to this role?
5305 *
5306 * There must be a chain of grants from 'member' to 'role' each of which
5307 * permits SET ROLE; that is, each of which has set_option = true.
5308 *
5309 * It doesn't matter whether the grants are inheritable. That's a separate
5310 * question; see has_privs_of_role.
5311 *
5312 * This function should be used to determine whether the session user can
5313 * use SET ROLE to become the target user. We also use it to determine whether
5314 * the session user can change an existing object to be owned by the target
5315 * user, or create new objects owned by the target user.
5316 */
5317bool
5319{
5320 /* Fast path for simple case */
5321 if (member == role)
5322 return true;
5323
5324 /* Superusers have every privilege, so can always SET ROLE */
5325 if (superuser_arg(member))
5326 return true;
5327
5328 /*
5329 * Find all the roles that member can access via SET ROLE, including
5330 * multi-level recursion, then see if target role is any one of them.
5331 */
5333 InvalidOid, NULL),
5334 role);
5335}
5336
5337/*
5338 * Permission violation error unless able to SET ROLE to target role.
5339 */
5340void
5342{
5343 if (!member_can_set_role(member, role))
5344 ereport(ERROR,
5345 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
5346 errmsg("must be able to SET ROLE \"%s\"",
5347 GetUserNameFromId(role, false))));
5348}
5349
5350/*
5351 * Is member a member of role (directly or indirectly)?
5352 *
5353 * This is defined to recurse through grants whether they are inherited or not.
5354 *
5355 * Do not use this for privilege checking, instead use has_privs_of_role().
5356 * Don't use it for determining whether it's possible to SET ROLE to some
5357 * other role; for that, use member_can_set_role(). And don't use it for
5358 * determining whether it's OK to create an object owned by some other role:
5359 * use member_can_set_role() for that, too.
5360 *
5361 * In short, calling this function is the wrong thing to do nearly everywhere.
5362 */
5363bool
5365{
5366 /* Fast path for simple case */
5367 if (member == role)
5368 return true;
5369
5370 /* Superusers have every privilege, so are part of every role */
5371 if (superuser_arg(member))
5372 return true;
5373
5374 /*
5375 * Find all the roles that member is a member of, including multi-level
5376 * recursion, then see if target role is any one of them.
5377 */
5379 InvalidOid, NULL),
5380 role);
5381}
5382
5383/*
5384 * Is member a member of role, not considering superuserness?
5385 *
5386 * This is identical to is_member_of_role except we ignore superuser
5387 * status.
5388 *
5389 * Do not use this for privilege checking, instead use has_privs_of_role()
5390 */
5391bool
5393{
5394 /* Fast path for simple case */
5395 if (member == role)
5396 return true;
5397
5398 /*
5399 * Find all the roles that member is a member of, including multi-level
5400 * recursion, then see if target role is any one of them.
5401 */
5403 InvalidOid, NULL),
5404 role);
5405}
5406
5407
5408/*
5409 * Is member an admin of role? That is, is member the role itself (subject to
5410 * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
5411 * or a superuser?
5412 */
5413bool
5415{
5416 Oid admin_role;
5417
5418 if (superuser_arg(member))
5419 return true;
5420
5421 /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5422 if (member == role)
5423 return false;
5424
5425 (void) roles_is_member_of(member, ROLERECURSE_MEMBERS, role, &admin_role);
5426 return OidIsValid(admin_role);
5427}
5428
5429/*
5430 * Find a role whose privileges "member" inherits which has ADMIN OPTION
5431 * on "role", ignoring super-userness.
5432 *
5433 * There might be more than one such role; prefer one which involves fewer
5434 * hops. That is, if member has ADMIN OPTION, prefer that over all other
5435 * options; if not, prefer a role from which member inherits more directly
5436 * over more indirect inheritance.
5437 */
5438Oid
5440{
5441 Oid admin_role;
5442
5443 /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5444 if (member == role)
5445 return InvalidOid;
5446
5447 (void) roles_is_member_of(member, ROLERECURSE_PRIVS, role, &admin_role);
5448 return admin_role;
5449}
5450
5451/*
5452 * Select the effective grantor ID for a GRANT or REVOKE operation.
5453 *
5454 * The grantor must always be either the object owner or some role that has
5455 * been explicitly granted grant options. This ensures that all granted
5456 * privileges appear to flow from the object owner, and there are never
5457 * multiple "original sources" of a privilege. Therefore, if the would-be
5458 * grantor is a member of a role that has the needed grant options, we have
5459 * to do the grant as that role instead.
5460 *
5461 * It is possible that the would-be grantor is a member of several roles
5462 * that have different subsets of the desired grant options, but no one
5463 * role has 'em all. In this case we pick a role with the largest number
5464 * of desired options. Ties are broken in favor of closer ancestors.
5465 *
5466 * roleId: the role attempting to do the GRANT/REVOKE
5467 * privileges: the privileges to be granted/revoked
5468 * acl: the ACL of the object in question
5469 * ownerId: the role owning the object in question
5470 * *grantorId: receives the OID of the role to do the grant as
5471 * *grantOptions: receives the grant options actually held by grantorId
5472 *
5473 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
5474 */
5475void
5477 const Acl *acl, Oid ownerId,
5478 Oid *grantorId, AclMode *grantOptions)
5479{
5480 AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
5481 List *roles_list;
5482 int nrights;
5483 ListCell *l;
5484
5485 /*
5486 * The object owner is always treated as having all grant options, so if
5487 * roleId is the owner it's easy. Also, if roleId is a superuser it's
5488 * easy: superusers are implicitly members of every role, so they act as
5489 * the object owner.
5490 */
5491 if (roleId == ownerId || superuser_arg(roleId))
5492 {
5493 *grantorId = ownerId;
5494 *grantOptions = needed_goptions;
5495 return;
5496 }
5497
5498 /*
5499 * Otherwise we have to do a careful search to see if roleId has the
5500 * privileges of any suitable role. Note: we can hang onto the result of
5501 * roles_is_member_of() throughout this loop, because aclmask_direct()
5502 * doesn't query any role memberships.
5503 */
5504 roles_list = roles_is_member_of(roleId, ROLERECURSE_PRIVS,
5505 InvalidOid, NULL);
5506
5507 /* initialize candidate result as default */
5508 *grantorId = roleId;
5509 *grantOptions = ACL_NO_RIGHTS;
5510 nrights = 0;
5511
5512 foreach(l, roles_list)
5513 {
5514 Oid otherrole = lfirst_oid(l);
5515 AclMode otherprivs;
5516
5517 otherprivs = aclmask_direct(acl, otherrole, ownerId,
5518 needed_goptions, ACLMASK_ALL);
5519 if (otherprivs == needed_goptions)
5520 {
5521 /* Found a suitable grantor */
5522 *grantorId = otherrole;
5523 *grantOptions = otherprivs;
5524 return;
5525 }
5526
5527 /*
5528 * If it has just some of the needed privileges, remember best
5529 * candidate.
5530 */
5531 if (otherprivs != ACL_NO_RIGHTS)
5532 {
5533 int nnewrights = pg_popcount64(otherprivs);
5534
5535 if (nnewrights > nrights)
5536 {
5537 *grantorId = otherrole;
5538 *grantOptions = otherprivs;
5539 nrights = nnewrights;
5540 }
5541 }
5542 }
5543}
5544
5545/*
5546 * get_role_oid - Given a role name, look up the role's OID.
5547 *
5548 * If missing_ok is false, throw an error if role name not found. If
5549 * true, just return InvalidOid.
5550 */
5551Oid
5552get_role_oid(const char *rolname, bool missing_ok)
5553{
5554 Oid oid;
5555
5556 oid = GetSysCacheOid1(AUTHNAME, Anum_pg_authid_oid,
5558 if (!OidIsValid(oid) && !missing_ok)
5559 ereport(ERROR,
5560 (errcode(ERRCODE_UNDEFINED_OBJECT),
5561 errmsg("role \"%s\" does not exist", rolname)));
5562 return oid;
5563}
5564
5565/*
5566 * get_role_oid_or_public - As above, but return ACL_ID_PUBLIC if the
5567 * role name is "public".
5568 */
5569Oid
5571{
5572 if (strcmp(rolname, "public") == 0)
5573 return ACL_ID_PUBLIC;
5574
5575 return get_role_oid(rolname, false);
5576}
5577
5578/*
5579 * Given a RoleSpec node, return the OID it corresponds to. If missing_ok is
5580 * true, return InvalidOid if the role does not exist.
5581 *
5582 * PUBLIC is always disallowed here. Routines wanting to handle the PUBLIC
5583 * case must check the case separately.
5584 */
5585Oid
5586get_rolespec_oid(const RoleSpec *role, bool missing_ok)
5587{
5588 Oid oid;
5589
5590 switch (role->roletype)
5591 {
5592 case ROLESPEC_CSTRING:
5593 Assert(role->rolename);
5594 oid = get_role_oid(role->rolename, missing_ok);
5595 break;
5596
5599 oid = GetUserId();
5600 break;
5601
5603 oid = GetSessionUserId();
5604 break;
5605
5606 case ROLESPEC_PUBLIC:
5607 ereport(ERROR,
5608 (errcode(ERRCODE_UNDEFINED_OBJECT),
5609 errmsg("role \"%s\" does not exist", "public")));
5610 oid = InvalidOid; /* make compiler happy */
5611 break;
5612
5613 default:
5614 elog(ERROR, "unexpected role type %d", role->roletype);
5615 }
5616
5617 return oid;
5618}
5619
5620/*
5621 * Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
5622 * Caller must ReleaseSysCache when done with the result tuple.
5623 */
5626{
5627 HeapTuple tuple;
5628
5629 switch (role->roletype)
5630 {
5631 case ROLESPEC_CSTRING:
5632 Assert(role->rolename);
5633 tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolename));
5634 if (!HeapTupleIsValid(tuple))
5635 ereport(ERROR,
5636 (errcode(ERRCODE_UNDEFINED_OBJECT),
5637 errmsg("role \"%s\" does not exist", role->rolename)));
5638 break;
5639
5642 tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
5643 if (!HeapTupleIsValid(tuple))
5644 elog(ERROR, "cache lookup failed for role %u", GetUserId());
5645 break;
5646
5649 if (!HeapTupleIsValid(tuple))
5650 elog(ERROR, "cache lookup failed for role %u", GetSessionUserId());
5651 break;
5652
5653 case ROLESPEC_PUBLIC:
5654 ereport(ERROR,
5655 (errcode(ERRCODE_UNDEFINED_OBJECT),
5656 errmsg("role \"%s\" does not exist", "public")));
5657 tuple = NULL; /* make compiler happy */
5658 break;
5659
5660 default:
5661 elog(ERROR, "unexpected role type %d", role->roletype);
5662 }
5663
5664 return tuple;
5665}
5666
5667/*
5668 * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
5669 */
5670char *
5672{
5673 HeapTuple tp;
5674 Form_pg_authid authForm;
5675 char *rolename;
5676
5677 tp = get_rolespec_tuple(role);
5678 authForm = (Form_pg_authid) GETSTRUCT(tp);
5679 rolename = pstrdup(NameStr(authForm->rolname));
5680 ReleaseSysCache(tp);
5681
5682 return rolename;
5683}
5684
5685/*
5686 * Given a RoleSpec, throw an error if the name is reserved, using detail_msg,
5687 * if provided (which must be already translated).
5688 *
5689 * If node is NULL, no error is thrown. If detail_msg is NULL then no detail
5690 * message is provided.
5691 */
5692void
5693check_rolespec_name(const RoleSpec *role, const char *detail_msg)
5694{
5695 if (!role)
5696 return;
5697
5698 if (role->roletype != ROLESPEC_CSTRING)
5699 return;
5700
5701 if (IsReservedName(role->rolename))
5702 {
5703 if (detail_msg)
5704 ereport(ERROR,
5705 (errcode(ERRCODE_RESERVED_NAME),
5706 errmsg("role name \"%s\" is reserved",
5707 role->rolename),
5708 errdetail_internal("%s", detail_msg)));
5709 else
5710 ereport(ERROR,
5711 (errcode(ERRCODE_RESERVED_NAME),
5712 errmsg("role name \"%s\" is reserved",
5713 role->rolename)));
5714 }
5715}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:262
static List * roles_is_member_of(Oid roleid, enum RoleRecurseType type, Oid admin_of, Oid *admin_role)
Definition: acl.c:5152
Datum pg_has_role_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4957
Datum has_schema_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3882
Datum has_largeobject_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4786
Datum hash_aclitem(PG_FUNCTION_ARGS)
Definition: acl.c:768
void initialize_acl(void)
Definition: acl.c:5040
Datum has_sequence_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:2136
Datum has_table_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:2021
Datum has_server_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:4084
Datum has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4335
Datum has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2760
Datum has_server_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:4004
Datum aclinsert(PG_FUNCTION_ARGS)
Definition: acl.c:1592
static AclMode convert_function_priv_string(text *priv_type_text)
Definition: acl.c:3574
Datum has_largeobject_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4736
static const char * getid(const char *s, char *n, Node *escontext)
Definition: acl.c:168
bool is_admin_of_role(Oid member, Oid role)
Definition: acl.c:5414
Datum has_column_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2840
static bool aclitem_match(const AclItem *a1, const AclItem *a2)
Definition: acl.c:713
Datum pg_has_role_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:4838
Datum has_language_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3602
Acl * aclconcat(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:477
Datum has_schema_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3802
Acl * aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
Definition: acl.c:501
Datum aclitem_eq(PG_FUNCTION_ARGS)
Definition: acl.c:748
Datum has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4254
Datum makeaclitem(PG_FUNCTION_ARGS)
Definition: acl.c:1634
Datum has_table_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:1998
Datum has_server_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4054
Datum has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2658
Datum has_language_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3710
static int column_privilege_check(Oid tableoid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: acl.c:2535
static Oid convert_type_name(text *typename)
Definition: acl.c:4563
Oid select_best_admin(Oid member, Oid role)
Definition: acl.c:5439
Datum aclexplode(PG_FUNCTION_ARGS)
Definition: acl.c:1790
static Oid convert_database_name(text *databasename)
Definition: acl.c:3147
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition: acl.c:803
Datum aclitemout(PG_FUNCTION_ARGS)
Definition: acl.c:646
Oid get_role_oid_or_public(const char *rolname)
Definition: acl.c:5570
Datum has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3243
Datum has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3324
bool aclequal(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:559
Datum hash_aclitem_extended(PG_FUNCTION_ARGS)
Definition: acl.c:782
static void check_acl(const Acl *acl)
Definition: acl.c:590
Datum has_parameter_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:4625
Datum has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3273
#define ROLES_LIST_BLOOM_THRESHOLD
Definition: acl.c:90
Datum has_database_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3013
static uint32 cached_db_hash
Definition: acl.c:82
Datum has_type_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:4403
Datum has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2575
Datum pg_has_role_name(PG_FUNCTION_ARGS)
Definition: acl.c:4864
Datum has_sequence_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:2202
static AclMode convert_largeobject_priv_string(text *priv_type_text)
Definition: acl.c:4809
static List * roles_list_append(List *roles_list, bloom_filter **bf, Oid role)
Definition: acl.c:5092
static AclMode convert_type_priv_string(text *priv_type_text)
Definition: acl.c:4584
Datum has_tablespace_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:4230
static AclMode convert_table_priv_string(text *priv_type_text)
Definition: acl.c:2063
static AclMode convert_server_priv_string(text *priv_type_text)
Definition: acl.c:4176
Datum has_table_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:1944
Datum has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3193
Datum has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4312
Acl * aclupdate(const Acl *old_acl, const AclItem *mod_aip, int modechg, Oid ownerId, DropBehavior behavior)
Definition: acl.c:992
static Acl * recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs, Oid ownerId, DropBehavior behavior)
Definition: acl.c:1302
static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: acl.c:5070
Datum has_database_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3037
static Oid convert_schema_name(text *schemaname)
Definition: acl.c:3962
Datum has_column_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2784
static void putid(char *p, const char *s)
Definition: acl.c:221
Datum has_schema_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3910
static void check_circularity(const Acl *old_acl, const AclItem *mod_aip, Oid ownerId)
Definition: acl.c:1222
static bool has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
Definition: acl.c:4612
bool is_member_of_role(Oid member, Oid role)
Definition: acl.c:5364
Datum has_sequence_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2237
Datum has_database_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3095
static Oid convert_foreign_data_wrapper_name(text *fdwname)
Definition: acl.c:3353
Datum has_language_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3682
static AclMode convert_database_priv_string(text *priv_type_text)
Definition: acl.c:3159
Datum has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3219
Datum has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2813
Datum has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2867
RoleRecurseType
Definition: acl.c:75
@ ROLERECURSE_PRIVS
Definition: acl.c:77
@ ROLERECURSE_MEMBERS
Definition: acl.c:76
@ ROLERECURSE_SETROLE
Definition: acl.c:78
Datum has_type_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4453
Datum has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:2389
Datum has_server_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4112
Datum has_language_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3652
Datum has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3301
Datum has_schema_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3852
Datum has_function_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:3393
void select_best_grantor(Oid roleId, AclMode privileges, const Acl *acl, Oid ownerId, Oid *grantorId, AclMode *grantOptions)
Definition: acl.c:5476
Datum has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2331
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5392
Datum has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:2165
Datum has_schema_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3828
Datum acldefault_sql(PG_FUNCTION_ARGS)
Definition: acl.c:920
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5284
Acl * make_empty_acl(void)
Definition: acl.c:448
static Oid convert_language_name(text *languagename)
Definition: acl.c:3762
Datum has_language_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3733
static AclMode convert_any_priv_string(text *priv_type_text, const priv_map *privileges)
Definition: acl.c:1686
Datum has_database_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3118
Datum has_function_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3419
static bool is_safe_acl_char(unsigned char c, bool is_getid)
Definition: acl.c:145
int aclmembers(const Acl *acl, Oid **roleids)
Definition: acl.c:1540
Datum has_language_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:3628
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1119
Datum has_server_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:4030
bool member_can_set_role(Oid member, Oid role)
Definition: acl.c:5318
Datum aclremove(PG_FUNCTION_ARGS)
Definition: acl.c:1602
static const char * convert_aclright_to_string(int aclright)
Definition: acl.c:1734
Acl * aclcopy(const Acl *orig_acl)
Definition: acl.c:457
Datum has_function_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3473
void aclitemsort(Acl *acl)
Definition: acl.c:545
Datum has_table_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:1972
Datum has_function_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3524
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1388
static Oid convert_server_name(text *servername)
Definition: acl.c:4164
static Oid convert_tablespace_name(text *tablespacename)
Definition: acl.c:4364
Datum has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2604
static AclMode convert_parameter_priv_string(text *priv_text)
Definition: acl.c:4673
static Oid convert_table_name(text *tablename)
Definition: acl.c:2048
Datum has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2631
static AclMode convert_tablespace_priv_string(text *priv_type_text)
Definition: acl.c:4376
static AclMode convert_language_priv_string(text *priv_type_text)
Definition: acl.c:3774
Datum aclitemin(PG_FUNCTION_ARGS)
Definition: acl.c:615
static AclMode convert_sequence_priv_string(text *priv_type_text)
Definition: acl.c:2298
Datum pg_has_role_id(PG_FUNCTION_ARGS)
Definition: acl.c:4912
Datum has_parameter_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4655
static Acl * allocacl(int n)
Definition: acl.c:426
static AttrNumber convert_column_name(Oid tableoid, text *column)
Definition: acl.c:2895
static AclMode convert_role_priv_string(text *priv_type_text)
Definition: acl.c:4987
static bool has_lo_priv_byid(Oid roleid, Oid lobjId, AclMode priv, bool *is_missing)
Definition: acl.c:4703
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5552
static Oid cached_role[]
Definition: acl.c:80
Datum has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:4204
Datum has_parameter_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:4641
Datum has_any_column_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:2361
Datum has_sequence_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2105
Datum has_function_privilege_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:3443
Datum has_type_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4534
char * get_rolespec_name(const RoleSpec *role)
Definition: acl.c:5671
Datum has_server_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:4135
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
Definition: acl.c:5010
Datum has_function_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:3501
Datum has_table_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:1920
Datum has_type_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4511
Datum has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
Definition: acl.c:2710
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5341
static const char * aclparse(const char *s, AclItem *aip, Node *escontext)
Definition: acl.c:273
void check_rolespec_name(const RoleSpec *role, const char *detail_msg)
Definition: acl.c:5693
Datum has_type_privilege_name(PG_FUNCTION_ARGS)
Definition: acl.c:4429
static List * cached_roles[]
Definition: acl.c:81
static AclMode aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1477
Datum has_tablespace_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:4284
Datum pg_has_role_name_id(PG_FUNCTION_ARGS)
Definition: acl.c:4888
Datum aclcontains(PG_FUNCTION_ARGS)
Definition: acl.c:1612
static Oid convert_function_name(text *functionname)
Definition: acl.c:3553
Datum has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2683
Datum has_schema_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:3933
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5586
Datum has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2457
Datum has_largeobject_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:4762
Datum has_database_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:2987
Datum has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:2735
static AclMode convert_schema_priv_string(text *priv_type_text)
Definition: acl.c:3974
Datum has_table_privilege_name_name(PG_FUNCTION_ARGS)
Definition: acl.c:1894
Datum has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:2484
static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text)
Definition: acl.c:3365
Datum has_database_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:3067
static int aclitemComparator(const void *arg1, const void *arg2)
Definition: acl.c:724
Datum has_type_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:4483
Datum has_any_column_privilege_id(PG_FUNCTION_ARGS)
Definition: acl.c:2424
Datum pg_has_role_id_name(PG_FUNCTION_ARGS)
Definition: acl.c:4934
Datum has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
Definition: acl.c:2265
HeapTuple get_rolespec_tuple(const RoleSpec *role)
Definition: acl.c:5625
static AclMode convert_column_priv_string(text *priv_type_text)
Definition: acl.c:2953
#define ACL_CREATE_CHR
Definition: acl.h:146
#define PG_RETURN_ACLITEM_P(x)
Definition: acl.h:118
#define ACL_ALL_RIGHTS_STR
Definition: acl.h:154
#define ACL_SET_CHR
Definition: acl.h:149
#define ACL_REFERENCES_CHR
Definition: acl.h:142
#define ACLITEM_ALL_GOPTION_BITS
Definition: acl.h:88
#define ACL_SIZE(ACL)
Definition: acl.h:111
#define PG_GETARG_ACLITEM_P(n)
Definition: acl.h:117
#define ACL_DAT(ACL)
Definition: acl.h:109
#define ACL_ALL_RIGHTS_FOREIGN_SERVER
Definition: acl.h:164
#define ACL_TRUNCATE_CHR
Definition: acl.h:141
#define ACL_ALL_RIGHTS_TABLESPACE
Definition: acl.h:170
AclResult
Definition: acl.h:182
@ ACLCHECK_NO_PRIV
Definition: acl.h:184
@ ACLCHECK_OK
Definition: acl.h:183
#define ACLITEM_GET_PRIVS(item)
Definition: acl.h:66
#define ACL_ALL_RIGHTS_PARAMETER_ACL
Definition: acl.h:168
#define ACL_SELECT_CHR
Definition: acl.h:138
#define ACL_ALL_RIGHTS_SCHEMA
Definition: acl.h:169
#define ACL_EXECUTE_CHR
Definition: acl.h:144
#define ACL_MODECHG_DEL
Definition: acl.h:130
#define ACL_DELETE_CHR
Definition: acl.h:140
#define ACL_ALL_RIGHTS_SEQUENCE
Definition: acl.h:161
#define ACL_ALL_RIGHTS_DATABASE
Definition: acl.h:162
#define ACL_MODECHG_ADD
Definition: acl.h:129
#define ACL_OPTION_TO_PRIVS(privs)
Definition: acl.h:71
#define ACL_INSERT_CHR
Definition: acl.h:137
#define ACL_UPDATE_CHR
Definition: acl.h:139
#define ACL_ALL_RIGHTS_FUNCTION
Definition: acl.h:165
#define ACL_N_SIZE(N)
Definition: acl.h:110
#define ACL_ALL_RIGHTS_LANGUAGE
Definition: acl.h:166
#define ACL_ALL_RIGHTS_TYPE
Definition: acl.h:171
#define ACL_ALTER_SYSTEM_CHR
Definition: acl.h:150
#define ACL_ALL_RIGHTS_FDW
Definition: acl.h:163
#define ACLITEM_SET_PRIVS_GOPTIONS(item, privs, goptions)
Definition: acl.h:82
#define ACL_NUM(ACL)
Definition: acl.h:108
#define ACL_USAGE_CHR
Definition: acl.h:145
#define PG_GETARG_ACL_P(n)
Definition: acl.h:122
#define ACLITEM_GET_GOPTIONS(item)
Definition: acl.h:67
#define ACLITEM_GET_RIGHTS(item)
Definition: acl.h:68
#define ACL_ALL_RIGHTS_RELATION
Definition: acl.h:160
#define ACL_MODECHG_EQL
Definition: acl.h:131
#define ACL_ID_PUBLIC
Definition: acl.h:46
#define ACL_CONNECT_CHR
Definition: acl.h:148
#define ACL_ALL_RIGHTS_LARGEOBJECT
Definition: acl.h:167
AclMaskHow
Definition: acl.h:175
@ ACLMASK_ANY
Definition: acl.h:177
@ ACLMASK_ALL
Definition: acl.h:176
#define PG_RETURN_ACL_P(x)
Definition: acl.h:124
#define ACL_TRIGGER_CHR
Definition: acl.h:143
#define ACL_CREATE_TEMP_CHR
Definition: acl.h:147
#define ACL_GRANT_OPTION_FOR(privs)
Definition: acl.h:70
#define ACLITEM_SET_RIGHTS(item, rights)
Definition: acl.h:79
#define ACL_MAINTAIN_CHR
Definition: acl.h:151
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3844
AclResult pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, Snapshot snapshot)
Definition: aclchk.c:4074
AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:4047
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3919
AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
Definition: aclchk.c:3908
AclResult pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
Definition: aclchk.c:4062
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3834
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3878
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4037
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
#define ARR_LBOUND(a)
Definition: array.h:296
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
void bloom_free(bloom_filter *filter)
Definition: bloomfilter.c:126
bloom_filter * bloom_create(int64 total_elems, int bloom_work_mem, uint64 seed)
Definition: bloomfilter.c:87
bool bloom_lacks_element(bloom_filter *filter, unsigned char *elem, size_t len)
Definition: bloomfilter.c:157
void bloom_add_element(bloom_filter *filter, unsigned char *elem, size_t len)
Definition: bloomfilter.c:135
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:752
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1155
uint64_t uint64
Definition: c.h:540
uint32_t uint32
Definition: c.h:539
#define UINT64CONST(x)
Definition: c.h:554
#define OidIsValid(objectId)
Definition: c.h:775
size_t Size
Definition: c.h:611
bool IsReservedName(const char *name)
Definition: catalog.c:278
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3167
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1234
int errdetail(const char *fmt,...)
Definition: elog.c:1207
int errhint(const char *fmt,...)
Definition: elog.c:1321
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereturn(context, dummy_value,...)
Definition: elog.h:278
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2260
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_UINT32(x)
Definition: fmgr.h:355
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_GETARG_CHAR(n)
Definition: fmgr.h:273
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define PG_GETARG_INT16(n)
Definition: fmgr.h:271
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:705
Oid get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok)
Definition: foreign.c:682
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
int work_mem
Definition: globals.c:131
Oid MyDatabaseId
Definition: globals.c:94
static Datum hash_uint32_extended(uint32 k, uint64 seed)
Definition: hashfn.h:49
Assert(PointerIsAligned(start, uint64))
static const FormData_pg_attribute a1
Definition: heap.c:144
static const FormData_pg_attribute a2
Definition: heap.c:157
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define funcname
Definition: indent_codes.h:69
int remaining
Definition: informix.c:692
static char * username
Definition: initdb.c:153
#define read(a, b, c)
Definition: win32.h:13
bool lo_compat_privileges
Definition: inv_api.c:56
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1812
int a
Definition: isn.c:73
int j
Definition: isn.c:78
int i
Definition: isn.c:77
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void list_free(List *list)
Definition: list.c:1546
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
#define NoLock
Definition: lockdefs.h:34
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2170
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
MemoryContext TopMemoryContext
Definition: mcxt.c:166
void * palloc(Size size)
Definition: mcxt.c:1365
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:476
Oid GetUserId(void)
Definition: miscinit.c:469
Oid GetSessionUserId(void)
Definition: miscinit.c:508
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:988
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3602
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3621
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:98
int oid_cmp(const void *p1, const void *p2)
Definition: oid.c:258
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
@ ROLESPEC_CURRENT_USER
Definition: parsenodes.h:420
@ ROLESPEC_CSTRING
Definition: parsenodes.h:418
@ ROLESPEC_SESSION_USER
Definition: parsenodes.h:421
@ ROLESPEC_CURRENT_ROLE
Definition: parsenodes.h:419
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:422
#define ACL_CREATE_TEMP
Definition: parsenodes.h:86
#define ACL_SET
Definition: parsenodes.h:88
#define ACL_DELETE
Definition: parsenodes.h:79
uint64 AclMode
Definition: parsenodes.h:74
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define ACL_INSERT
Definition: parsenodes.h:76
#define ACL_NO_RIGHTS
Definition: parsenodes.h:92
#define ACL_UPDATE
Definition: parsenodes.h:78
DropBehavior
Definition: parsenodes.h:2394
@ DROP_CASCADE
Definition: parsenodes.h:2396
@ DROP_RESTRICT
Definition: parsenodes.h:2395
ObjectType
Definition: parsenodes.h:2321
@ OBJECT_FDW
Definition: parsenodes.h:2338
@ OBJECT_SCHEMA
Definition: parsenodes.h:2358
@ OBJECT_DOMAIN
Definition: parsenodes.h:2334
@ OBJECT_COLUMN
Definition: parsenodes.h:2328
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2364
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2344
@ OBJECT_DATABASE
Definition: parsenodes.h:2331
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2359
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2343
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2339
@ OBJECT_TABLE
Definition: parsenodes.h:2363
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2349
@ OBJECT_TYPE
Definition: parsenodes.h:2371
@ OBJECT_FUNCTION
Definition: parsenodes.h:2341
#define ACL_CONNECT
Definition: parsenodes.h:87
#define ACL_ALTER_SYSTEM
Definition: parsenodes.h:89
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define ACL_SELECT
Definition: parsenodes.h:77
#define ACL_TRUNCATE
Definition: parsenodes.h:80
#define ACL_EXECUTE
Definition: parsenodes.h:83
#define ACL_CREATE
Definition: parsenodes.h:85
#define ACL_TRIGGER
Definition: parsenodes.h:82
#define N_ACL_RIGHTS
Definition: parsenodes.h:91
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
FormData_pg_auth_members * Form_pg_auth_members
NameData rolname
Definition: pg_authid.h:34
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
void * arg
int pg_popcount64(uint64 word)
Definition: pg_bitutils.c:515
static PgChecksumMode mode
Definition: pg_checksums.c:55
#define NAMEDATALEN
const void size_t len
FormData_pg_database * Form_pg_database
Definition: pg_database.h:96
bool LargeObjectExistsWithSnapshot(Oid loid, Snapshot snapshot)
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define list_make1_oid(x1)
Definition: pg_list.h:242
#define foreach_oid(var, lst)
Definition: pg_list.h:471
#define lfirst_oid(lc)
Definition: pg_list.h:174
NameData typname
Definition: pg_type.h:41
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define sprintf
Definition: port.h:241
#define qsort(a, b, c, d)
Definition: port.h:479
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:252
static Datum UInt64GetDatum(uint64 X)
Definition: postgres.h:423
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
char * c
Oid get_language_oid(const char *langname, bool missing_ok)
Definition: proclang.c:226
static size_t qunique(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *))
Definition: qunique.h:21
Datum regtypein(PG_FUNCTION_ARGS)
Definition: regproc.c:1184
Datum regprocedurein(PG_FUNCTION_ARGS)
Definition: regproc.c:229
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:798
char * dbname
Definition: streamutil.c:49
Definition: acl.h:55
Oid ai_grantee
Definition: acl.h:56
AclMode ai_privs
Definition: acl.h:58
Oid ai_grantor
Definition: acl.h:57
Oid elemtype
Definition: array.h:97
int ndim
Definition: array.h:95
int32 dataoffset
Definition: array.h:96
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
Definition: pg_list.h:54
Definition: nodes.h:135
RoleSpecType roletype
Definition: parsenodes.h:428
char * rolename
Definition: parsenodes.h:429
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:185
int n_members
Definition: catcache.h:183
HeapTupleData tuple
Definition: catcache.h:124
Definition: c.h:747
Definition: acl.c:55
const char * name
Definition: acl.c:56
AclMode value
Definition: acl.c:57
Definition: c.h:693
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:230
#define ReleaseSysCacheList(x)
Definition: syscache.h:134
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:127
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:118
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:109
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:182
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:842
static void SET_VARSIZE(void *PTR, Size len)
Definition: varatt.h:432
char * text_to_cstring(const text *t)
Definition: varlena.c:214
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:2686
const char * type
const char * name