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