1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/acl.c
13 *-------------------------------------------------------------------------
19 #include "catalog/namespace.h"
20 #include "catalog/pg_authid.h"
21 #include "catalog/pg_auth_members.h"
22 #include "catalog/pg_type.h"
23 #include "catalog/pg_class.h"
24 #include "commands/dbcommands.h"
25 #include "commands/proclang.h"
26 #include "commands/tablespace.h"
27 #include "foreign/foreign.h"
29 #include "miscadmin.h"
30 #include "utils/acl.h"
31 #include "utils/builtins.h"
32 #include "utils/inval.h"
33 #include "utils/lsyscache.h"
34 #include "utils/memutils.h"
35 #include "utils/syscache.h"
45 * We frequently need to test whether a given role is a member of some other
46 * role. In most of these tests the "given role" is the same, namely the
47 * active current user. So we can optimize it by keeping a cached list of
48 * all the roles the "given role" is a member of, directly or indirectly.
49 * The cache is flushed whenever we detect a change in pg_auth_members.
51 * There are actually two caches, one computed under "has_privs" rules
52 * (do not recurse where rolinherit isn't true) and one computed under
53 * "is_member" rules (recurse regardless of rolinherit).
55 * Possibly this mechanism should be generalized to allow caching membership
56 * info for multiple roles?
58 * The has_privs cache is:
59 * cached_privs_role is the role OID the cache is for.
60 * cached_privs_roles is an OID list of roles that cached_privs_role
61 * has the privileges of (always including itself).
62 * The cache is valid if cached_privs_role is not InvalidOid.
64 * The is_member cache is similarly:
65 * cached_member_role is the role OID the cache is for.
66 * cached_membership_roles is an OID list of roles that cached_member_role
67 * is a member of (always including itself).
68 * The cache is valid if cached_member_role is not InvalidOid.
70 static Oid cached_privs_role = InvalidOid;
71 static List *cached_privs_roles = NIL;
72 static Oid cached_member_role = InvalidOid;
73 static List *cached_membership_roles = NIL;
76 static const char *getid(const char *s, char *n);
77 static void putid(char *p, const char *s);
78 static Acl *allocacl(int n);
79 static void check_acl(const Acl *acl);
80 static const char *aclparse(const char *s, AclItem *aip);
81 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
82 static int aclitemComparator(const void *arg1, const void *arg2);
83 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
85 static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
86 Oid ownerId, DropBehavior behavior);
87 static int oidComparator(const void *arg1, const void *arg2);
89 static AclMode convert_priv_string(text *priv_type_text);
90 static AclMode convert_any_priv_string(text *priv_type_text,
91 const priv_map *privileges);
93 static Oid convert_table_name(text *tablename);
94 static AclMode convert_table_priv_string(text *priv_type_text);
95 static AclMode convert_sequence_priv_string(text *priv_type_text);
96 static AttrNumber convert_column_name(Oid tableoid, text *column);
97 static AclMode convert_column_priv_string(text *priv_type_text);
98 static Oid convert_database_name(text *databasename);
99 static AclMode convert_database_priv_string(text *priv_type_text);
100 static Oid convert_foreign_data_wrapper_name(text *fdwname);
101 static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text);
102 static Oid convert_function_name(text *functionname);
103 static AclMode convert_function_priv_string(text *priv_type_text);
104 static Oid convert_language_name(text *languagename);
105 static AclMode convert_language_priv_string(text *priv_type_text);
106 static Oid convert_schema_name(text *schemaname);
107 static AclMode convert_schema_priv_string(text *priv_type_text);
108 static Oid convert_server_name(text *servername);
109 static AclMode convert_server_priv_string(text *priv_type_text);
110 static Oid convert_tablespace_name(text *tablespacename);
111 static AclMode convert_tablespace_priv_string(text *priv_type_text);
112 static AclMode convert_role_priv_string(text *priv_type_text);
113 static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
115 static void RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
116 static Oid get_role_oid_or_public(const char *rolname);
121 * Consumes the first alphanumeric string (identifier) found in string
122 * 's', ignoring any leading white space. If it finds a double quote
123 * it returns the word inside the quotes.
126 * the string position in 's' that points to the next non-space character
127 * in 's', after any quotes. Also:
128 * - loads the identifier into 'n'. (If no identifier is found, 'n'
129 * contains an empty string.) 'n' must be NAMEDATALEN bytes.
132 getid(const char *s, char *n)
135 bool in_quotes = false;
139 while (isspace((unsigned char) *s))
141 /* This code had better match what putid() does, below */
144 (isalnum((unsigned char) *s) ||
152 /* safe to look at next char (could be '\0' though) */
155 in_quotes = !in_quotes;
158 /* it's an escaped double quote; skip the escaping char */
162 /* Add the character to the string */
163 if (len >= NAMEDATALEN - 1)
165 (errcode(ERRCODE_NAME_TOO_LONG),
166 errmsg("identifier too long"),
167 errdetail("Identifier must be less than %d characters.",
173 while (isspace((unsigned char) *s))
179 * Write a role name at *p, adding double quotes if needed.
180 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
181 * This needs to be kept in sync with copyAclUserName in pg_dump/dumputils.c
184 putid(char *p, const char *s)
189 for (src = s; *src; src++)
191 /* This test had better match what getid() does, above */
192 if (!isalnum((unsigned char) *src) && *src != '_')
200 for (src = s; *src; src++)
202 /* A double quote character in a username is encoded as "" */
214 * Consumes and parses an ACL specification of the form:
215 * [group|user] [A-Za-z0-9]*=[rwaR]*
216 * from string 's', ignoring any leading white space or white space
217 * between the optional id type keyword (group|user) and the actual
220 * The group|user decoration is unnecessary in the roles world,
221 * but we still accept it for backward compatibility.
223 * This routine is called by the parser as well as aclitemin(), hence
224 * the added generality.
227 * the string position in 's' immediately following the ACL
228 * specification. Also:
229 * - loads the structure pointed to by 'aip' with the appropriate
230 * UID/GID, id type identifier and mode type values.
233 aclparse(const char *s, AclItem *aip)
238 char name[NAMEDATALEN];
239 char name2[NAMEDATALEN];
244 elog(LOG, "aclparse: input = \"%s\"", s);
249 /* we just read a keyword, not a name */
250 if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
252 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
253 errmsg("unrecognized key word: \"%s\"", name),
254 errhint("ACL key word must be \"group\" or \"user\".")));
255 s = getid(s, name); /* move s to the name beyond the keyword */
258 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
259 errmsg("missing name"),
260 errhint("A name must follow the \"group\" or \"user\" key word.")));
265 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
266 errmsg("missing \"=\" sign")));
268 privs = goption = ACL_NO_RIGHTS;
270 for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
289 case ACL_TRUNCATE_CHR:
292 case ACL_REFERENCES_CHR:
293 read = ACL_REFERENCES;
295 case ACL_TRIGGER_CHR:
298 case ACL_EXECUTE_CHR:
307 case ACL_CREATE_TEMP_CHR:
308 read = ACL_CREATE_TEMP;
310 case ACL_CONNECT_CHR:
313 case 'R': /* ignore old RULE privileges */
318 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
319 errmsg("invalid mode character: must be one of \"%s\"",
320 ACL_ALL_RIGHTS_STR)));
327 aip->ai_grantee = ACL_ID_PUBLIC;
329 aip->ai_grantee = get_role_oid(name, false);
332 * XXX Allow a degree of backward compatibility by defaulting the grantor
337 s = getid(s + 1, name2);
338 if (name2[0] == '\0')
340 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
341 errmsg("a name must follow the \"/\" sign")));
342 aip->ai_grantor = get_role_oid(name2, false);
346 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
348 (errcode(ERRCODE_INVALID_GRANTOR),
349 errmsg("defaulting grantor to user ID %u",
350 BOOTSTRAP_SUPERUSERID)));
353 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
356 elog(LOG, "aclparse: correctly read [%u %x %x]",
357 aip->ai_grantee, privs, goption);
365 * Allocates storage for a new Acl with 'n' entries.
377 elog(ERROR, "invalid size: %d", n);
378 size = ACL_N_SIZE(n);
379 new_acl = (Acl *) palloc0(size);
380 SET_VARSIZE(new_acl, size);
382 new_acl->dataoffset = 0; /* we never put in any nulls */
383 new_acl->elemtype = ACLITEMOID;
384 ARR_LBOUND(new_acl)[0] = 1;
385 ARR_DIMS(new_acl)[0] = n;
390 * Create a zero-entry ACL
402 aclcopy(const Acl *orig_acl)
406 result_acl = allocacl(ACL_NUM(orig_acl));
408 memcpy(ACL_DAT(result_acl),
410 ACL_NUM(orig_acl) * sizeof(AclItem));
416 * Concatenate two ACLs
418 * This is a bit cheesy, since we may produce an ACL with redundant entries.
419 * Be careful what the result is used for!
422 aclconcat(const Acl *left_acl, const Acl *right_acl)
426 result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
428 memcpy(ACL_DAT(result_acl),
430 ACL_NUM(left_acl) * sizeof(AclItem));
432 memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
434 ACL_NUM(right_acl) * sizeof(AclItem));
442 * This produces a properly merged ACL with no redundant entries.
443 * Returns NULL on NULL input.
446 aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
453 /* Check for cases where one or both are empty/null */
454 if (left_acl == NULL || ACL_NUM(left_acl) == 0)
456 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
459 return aclcopy(right_acl);
463 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
464 return aclcopy(left_acl);
467 /* Merge them the hard way, one item at a time */
468 result_acl = aclcopy(left_acl);
470 aip = ACL_DAT(right_acl);
471 num = ACL_NUM(right_acl);
473 for (i = 0; i < num; i++, aip++)
477 tmp_acl = aclupdate(result_acl, aip, ACL_MODECHG_ADD,
478 ownerId, DROP_RESTRICT);
480 result_acl = tmp_acl;
487 * Sort the items in an ACL (into an arbitrary but consistent order)
490 aclitemsort(Acl *acl)
492 if (acl != NULL && ACL_NUM(acl) > 1)
493 qsort(ACL_DAT(acl), ACL_NUM(acl), sizeof(AclItem), aclitemComparator);
497 * Check if two ACLs are exactly equal
499 * This will not detect equality if the two arrays contain the same items
500 * in different orders. To handle that case, sort both inputs first,
501 * using aclitemsort().
504 aclequal(const Acl *left_acl, const Acl *right_acl)
506 /* Check for cases where one or both are empty/null */
507 if (left_acl == NULL || ACL_NUM(left_acl) == 0)
509 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
516 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
520 if (ACL_NUM(left_acl) != ACL_NUM(right_acl))
523 if (memcmp(ACL_DAT(left_acl),
525 ACL_NUM(left_acl) * sizeof(AclItem)) == 0)
532 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
535 check_acl(const Acl *acl)
537 if (ARR_ELEMTYPE(acl) != ACLITEMOID)
539 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
540 errmsg("ACL array contains wrong data type")));
541 if (ARR_NDIM(acl) != 1)
543 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
544 errmsg("ACL arrays must be one-dimensional")));
545 if (ARR_HASNULL(acl))
547 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
548 errmsg("ACL arrays must not contain null values")));
553 * Allocates storage for, and fills in, a new AclItem given a string
554 * 's' that contains an ACL specification. See aclparse for details.
560 aclitemin(PG_FUNCTION_ARGS)
562 const char *s = PG_GETARG_CSTRING(0);
565 aip = (AclItem *) palloc(sizeof(AclItem));
566 s = aclparse(s, aip);
567 while (isspace((unsigned char) *s))
571 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
572 errmsg("extra garbage at the end of the ACL specification")));
574 PG_RETURN_ACLITEM_P(aip);
579 * Allocates storage for, and fills in, a new null-delimited string
580 * containing a formatted ACL specification. See aclparse for details.
586 aclitemout(PG_FUNCTION_ARGS)
588 AclItem *aip = PG_GETARG_ACLITEM_P(0);
594 out = palloc(strlen("=/") +
596 2 * (2 * NAMEDATALEN + 2) +
602 if (aip->ai_grantee != ACL_ID_PUBLIC)
604 htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantee));
605 if (HeapTupleIsValid(htup))
607 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
608 ReleaseSysCache(htup);
612 /* Generate numeric OID if we don't find an entry */
613 sprintf(p, "%u", aip->ai_grantee);
621 for (i = 0; i < N_ACL_RIGHTS; ++i)
623 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
624 *p++ = ACL_ALL_RIGHTS_STR[i];
625 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
632 htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantor));
633 if (HeapTupleIsValid(htup))
635 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
636 ReleaseSysCache(htup);
640 /* Generate numeric OID if we don't find an entry */
641 sprintf(p, "%u", aip->ai_grantor);
644 PG_RETURN_CSTRING(out);
649 * Two AclItems are considered to match iff they have the same
650 * grantee and grantor; the privileges are ignored.
653 aclitem_match(const AclItem *a1, const AclItem *a2)
655 return a1->ai_grantee == a2->ai_grantee &&
656 a1->ai_grantor == a2->ai_grantor;
661 * qsort comparison function for AclItems
664 aclitemComparator(const void *arg1, const void *arg2)
666 const AclItem *a1 = (const AclItem *) arg1;
667 const AclItem *a2 = (const AclItem *) arg2;
669 if (a1->ai_grantee > a2->ai_grantee)
671 if (a1->ai_grantee < a2->ai_grantee)
673 if (a1->ai_grantor > a2->ai_grantor)
675 if (a1->ai_grantor < a2->ai_grantor)
677 if (a1->ai_privs > a2->ai_privs)
679 if (a1->ai_privs < a2->ai_privs)
685 * aclitem equality operator
688 aclitem_eq(PG_FUNCTION_ARGS)
690 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
691 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
694 result = a1->ai_privs == a2->ai_privs &&
695 a1->ai_grantee == a2->ai_grantee &&
696 a1->ai_grantor == a2->ai_grantor;
697 PG_RETURN_BOOL(result);
701 * aclitem hash function
703 * We make aclitems hashable not so much because anyone is likely to hash
704 * them, as because we want array equality to work on aclitem arrays, and
705 * with the typcache mechanism we must have a hash or btree opclass.
708 hash_aclitem(PG_FUNCTION_ARGS)
710 AclItem *a = PG_GETARG_ACLITEM_P(0);
712 /* not very bright, but avoids any issue of padding in struct */
713 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
718 * acldefault() --- create an ACL describing default access permissions
720 * Change this routine if you want to alter the default access policy for
721 * newly-created objects (or any object with a NULL acl entry).
723 * Note that these are the hard-wired "defaults" that are used in the
724 * absence of any pg_default_acl entry.
727 acldefault(GrantObjectType objtype, Oid ownerId)
729 AclMode world_default;
730 AclMode owner_default;
737 case ACL_OBJECT_COLUMN:
738 /* by default, columns have no extra privileges */
739 world_default = ACL_NO_RIGHTS;
740 owner_default = ACL_NO_RIGHTS;
742 case ACL_OBJECT_RELATION:
743 world_default = ACL_NO_RIGHTS;
744 owner_default = ACL_ALL_RIGHTS_RELATION;
746 case ACL_OBJECT_SEQUENCE:
747 world_default = ACL_NO_RIGHTS;
748 owner_default = ACL_ALL_RIGHTS_SEQUENCE;
750 case ACL_OBJECT_DATABASE:
751 /* for backwards compatibility, grant some rights by default */
752 world_default = ACL_CREATE_TEMP | ACL_CONNECT;
753 owner_default = ACL_ALL_RIGHTS_DATABASE;
755 case ACL_OBJECT_FUNCTION:
756 /* Grant EXECUTE by default, for now */
757 world_default = ACL_EXECUTE;
758 owner_default = ACL_ALL_RIGHTS_FUNCTION;
760 case ACL_OBJECT_LANGUAGE:
761 /* Grant USAGE by default, for now */
762 world_default = ACL_USAGE;
763 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
765 case ACL_OBJECT_LARGEOBJECT:
766 world_default = ACL_NO_RIGHTS;
767 owner_default = ACL_ALL_RIGHTS_LARGEOBJECT;
769 case ACL_OBJECT_NAMESPACE:
770 world_default = ACL_NO_RIGHTS;
771 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
773 case ACL_OBJECT_TABLESPACE:
774 world_default = ACL_NO_RIGHTS;
775 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
778 world_default = ACL_NO_RIGHTS;
779 owner_default = ACL_ALL_RIGHTS_FDW;
781 case ACL_OBJECT_FOREIGN_SERVER:
782 world_default = ACL_NO_RIGHTS;
783 owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
786 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
787 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
788 owner_default = ACL_NO_RIGHTS;
793 if (world_default != ACL_NO_RIGHTS)
795 if (owner_default != ACL_NO_RIGHTS)
798 acl = allocacl(nacl);
801 if (world_default != ACL_NO_RIGHTS)
803 aip->ai_grantee = ACL_ID_PUBLIC;
804 aip->ai_grantor = ownerId;
805 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
810 * Note that the owner's entry shows all ordinary privileges but no grant
811 * options. This is because his grant options come "from the system" and
812 * not from his own efforts. (The SQL spec says that the owner's rights
813 * come from a "_SYSTEM" authid.) However, we do consider that the
814 * owner's ordinary privileges are self-granted; this lets him revoke
815 * them. We implement the owner's grant options without any explicit
816 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
817 * whereever we are testing grant options.
819 if (owner_default != ACL_NO_RIGHTS)
821 aip->ai_grantee = ownerId;
822 aip->ai_grantor = ownerId;
823 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
831 * Update an ACL array to add or remove specified privileges.
833 * old_acl: the input ACL array
834 * mod_aip: defines the privileges to be added, removed, or substituted
835 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
836 * ownerId: Oid of object owner
837 * behavior: RESTRICT or CASCADE behavior for recursive removal
839 * ownerid and behavior are only relevant when the update operation specifies
840 * deletion of grant options.
842 * The result is a modified copy; the input object is not changed.
844 * NB: caller is responsible for having detoasted the input ACL, if needed.
847 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
848 int modechg, Oid ownerId, DropBehavior behavior)
860 /* Caller probably already checked old_acl, but be safe */
863 /* If granting grant options, check for circularity */
864 if (modechg != ACL_MODECHG_DEL &&
865 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
866 check_circularity(old_acl, mod_aip, ownerId);
868 num = ACL_NUM(old_acl);
869 old_aip = ACL_DAT(old_acl);
872 * Search the ACL for an existing entry for this grantee and grantor. If
873 * one exists, just modify the entry in-place (well, in the same position,
874 * since we actually return a copy); otherwise, insert the new entry at
878 for (dst = 0; dst < num; ++dst)
880 if (aclitem_match(mod_aip, old_aip + dst))
882 /* found a match, so modify existing item */
883 new_acl = allocacl(num);
884 new_aip = ACL_DAT(new_acl);
885 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
892 /* need to append a new item */
893 new_acl = allocacl(num + 1);
894 new_aip = ACL_DAT(new_acl);
895 memcpy(new_aip, old_aip, num * sizeof(AclItem));
897 /* initialize the new entry with no permissions */
898 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
899 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
900 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
901 ACL_NO_RIGHTS, ACL_NO_RIGHTS);
902 num++; /* set num to the size of new_acl */
905 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
906 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
908 /* apply the specified permissions change */
911 case ACL_MODECHG_ADD:
912 ACLITEM_SET_RIGHTS(new_aip[dst],
913 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
915 case ACL_MODECHG_DEL:
916 ACLITEM_SET_RIGHTS(new_aip[dst],
917 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
919 case ACL_MODECHG_EQL:
920 ACLITEM_SET_RIGHTS(new_aip[dst],
921 ACLITEM_GET_RIGHTS(*mod_aip));
925 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
926 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
929 * If the adjusted entry has no permissions, delete it from the list.
931 if (new_rights == ACL_NO_RIGHTS)
933 memmove(new_aip + dst,
935 (num - dst - 1) * sizeof(AclItem));
936 /* Adjust array size to be 'num - 1' items */
937 ARR_DIMS(new_acl)[0] = num - 1;
938 SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
942 * Remove abandoned privileges (cascading revoke). Currently we can only
943 * handle this when the grantee is not PUBLIC.
945 if ((old_goptions & ~new_goptions) != 0)
947 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
948 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
949 (old_goptions & ~new_goptions),
957 * Update an ACL array to reflect a change of owner to the parent object
959 * old_acl: the input ACL array (must not be NULL)
960 * oldOwnerId: Oid of the old object owner
961 * newOwnerId: Oid of the new object owner
963 * The result is a modified copy; the input object is not changed.
965 * NB: caller is responsible for having detoasted the input ACL, if needed.
968 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
976 bool newpresent = false;
985 * Make a copy of the given ACL, substituting new owner ID for old
986 * wherever it appears as either grantor or grantee. Also note if the new
987 * owner ID is already present.
989 num = ACL_NUM(old_acl);
990 old_aip = ACL_DAT(old_acl);
991 new_acl = allocacl(num);
992 new_aip = ACL_DAT(new_acl);
993 memcpy(new_aip, old_aip, num * sizeof(AclItem));
994 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
996 if (dst_aip->ai_grantor == oldOwnerId)
997 dst_aip->ai_grantor = newOwnerId;
998 else if (dst_aip->ai_grantor == newOwnerId)
1000 if (dst_aip->ai_grantee == oldOwnerId)
1001 dst_aip->ai_grantee = newOwnerId;
1002 else if (dst_aip->ai_grantee == newOwnerId)
1007 * If the old ACL contained any references to the new owner, then we may
1008 * now have generated an ACL containing duplicate entries. Find them and
1009 * merge them so that there are not duplicates. (This is relatively
1010 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
1011 * be the normal case.)
1013 * To simplify deletion of duplicate entries, we temporarily leave them in
1014 * the array but set their privilege masks to zero; when we reach such an
1015 * entry it's just skipped. (Thus, a side effect of this code will be to
1016 * remove privilege-free entries, should there be any in the input.) dst
1017 * is the next output slot, targ is the currently considered input slot
1018 * (always >= dst), and src scans entries to the right of targ looking for
1019 * duplicates. Once an entry has been emitted to dst it is known
1020 * duplicate-free and need not be considered anymore.
1025 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
1027 /* ignore if deleted in an earlier pass */
1028 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
1030 /* find and merge any duplicates */
1031 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
1034 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
1036 if (aclitem_match(targ_aip, src_aip))
1038 ACLITEM_SET_RIGHTS(*targ_aip,
1039 ACLITEM_GET_RIGHTS(*targ_aip) |
1040 ACLITEM_GET_RIGHTS(*src_aip));
1041 /* mark the duplicate deleted */
1042 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
1045 /* and emit to output */
1046 new_aip[dst] = *targ_aip;
1049 /* Adjust array size to be 'dst' items */
1050 ARR_DIMS(new_acl)[0] = dst;
1051 SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
1059 * When granting grant options, we must disallow attempts to set up circular
1060 * chains of grant options. Suppose A (the object owner) grants B some
1061 * privileges with grant option, and B re-grants them to C. If C could
1062 * grant the privileges to B as well, then A would be unable to effectively
1063 * revoke the privileges from B, since recursive_revoke would consider that
1064 * B still has 'em from C.
1066 * We check for this by recursively deleting all grant options belonging to
1067 * the target grantee, and then seeing if the would-be grantor still has the
1068 * grant option or not.
1071 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
1083 * For now, grant options can only be granted to roles, not PUBLIC.
1084 * Otherwise we'd have to work a bit harder here.
1086 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
1088 /* The owner always has grant options, no need to check */
1089 if (mod_aip->ai_grantor == ownerId)
1092 /* Make a working copy */
1093 acl = allocacl(ACL_NUM(old_acl));
1094 memcpy(acl, old_acl, ACL_SIZE(old_acl));
1096 /* Zap all grant options of target grantee, plus what depends on 'em */
1100 for (i = 0; i < num; i++)
1102 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
1103 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
1107 /* We'll actually zap ordinary privs too, but no matter */
1108 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
1109 ownerId, DROP_CASCADE);
1118 /* Now we can compute grantor's independently-derived privileges */
1119 own_privs = aclmask(acl,
1120 mod_aip->ai_grantor,
1122 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
1124 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
1126 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
1128 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1129 errmsg("grant options cannot be granted back to your own grantor")));
1136 * Ensure that no privilege is "abandoned". A privilege is abandoned
1137 * if the user that granted the privilege loses the grant option. (So
1138 * the chain through which it was granted is broken.) Either the
1139 * abandoned privileges are revoked as well, or an error message is
1140 * printed, depending on the drop behavior option.
1142 * acl: the input ACL list
1143 * grantee: the user from whom some grant options have been revoked
1144 * revoke_privs: the grant options being revoked
1145 * ownerId: Oid of object owner
1146 * behavior: RESTRICT or CASCADE behavior for recursive removal
1148 * The input Acl object is pfree'd if replaced.
1151 recursive_revoke(Acl *acl,
1153 AclMode revoke_privs,
1155 DropBehavior behavior)
1164 /* The owner can never truly lose grant options, so short-circuit */
1165 if (grantee == ownerId)
1168 /* The grantee might still have the privileges via another grantor */
1169 still_has = aclmask(acl, grantee, ownerId,
1170 ACL_GRANT_OPTION_FOR(revoke_privs),
1172 revoke_privs &= ~still_has;
1173 if (revoke_privs == ACL_NO_RIGHTS)
1179 for (i = 0; i < num; i++)
1181 if (aip[i].ai_grantor == grantee
1182 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1187 if (behavior == DROP_RESTRICT)
1189 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1190 errmsg("dependent privileges exist"),
1191 errhint("Use CASCADE to revoke them too.")));
1193 mod_acl.ai_grantor = grantee;
1194 mod_acl.ai_grantee = aip[i].ai_grantee;
1195 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
1199 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1214 * aclmask --- compute bitmask of all privileges held by roleid.
1216 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1217 * held by the given roleid according to the given ACL list, ANDed
1218 * with 'mask'. (The point of passing 'mask' is to let the routine
1219 * exit early if all privileges of interest have been found.)
1221 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1222 * is known true. (This lets us exit soonest in cases where the
1223 * caller is only going to test for zero or nonzero result.)
1227 * To see if any of a set of privileges are held:
1228 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1230 * To see if all of a set of privileges are held:
1231 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1233 * To determine exactly which of a set of privileges are held:
1234 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1237 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1238 AclMode mask, AclMaskHow how)
1247 * Null ACL should not happen, since caller should have inserted
1248 * appropriate default
1251 elog(ERROR, "null ACL");
1255 /* Quick exit for mask == 0 */
1261 /* Owner always implicitly has all grant options */
1262 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1263 has_privs_of_role(roleid, ownerId))
1265 result = mask & ACLITEM_ALL_GOPTION_BITS;
1266 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1271 aidat = ACL_DAT(acl);
1274 * Check privileges granted directly to roleid or to public
1276 for (i = 0; i < num; i++)
1278 AclItem *aidata = &aidat[i];
1280 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1281 aidata->ai_grantee == roleid)
1283 result |= aidata->ai_privs & mask;
1284 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1290 * Check privileges granted indirectly via role memberships. We do this in
1291 * a separate pass to minimize expensive indirect membership tests. In
1292 * particular, it's worth testing whether a given ACL entry grants any
1293 * privileges still of interest before we perform the has_privs_of_role
1296 remaining = mask & ~result;
1297 for (i = 0; i < num; i++)
1299 AclItem *aidata = &aidat[i];
1301 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1302 aidata->ai_grantee == roleid)
1303 continue; /* already checked it */
1305 if ((aidata->ai_privs & remaining) &&
1306 has_privs_of_role(roleid, aidata->ai_grantee))
1308 result |= aidata->ai_privs & mask;
1309 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1311 remaining = mask & ~result;
1320 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1322 * This is exactly like aclmask() except that we consider only privileges
1323 * held *directly* by roleid, not those inherited via role membership.
1326 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1327 AclMode mask, AclMaskHow how)
1335 * Null ACL should not happen, since caller should have inserted
1336 * appropriate default
1339 elog(ERROR, "null ACL");
1343 /* Quick exit for mask == 0 */
1349 /* Owner always implicitly has all grant options */
1350 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1353 result = mask & ACLITEM_ALL_GOPTION_BITS;
1354 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1359 aidat = ACL_DAT(acl);
1362 * Check privileges granted directly to roleid (and not to public)
1364 for (i = 0; i < num; i++)
1366 AclItem *aidata = &aidat[i];
1368 if (aidata->ai_grantee == roleid)
1370 result |= aidata->ai_privs & mask;
1371 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1382 * Find out all the roleids mentioned in an Acl.
1383 * Note that we do not distinguish grantors from grantees.
1385 * *roleids is set to point to a palloc'd array containing distinct OIDs
1386 * in sorted order. The length of the array is the function result.
1389 aclmembers(const Acl *acl, Oid **roleids)
1392 const AclItem *acldat;
1397 if (acl == NULL || ACL_NUM(acl) == 0)
1405 /* Allocate the worst-case space requirement */
1406 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1407 acldat = ACL_DAT(acl);
1410 * Walk the ACL collecting mentioned RoleIds.
1413 for (i = 0; i < ACL_NUM(acl); i++)
1415 const AclItem *ai = &acldat[i];
1417 if (ai->ai_grantee != ACL_ID_PUBLIC)
1418 list[j++] = ai->ai_grantee;
1419 /* grantor is currently never PUBLIC, but let's check anyway */
1420 if (ai->ai_grantor != ACL_ID_PUBLIC)
1421 list[j++] = ai->ai_grantor;
1424 /* Sort the array */
1425 qsort(list, j, sizeof(Oid), oidComparator);
1427 /* Remove duplicates from the array */
1429 for (i = 1; i < j; i++)
1431 if (list[k] != list[i])
1432 list[++k] = list[i];
1436 * We could repalloc the array down to minimum size, but it's hardly worth
1437 * it since it's only transient memory.
1446 * qsort comparison function for Oids
1449 oidComparator(const void *arg1, const void *arg2)
1451 Oid oid1 = *(const Oid *) arg1;
1452 Oid oid2 = *(const Oid *) arg2;
1463 * aclinsert (exported function)
1466 aclinsert(PG_FUNCTION_ARGS)
1469 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1470 errmsg("aclinsert is no longer supported")));
1472 PG_RETURN_NULL(); /* keep compiler quiet */
1476 aclremove(PG_FUNCTION_ARGS)
1479 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1480 errmsg("aclremove is no longer supported")));
1482 PG_RETURN_NULL(); /* keep compiler quiet */
1486 aclcontains(PG_FUNCTION_ARGS)
1488 Acl *acl = PG_GETARG_ACL_P(0);
1489 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1496 aidat = ACL_DAT(acl);
1497 for (i = 0; i < num; ++i)
1499 if (aip->ai_grantee == aidat[i].ai_grantee &&
1500 aip->ai_grantor == aidat[i].ai_grantor &&
1501 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1502 PG_RETURN_BOOL(true);
1504 PG_RETURN_BOOL(false);
1508 makeaclitem(PG_FUNCTION_ARGS)
1510 Oid grantee = PG_GETARG_OID(0);
1511 Oid grantor = PG_GETARG_OID(1);
1512 text *privtext = PG_GETARG_TEXT_P(2);
1513 bool goption = PG_GETARG_BOOL(3);
1517 priv = convert_priv_string(privtext);
1519 result = (AclItem *) palloc(sizeof(AclItem));
1521 result->ai_grantee = grantee;
1522 result->ai_grantor = grantor;
1524 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1525 (goption ? priv : ACL_NO_RIGHTS));
1527 PG_RETURN_ACLITEM_P(result);
1531 convert_priv_string(text *priv_type_text)
1533 char *priv_type = text_to_cstring(priv_type_text);
1535 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1537 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1539 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1541 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1543 if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
1544 return ACL_TRUNCATE;
1545 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1546 return ACL_REFERENCES;
1547 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1549 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1551 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1553 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1555 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1556 return ACL_CREATE_TEMP;
1557 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1558 return ACL_CREATE_TEMP;
1559 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1561 if (pg_strcasecmp(priv_type, "RULE") == 0)
1562 return 0; /* ignore old RULE privileges */
1565 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1566 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1567 return ACL_NO_RIGHTS; /* keep compiler quiet */
1572 * convert_any_priv_string: recognize privilege strings for has_foo_privilege
1574 * We accept a comma-separated list of case-insensitive privilege names,
1575 * producing a bitmask of the OR'd privilege bits. We are liberal about
1576 * whitespace between items, not so much about whitespace within items.
1577 * The allowed privilege names are given as an array of priv_map structs,
1578 * terminated by one with a NULL name pointer.
1581 convert_any_priv_string(text *priv_type_text,
1582 const priv_map *privileges)
1585 char *priv_type = text_to_cstring(priv_type_text);
1589 /* We rely on priv_type being a private, modifiable string */
1590 for (chunk = priv_type; chunk; chunk = next_chunk)
1593 const priv_map *this_priv;
1595 /* Split string at commas */
1596 next_chunk = strchr(chunk, ',');
1598 *next_chunk++ = '\0';
1600 /* Drop leading/trailing whitespace in this chunk */
1601 while (*chunk && isspace((unsigned char) *chunk))
1603 chunk_len = strlen(chunk);
1604 while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
1606 chunk[chunk_len] = '\0';
1608 /* Match to the privileges list */
1609 for (this_priv = privileges; this_priv->name; this_priv++)
1611 if (pg_strcasecmp(this_priv->name, chunk) == 0)
1613 result |= this_priv->value;
1617 if (!this_priv->name)
1619 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1620 errmsg("unrecognized privilege type: \"%s\"", chunk)));
1629 convert_aclright_to_string(int aclright)
1643 case ACL_REFERENCES:
1644 return "REFERENCES";
1653 case ACL_CREATE_TEMP:
1658 elog(ERROR, "unrecognized aclright: %d", aclright);
1665 * Convert an aclitem[] to a table.
1669 * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
1673 * {{ OID(joe), 0::OID, 'SELECT', false },
1674 * { OID(joe), OID(foo), 'INSERT', true },
1675 * { OID(joe), OID(foo), 'UPDATE', false }}
1679 aclexplode(PG_FUNCTION_ARGS)
1681 Acl *acl = PG_GETARG_ACL_P(0);
1682 FuncCallContext *funcctx;
1686 if (SRF_IS_FIRSTCALL())
1689 MemoryContext oldcontext;
1693 funcctx = SRF_FIRSTCALL_INIT();
1694 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1697 * build tupdesc for result tuples (matches out parameters in pg_proc
1700 tupdesc = CreateTemplateTupleDesc(4, false);
1701 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
1703 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
1705 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
1707 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
1710 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1712 /* allocate memory for user context */
1713 idx = (int *) palloc(sizeof(int[2]));
1714 idx[0] = 0; /* ACL array item index */
1715 idx[1] = -1; /* privilege type counter */
1716 funcctx->user_fctx = (void *) idx;
1718 MemoryContextSwitchTo(oldcontext);
1721 funcctx = SRF_PERCALL_SETUP();
1722 idx = (int *) funcctx->user_fctx;
1723 aidat = ACL_DAT(acl);
1725 /* need test here in case acl has no items */
1726 while (idx[0] < ACL_NUM(acl))
1732 if (idx[1] == N_ACL_RIGHTS)
1736 if (idx[0] >= ACL_NUM(acl)) /* done */
1739 aidata = &aidat[idx[0]];
1740 priv_bit = 1 << idx[1];
1742 if (ACLITEM_GET_PRIVS(*aidata) & priv_bit)
1749 values[0] = ObjectIdGetDatum(aidata->ai_grantor);
1750 values[1] = ObjectIdGetDatum(aidata->ai_grantee);
1751 values[2] = CStringGetTextDatum(convert_aclright_to_string(priv_bit));
1752 values[3] = BoolGetDatum((ACLITEM_GET_GOPTIONS(*aidata) & priv_bit) != 0);
1754 MemSet(nulls, 0, sizeof(nulls));
1756 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1757 result = HeapTupleGetDatum(tuple);
1759 SRF_RETURN_NEXT(funcctx, result);
1763 SRF_RETURN_DONE(funcctx);
1768 * has_table_privilege variants
1769 * These are all named "has_table_privilege" at the SQL level.
1770 * They take various combinations of relation name, relation OID,
1771 * user name, user OID, or implicit user = current_user.
1773 * The result is a boolean value: true if user has the indicated
1774 * privilege, false if not. The variants that take a relation OID
1775 * return NULL if the OID doesn't exist (rather than failing, as
1776 * they did before Postgres 8.4).
1780 * has_table_privilege_name_name
1781 * Check user privileges on a table given
1782 * name username, text tablename, and text priv name.
1785 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1787 Name rolename = PG_GETARG_NAME(0);
1788 text *tablename = PG_GETARG_TEXT_P(1);
1789 text *priv_type_text = PG_GETARG_TEXT_P(2);
1793 AclResult aclresult;
1795 roleid = get_role_oid_or_public(NameStr(*rolename));
1796 tableoid = convert_table_name(tablename);
1797 mode = convert_table_priv_string(priv_type_text);
1799 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1801 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1805 * has_table_privilege_name
1806 * Check user privileges on a table given
1807 * text tablename and text priv name.
1808 * current_user is assumed
1811 has_table_privilege_name(PG_FUNCTION_ARGS)
1813 text *tablename = PG_GETARG_TEXT_P(0);
1814 text *priv_type_text = PG_GETARG_TEXT_P(1);
1818 AclResult aclresult;
1820 roleid = GetUserId();
1821 tableoid = convert_table_name(tablename);
1822 mode = convert_table_priv_string(priv_type_text);
1824 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1826 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1830 * has_table_privilege_name_id
1831 * Check user privileges on a table given
1832 * name usename, table oid, and text priv name.
1835 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1837 Name username = PG_GETARG_NAME(0);
1838 Oid tableoid = PG_GETARG_OID(1);
1839 text *priv_type_text = PG_GETARG_TEXT_P(2);
1842 AclResult aclresult;
1844 roleid = get_role_oid_or_public(NameStr(*username));
1845 mode = convert_table_priv_string(priv_type_text);
1847 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
1850 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1852 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1856 * has_table_privilege_id
1857 * Check user privileges on a table given
1858 * table oid, and text priv name.
1859 * current_user is assumed
1862 has_table_privilege_id(PG_FUNCTION_ARGS)
1864 Oid tableoid = PG_GETARG_OID(0);
1865 text *priv_type_text = PG_GETARG_TEXT_P(1);
1868 AclResult aclresult;
1870 roleid = GetUserId();
1871 mode = convert_table_priv_string(priv_type_text);
1873 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
1876 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1878 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1882 * has_table_privilege_id_name
1883 * Check user privileges on a table given
1884 * roleid, text tablename, and text priv name.
1887 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1889 Oid roleid = PG_GETARG_OID(0);
1890 text *tablename = PG_GETARG_TEXT_P(1);
1891 text *priv_type_text = PG_GETARG_TEXT_P(2);
1894 AclResult aclresult;
1896 tableoid = convert_table_name(tablename);
1897 mode = convert_table_priv_string(priv_type_text);
1899 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1901 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1905 * has_table_privilege_id_id
1906 * Check user privileges on a table given
1907 * roleid, table oid, and text priv name.
1910 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1912 Oid roleid = PG_GETARG_OID(0);
1913 Oid tableoid = PG_GETARG_OID(1);
1914 text *priv_type_text = PG_GETARG_TEXT_P(2);
1916 AclResult aclresult;
1918 mode = convert_table_priv_string(priv_type_text);
1920 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
1923 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1925 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1929 * Support routines for has_table_privilege family.
1933 * Given a table name expressed as a string, look it up and return Oid
1936 convert_table_name(text *tablename)
1940 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1942 return RangeVarGetRelid(relrv, false);
1946 * convert_table_priv_string
1947 * Convert text string to AclMode value.
1950 convert_table_priv_string(text *priv_type_text)
1952 static const priv_map table_priv_map[] = {
1953 {"SELECT", ACL_SELECT},
1954 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
1955 {"INSERT", ACL_INSERT},
1956 {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
1957 {"UPDATE", ACL_UPDATE},
1958 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
1959 {"DELETE", ACL_DELETE},
1960 {"DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE)},
1961 {"TRUNCATE", ACL_TRUNCATE},
1962 {"TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE)},
1963 {"REFERENCES", ACL_REFERENCES},
1964 {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
1965 {"TRIGGER", ACL_TRIGGER},
1966 {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
1967 {"RULE", 0}, /* ignore old RULE privileges */
1968 {"RULE WITH GRANT OPTION", 0},
1972 return convert_any_priv_string(priv_type_text, table_priv_map);
1976 * has_sequence_privilege variants
1977 * These are all named "has_sequence_privilege" at the SQL level.
1978 * They take various combinations of relation name, relation OID,
1979 * user name, user OID, or implicit user = current_user.
1981 * The result is a boolean value: true if user has the indicated
1982 * privilege, false if not. The variants that take a relation OID
1983 * return NULL if the OID doesn't exist.
1987 * has_sequence_privilege_name_name
1988 * Check user privileges on a sequence given
1989 * name username, text sequencename, and text priv name.
1992 has_sequence_privilege_name_name(PG_FUNCTION_ARGS)
1994 Name rolename = PG_GETARG_NAME(0);
1995 text *sequencename = PG_GETARG_TEXT_P(1);
1996 text *priv_type_text = PG_GETARG_TEXT_P(2);
2000 AclResult aclresult;
2002 roleid = get_role_oid_or_public(NameStr(*rolename));
2003 mode = convert_sequence_priv_string(priv_type_text);
2004 sequenceoid = convert_table_name(sequencename);
2005 if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2007 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2008 errmsg("\"%s\" is not a sequence",
2009 text_to_cstring(sequencename))));
2011 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2013 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2017 * has_sequence_privilege_name
2018 * Check user privileges on a sequence given
2019 * text sequencename and text priv name.
2020 * current_user is assumed
2023 has_sequence_privilege_name(PG_FUNCTION_ARGS)
2025 text *sequencename = PG_GETARG_TEXT_P(0);
2026 text *priv_type_text = PG_GETARG_TEXT_P(1);
2030 AclResult aclresult;
2032 roleid = GetUserId();
2033 mode = convert_sequence_priv_string(priv_type_text);
2034 sequenceoid = convert_table_name(sequencename);
2035 if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2037 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2038 errmsg("\"%s\" is not a sequence",
2039 text_to_cstring(sequencename))));
2041 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2043 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2047 * has_sequence_privilege_name_id
2048 * Check user privileges on a sequence given
2049 * name usename, sequence oid, and text priv name.
2052 has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
2054 Name username = PG_GETARG_NAME(0);
2055 Oid sequenceoid = PG_GETARG_OID(1);
2056 text *priv_type_text = PG_GETARG_TEXT_P(2);
2059 AclResult aclresult;
2062 roleid = get_role_oid_or_public(NameStr(*username));
2063 mode = convert_sequence_priv_string(priv_type_text);
2064 relkind = get_rel_relkind(sequenceoid);
2065 if (relkind == '\0')
2067 else if (relkind != RELKIND_SEQUENCE)
2069 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2070 errmsg("\"%s\" is not a sequence",
2071 get_rel_name(sequenceoid))));
2073 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2075 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2079 * has_sequence_privilege_id
2080 * Check user privileges on a sequence given
2081 * sequence oid, and text priv name.
2082 * current_user is assumed
2085 has_sequence_privilege_id(PG_FUNCTION_ARGS)
2087 Oid sequenceoid = PG_GETARG_OID(0);
2088 text *priv_type_text = PG_GETARG_TEXT_P(1);
2091 AclResult aclresult;
2094 roleid = GetUserId();
2095 mode = convert_sequence_priv_string(priv_type_text);
2096 relkind = get_rel_relkind(sequenceoid);
2097 if (relkind == '\0')
2099 else if (relkind != RELKIND_SEQUENCE)
2101 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2102 errmsg("\"%s\" is not a sequence",
2103 get_rel_name(sequenceoid))));
2105 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2107 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2111 * has_sequence_privilege_id_name
2112 * Check user privileges on a sequence given
2113 * roleid, text sequencename, and text priv name.
2116 has_sequence_privilege_id_name(PG_FUNCTION_ARGS)
2118 Oid roleid = PG_GETARG_OID(0);
2119 text *sequencename = PG_GETARG_TEXT_P(1);
2120 text *priv_type_text = PG_GETARG_TEXT_P(2);
2123 AclResult aclresult;
2125 mode = convert_sequence_priv_string(priv_type_text);
2126 sequenceoid = convert_table_name(sequencename);
2127 if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2129 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2130 errmsg("\"%s\" is not a sequence",
2131 text_to_cstring(sequencename))));
2133 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2135 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2139 * has_sequence_privilege_id_id
2140 * Check user privileges on a sequence given
2141 * roleid, sequence oid, and text priv name.
2144 has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
2146 Oid roleid = PG_GETARG_OID(0);
2147 Oid sequenceoid = PG_GETARG_OID(1);
2148 text *priv_type_text = PG_GETARG_TEXT_P(2);
2150 AclResult aclresult;
2153 mode = convert_sequence_priv_string(priv_type_text);
2154 relkind = get_rel_relkind(sequenceoid);
2155 if (relkind == '\0')
2157 else if (relkind != RELKIND_SEQUENCE)
2159 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2160 errmsg("\"%s\" is not a sequence",
2161 get_rel_name(sequenceoid))));
2163 aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2165 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2169 * convert_sequence_priv_string
2170 * Convert text string to AclMode value.
2173 convert_sequence_priv_string(text *priv_type_text)
2175 static const priv_map sequence_priv_map[] = {
2176 {"USAGE", ACL_USAGE},
2177 {"SELECT", ACL_SELECT},
2178 {"UPDATE", ACL_UPDATE},
2182 return convert_any_priv_string(priv_type_text, sequence_priv_map);
2187 * has_any_column_privilege variants
2188 * These are all named "has_any_column_privilege" at the SQL level.
2189 * They take various combinations of relation name, relation OID,
2190 * user name, user OID, or implicit user = current_user.
2192 * The result is a boolean value: true if user has the indicated
2193 * privilege for any column of the table, false if not. The variants
2194 * that take a relation OID return NULL if the OID doesn't exist.
2198 * has_any_column_privilege_name_name
2199 * Check user privileges on any column of a table given
2200 * name username, text tablename, and text priv name.
2203 has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
2205 Name rolename = PG_GETARG_NAME(0);
2206 text *tablename = PG_GETARG_TEXT_P(1);
2207 text *priv_type_text = PG_GETARG_TEXT_P(2);
2211 AclResult aclresult;
2213 roleid = get_role_oid_or_public(NameStr(*rolename));
2214 tableoid = convert_table_name(tablename);
2215 mode = convert_column_priv_string(priv_type_text);
2217 /* First check at table level, then examine each column if needed */
2218 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2219 if (aclresult != ACLCHECK_OK)
2220 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2223 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2227 * has_any_column_privilege_name
2228 * Check user privileges on any column of a table given
2229 * text tablename and text priv name.
2230 * current_user is assumed
2233 has_any_column_privilege_name(PG_FUNCTION_ARGS)
2235 text *tablename = PG_GETARG_TEXT_P(0);
2236 text *priv_type_text = PG_GETARG_TEXT_P(1);
2240 AclResult aclresult;
2242 roleid = GetUserId();
2243 tableoid = convert_table_name(tablename);
2244 mode = convert_column_priv_string(priv_type_text);
2246 /* First check at table level, then examine each column if needed */
2247 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2248 if (aclresult != ACLCHECK_OK)
2249 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2252 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2256 * has_any_column_privilege_name_id
2257 * Check user privileges on any column of a table given
2258 * name usename, table oid, and text priv name.
2261 has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
2263 Name username = PG_GETARG_NAME(0);
2264 Oid tableoid = PG_GETARG_OID(1);
2265 text *priv_type_text = PG_GETARG_TEXT_P(2);
2268 AclResult aclresult;
2270 roleid = get_role_oid_or_public(NameStr(*username));
2271 mode = convert_column_priv_string(priv_type_text);
2273 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
2276 /* First check at table level, then examine each column if needed */
2277 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2278 if (aclresult != ACLCHECK_OK)
2279 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2282 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2286 * has_any_column_privilege_id
2287 * Check user privileges on any column of a table given
2288 * table oid, and text priv name.
2289 * current_user is assumed
2292 has_any_column_privilege_id(PG_FUNCTION_ARGS)
2294 Oid tableoid = PG_GETARG_OID(0);
2295 text *priv_type_text = PG_GETARG_TEXT_P(1);
2298 AclResult aclresult;
2300 roleid = GetUserId();
2301 mode = convert_column_priv_string(priv_type_text);
2303 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
2306 /* First check at table level, then examine each column if needed */
2307 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2308 if (aclresult != ACLCHECK_OK)
2309 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2312 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2316 * has_any_column_privilege_id_name
2317 * Check user privileges on any column of a table given
2318 * roleid, text tablename, and text priv name.
2321 has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
2323 Oid roleid = PG_GETARG_OID(0);
2324 text *tablename = PG_GETARG_TEXT_P(1);
2325 text *priv_type_text = PG_GETARG_TEXT_P(2);
2328 AclResult aclresult;
2330 tableoid = convert_table_name(tablename);
2331 mode = convert_column_priv_string(priv_type_text);
2333 /* First check at table level, then examine each column if needed */
2334 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2335 if (aclresult != ACLCHECK_OK)
2336 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2339 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2343 * has_any_column_privilege_id_id
2344 * Check user privileges on any column of a table given
2345 * roleid, table oid, and text priv name.
2348 has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
2350 Oid roleid = PG_GETARG_OID(0);
2351 Oid tableoid = PG_GETARG_OID(1);
2352 text *priv_type_text = PG_GETARG_TEXT_P(2);
2354 AclResult aclresult;
2356 mode = convert_column_priv_string(priv_type_text);
2358 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
2361 /* First check at table level, then examine each column if needed */
2362 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2363 if (aclresult != ACLCHECK_OK)
2364 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2367 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2372 * has_column_privilege variants
2373 * These are all named "has_column_privilege" at the SQL level.
2374 * They take various combinations of relation name, relation OID,
2375 * column name, column attnum, user name, user OID, or
2376 * implicit user = current_user.
2378 * The result is a boolean value: true if user has the indicated
2379 * privilege, false if not. The variants that take a relation OID
2380 * and an integer attnum return NULL (rather than throwing an error)
2381 * if the column doesn't exist or is dropped.
2385 * column_privilege_check: check column privileges, but don't throw an error
2386 * for dropped column or table
2388 * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
2391 column_privilege_check(Oid tableoid, AttrNumber attnum,
2392 Oid roleid, AclMode mode)
2394 AclResult aclresult;
2396 Form_pg_attribute attributeForm;
2399 * First check if we have the privilege at the table level. We check
2400 * existence of the pg_class row before risking calling pg_class_aclcheck.
2401 * Note: it might seem there's a race condition against concurrent DROP,
2402 * but really it's safe because there will be no syscache flush between
2403 * here and there. So if we see the row in the syscache, so will
2404 * pg_class_aclcheck.
2406 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
2409 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2411 if (aclresult == ACLCHECK_OK)
2415 * No table privilege, so try per-column privileges. Again, we have to
2416 * check for dropped attribute first, and we rely on the syscache not to
2417 * notice a concurrent drop before pg_attribute_aclcheck fetches the row.
2419 attTuple = SearchSysCache2(ATTNUM,
2420 ObjectIdGetDatum(tableoid),
2421 Int16GetDatum(attnum));
2422 if (!HeapTupleIsValid(attTuple))
2424 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
2425 if (attributeForm->attisdropped)
2427 ReleaseSysCache(attTuple);
2430 ReleaseSysCache(attTuple);
2432 aclresult = pg_attribute_aclcheck(tableoid, attnum, roleid, mode);
2434 return (aclresult == ACLCHECK_OK);
2438 * has_column_privilege_name_name_name
2439 * Check user privileges on a column given
2440 * name username, text tablename, text colname, and text priv name.
2443 has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
2445 Name rolename = PG_GETARG_NAME(0);
2446 text *tablename = PG_GETARG_TEXT_P(1);
2447 text *column = PG_GETARG_TEXT_P(2);
2448 text *priv_type_text = PG_GETARG_TEXT_P(3);
2451 AttrNumber colattnum;
2455 roleid = get_role_oid_or_public(NameStr(*rolename));
2456 tableoid = convert_table_name(tablename);
2457 colattnum = convert_column_name(tableoid, column);
2458 mode = convert_column_priv_string(priv_type_text);
2460 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2463 PG_RETURN_BOOL(privresult);
2467 * has_column_privilege_name_name_attnum
2468 * Check user privileges on a column given
2469 * name username, text tablename, int attnum, and text priv name.
2472 has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
2474 Name rolename = PG_GETARG_NAME(0);
2475 text *tablename = PG_GETARG_TEXT_P(1);
2476 AttrNumber colattnum = PG_GETARG_INT16(2);
2477 text *priv_type_text = PG_GETARG_TEXT_P(3);
2483 roleid = get_role_oid_or_public(NameStr(*rolename));
2484 tableoid = convert_table_name(tablename);
2485 mode = convert_column_priv_string(priv_type_text);
2487 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2490 PG_RETURN_BOOL(privresult);
2494 * has_column_privilege_name_id_name
2495 * Check user privileges on a column given
2496 * name username, table oid, text colname, and text priv name.
2499 has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
2501 Name username = PG_GETARG_NAME(0);
2502 Oid tableoid = PG_GETARG_OID(1);
2503 text *column = PG_GETARG_TEXT_P(2);
2504 text *priv_type_text = PG_GETARG_TEXT_P(3);
2506 AttrNumber colattnum;
2510 roleid = get_role_oid_or_public(NameStr(*username));
2511 colattnum = convert_column_name(tableoid, column);
2512 mode = convert_column_priv_string(priv_type_text);
2514 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2517 PG_RETURN_BOOL(privresult);
2521 * has_column_privilege_name_id_attnum
2522 * Check user privileges on a column given
2523 * name username, table oid, int attnum, and text priv name.
2526 has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
2528 Name username = PG_GETARG_NAME(0);
2529 Oid tableoid = PG_GETARG_OID(1);
2530 AttrNumber colattnum = PG_GETARG_INT16(2);
2531 text *priv_type_text = PG_GETARG_TEXT_P(3);
2536 roleid = get_role_oid_or_public(NameStr(*username));
2537 mode = convert_column_priv_string(priv_type_text);
2539 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2542 PG_RETURN_BOOL(privresult);
2546 * has_column_privilege_id_name_name
2547 * Check user privileges on a column given
2548 * oid roleid, text tablename, text colname, and text priv name.
2551 has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
2553 Oid roleid = PG_GETARG_OID(0);
2554 text *tablename = PG_GETARG_TEXT_P(1);
2555 text *column = PG_GETARG_TEXT_P(2);
2556 text *priv_type_text = PG_GETARG_TEXT_P(3);
2558 AttrNumber colattnum;
2562 tableoid = convert_table_name(tablename);
2563 colattnum = convert_column_name(tableoid, column);
2564 mode = convert_column_priv_string(priv_type_text);
2566 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2569 PG_RETURN_BOOL(privresult);
2573 * has_column_privilege_id_name_attnum
2574 * Check user privileges on a column given
2575 * oid roleid, text tablename, int attnum, and text priv name.
2578 has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
2580 Oid roleid = PG_GETARG_OID(0);
2581 text *tablename = PG_GETARG_TEXT_P(1);
2582 AttrNumber colattnum = PG_GETARG_INT16(2);
2583 text *priv_type_text = PG_GETARG_TEXT_P(3);
2588 tableoid = convert_table_name(tablename);
2589 mode = convert_column_priv_string(priv_type_text);
2591 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2594 PG_RETURN_BOOL(privresult);
2598 * has_column_privilege_id_id_name
2599 * Check user privileges on a column given
2600 * oid roleid, table oid, text colname, and text priv name.
2603 has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
2605 Oid roleid = PG_GETARG_OID(0);
2606 Oid tableoid = PG_GETARG_OID(1);
2607 text *column = PG_GETARG_TEXT_P(2);
2608 text *priv_type_text = PG_GETARG_TEXT_P(3);
2609 AttrNumber colattnum;
2613 colattnum = convert_column_name(tableoid, column);
2614 mode = convert_column_priv_string(priv_type_text);
2616 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2619 PG_RETURN_BOOL(privresult);
2623 * has_column_privilege_id_id_attnum
2624 * Check user privileges on a column given
2625 * oid roleid, table oid, int attnum, and text priv name.
2628 has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
2630 Oid roleid = PG_GETARG_OID(0);
2631 Oid tableoid = PG_GETARG_OID(1);
2632 AttrNumber colattnum = PG_GETARG_INT16(2);
2633 text *priv_type_text = PG_GETARG_TEXT_P(3);
2637 mode = convert_column_priv_string(priv_type_text);
2639 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2642 PG_RETURN_BOOL(privresult);
2646 * has_column_privilege_name_name
2647 * Check user privileges on a column given
2648 * text tablename, text colname, and text priv name.
2649 * current_user is assumed
2652 has_column_privilege_name_name(PG_FUNCTION_ARGS)
2654 text *tablename = PG_GETARG_TEXT_P(0);
2655 text *column = PG_GETARG_TEXT_P(1);
2656 text *priv_type_text = PG_GETARG_TEXT_P(2);
2659 AttrNumber colattnum;
2663 roleid = GetUserId();
2664 tableoid = convert_table_name(tablename);
2665 colattnum = convert_column_name(tableoid, column);
2666 mode = convert_column_priv_string(priv_type_text);
2668 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2671 PG_RETURN_BOOL(privresult);
2675 * has_column_privilege_name_attnum
2676 * Check user privileges on a column given
2677 * text tablename, int attnum, and text priv name.
2678 * current_user is assumed
2681 has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
2683 text *tablename = PG_GETARG_TEXT_P(0);
2684 AttrNumber colattnum = PG_GETARG_INT16(1);
2685 text *priv_type_text = PG_GETARG_TEXT_P(2);
2691 roleid = GetUserId();
2692 tableoid = convert_table_name(tablename);
2693 mode = convert_column_priv_string(priv_type_text);
2695 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2698 PG_RETURN_BOOL(privresult);
2702 * has_column_privilege_id_name
2703 * Check user privileges on a column given
2704 * table oid, text colname, and text priv name.
2705 * current_user is assumed
2708 has_column_privilege_id_name(PG_FUNCTION_ARGS)
2710 Oid tableoid = PG_GETARG_OID(0);
2711 text *column = PG_GETARG_TEXT_P(1);
2712 text *priv_type_text = PG_GETARG_TEXT_P(2);
2714 AttrNumber colattnum;
2718 roleid = GetUserId();
2719 colattnum = convert_column_name(tableoid, column);
2720 mode = convert_column_priv_string(priv_type_text);
2722 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2725 PG_RETURN_BOOL(privresult);
2729 * has_column_privilege_id_attnum
2730 * Check user privileges on a column given
2731 * table oid, int attnum, and text priv name.
2732 * current_user is assumed
2735 has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
2737 Oid tableoid = PG_GETARG_OID(0);
2738 AttrNumber colattnum = PG_GETARG_INT16(1);
2739 text *priv_type_text = PG_GETARG_TEXT_P(2);
2744 roleid = GetUserId();
2745 mode = convert_column_priv_string(priv_type_text);
2747 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2750 PG_RETURN_BOOL(privresult);
2754 * Support routines for has_column_privilege family.
2758 * Given a table OID and a column name expressed as a string, look it up
2759 * and return the column number
2762 convert_column_name(Oid tableoid, text *column)
2767 colname = text_to_cstring(column);
2768 attnum = get_attnum(tableoid, colname);
2769 if (attnum == InvalidAttrNumber)
2771 (errcode(ERRCODE_UNDEFINED_COLUMN),
2772 errmsg("column \"%s\" of relation \"%s\" does not exist",
2773 colname, get_rel_name(tableoid))));
2779 * convert_column_priv_string
2780 * Convert text string to AclMode value.
2783 convert_column_priv_string(text *priv_type_text)
2785 static const priv_map column_priv_map[] = {
2786 {"SELECT", ACL_SELECT},
2787 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2788 {"INSERT", ACL_INSERT},
2789 {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2790 {"UPDATE", ACL_UPDATE},
2791 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2792 {"REFERENCES", ACL_REFERENCES},
2793 {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2797 return convert_any_priv_string(priv_type_text, column_priv_map);
2802 * has_database_privilege variants
2803 * These are all named "has_database_privilege" at the SQL level.
2804 * They take various combinations of database name, database OID,
2805 * user name, user OID, or implicit user = current_user.
2807 * The result is a boolean value: true if user has the indicated
2808 * privilege, false if not, or NULL if object doesn't exist.
2812 * has_database_privilege_name_name
2813 * Check user privileges on a database given
2814 * name username, text databasename, and text priv name.
2817 has_database_privilege_name_name(PG_FUNCTION_ARGS)
2819 Name username = PG_GETARG_NAME(0);
2820 text *databasename = PG_GETARG_TEXT_P(1);
2821 text *priv_type_text = PG_GETARG_TEXT_P(2);
2825 AclResult aclresult;
2827 roleid = get_role_oid_or_public(NameStr(*username));
2828 databaseoid = convert_database_name(databasename);
2829 mode = convert_database_priv_string(priv_type_text);
2831 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2833 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2837 * has_database_privilege_name
2838 * Check user privileges on a database given
2839 * text databasename and text priv name.
2840 * current_user is assumed
2843 has_database_privilege_name(PG_FUNCTION_ARGS)
2845 text *databasename = PG_GETARG_TEXT_P(0);
2846 text *priv_type_text = PG_GETARG_TEXT_P(1);
2850 AclResult aclresult;
2852 roleid = GetUserId();
2853 databaseoid = convert_database_name(databasename);
2854 mode = convert_database_priv_string(priv_type_text);
2856 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2858 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2862 * has_database_privilege_name_id
2863 * Check user privileges on a database given
2864 * name usename, database oid, and text priv name.
2867 has_database_privilege_name_id(PG_FUNCTION_ARGS)
2869 Name username = PG_GETARG_NAME(0);
2870 Oid databaseoid = PG_GETARG_OID(1);
2871 text *priv_type_text = PG_GETARG_TEXT_P(2);
2874 AclResult aclresult;
2876 roleid = get_role_oid_or_public(NameStr(*username));
2877 mode = convert_database_priv_string(priv_type_text);
2879 if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
2882 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2884 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2888 * has_database_privilege_id
2889 * Check user privileges on a database given
2890 * database oid, and text priv name.
2891 * current_user is assumed
2894 has_database_privilege_id(PG_FUNCTION_ARGS)
2896 Oid databaseoid = PG_GETARG_OID(0);
2897 text *priv_type_text = PG_GETARG_TEXT_P(1);
2900 AclResult aclresult;
2902 roleid = GetUserId();
2903 mode = convert_database_priv_string(priv_type_text);
2905 if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
2908 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2910 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2914 * has_database_privilege_id_name
2915 * Check user privileges on a database given
2916 * roleid, text databasename, and text priv name.
2919 has_database_privilege_id_name(PG_FUNCTION_ARGS)
2921 Oid roleid = PG_GETARG_OID(0);
2922 text *databasename = PG_GETARG_TEXT_P(1);
2923 text *priv_type_text = PG_GETARG_TEXT_P(2);
2926 AclResult aclresult;
2928 databaseoid = convert_database_name(databasename);
2929 mode = convert_database_priv_string(priv_type_text);
2931 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2933 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2937 * has_database_privilege_id_id
2938 * Check user privileges on a database given
2939 * roleid, database oid, and text priv name.
2942 has_database_privilege_id_id(PG_FUNCTION_ARGS)
2944 Oid roleid = PG_GETARG_OID(0);
2945 Oid databaseoid = PG_GETARG_OID(1);
2946 text *priv_type_text = PG_GETARG_TEXT_P(2);
2948 AclResult aclresult;
2950 mode = convert_database_priv_string(priv_type_text);
2952 if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
2955 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2957 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2961 * Support routines for has_database_privilege family.
2965 * Given a database name expressed as a string, look it up and return Oid
2968 convert_database_name(text *databasename)
2970 char *dbname = text_to_cstring(databasename);
2972 return get_database_oid(dbname, false);
2976 * convert_database_priv_string
2977 * Convert text string to AclMode value.
2980 convert_database_priv_string(text *priv_type_text)
2982 static const priv_map database_priv_map[] = {
2983 {"CREATE", ACL_CREATE},
2984 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
2985 {"TEMPORARY", ACL_CREATE_TEMP},
2986 {"TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
2987 {"TEMP", ACL_CREATE_TEMP},
2988 {"TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
2989 {"CONNECT", ACL_CONNECT},
2990 {"CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT)},
2994 return convert_any_priv_string(priv_type_text, database_priv_map);
3000 * has_foreign_data_wrapper_privilege variants
3001 * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
3002 * They take various combinations of foreign-data wrapper name,
3003 * fdw OID, user name, user OID, or implicit user = current_user.
3005 * The result is a boolean value: true if user has the indicated
3006 * privilege, false if not.
3010 * has_foreign_data_wrapper_privilege_name_name
3011 * Check user privileges on a foreign-data wrapper given
3012 * name username, text fdwname, and text priv name.
3015 has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
3017 Name username = PG_GETARG_NAME(0);
3018 text *fdwname = PG_GETARG_TEXT_P(1);
3019 text *priv_type_text = PG_GETARG_TEXT_P(2);
3023 AclResult aclresult;
3025 roleid = get_role_oid_or_public(NameStr(*username));
3026 fdwid = convert_foreign_data_wrapper_name(fdwname);
3027 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3029 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
3031 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3035 * has_foreign_data_wrapper_privilege_name
3036 * Check user privileges on a foreign-data wrapper given
3037 * text fdwname and text priv name.
3038 * current_user is assumed
3041 has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
3043 text *fdwname = PG_GETARG_TEXT_P(0);
3044 text *priv_type_text = PG_GETARG_TEXT_P(1);
3048 AclResult aclresult;
3050 roleid = GetUserId();
3051 fdwid = convert_foreign_data_wrapper_name(fdwname);
3052 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3054 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
3056 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3060 * has_foreign_data_wrapper_privilege_name_id
3061 * Check user privileges on a foreign-data wrapper given
3062 * name usename, foreign-data wrapper oid, and text priv name.
3065 has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
3067 Name username = PG_GETARG_NAME(0);
3068 Oid fdwid = PG_GETARG_OID(1);
3069 text *priv_type_text = PG_GETARG_TEXT_P(2);
3072 AclResult aclresult;
3074 roleid = get_role_oid_or_public(NameStr(*username));
3075 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3077 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
3079 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3083 * has_foreign_data_wrapper_privilege_id
3084 * Check user privileges on a foreign-data wrapper given
3085 * foreign-data wrapper oid, and text priv name.
3086 * current_user is assumed
3089 has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
3091 Oid fdwid = PG_GETARG_OID(0);
3092 text *priv_type_text = PG_GETARG_TEXT_P(1);
3095 AclResult aclresult;
3097 roleid = GetUserId();
3098 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3100 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
3102 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3106 * has_foreign_data_wrapper_privilege_id_name
3107 * Check user privileges on a foreign-data wrapper given
3108 * roleid, text fdwname, and text priv name.
3111 has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
3113 Oid roleid = PG_GETARG_OID(0);
3114 text *fdwname = PG_GETARG_TEXT_P(1);
3115 text *priv_type_text = PG_GETARG_TEXT_P(2);
3118 AclResult aclresult;
3120 fdwid = convert_foreign_data_wrapper_name(fdwname);
3121 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3123 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
3125 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3129 * has_foreign_data_wrapper_privilege_id_id
3130 * Check user privileges on a foreign-data wrapper given
3131 * roleid, fdw oid, and text priv name.
3134 has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
3136 Oid roleid = PG_GETARG_OID(0);
3137 Oid fdwid = PG_GETARG_OID(1);
3138 text *priv_type_text = PG_GETARG_TEXT_P(2);
3140 AclResult aclresult;
3142 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3144 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
3146 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3150 * Support routines for has_foreign_data_wrapper_privilege family.
3154 * Given a FDW name expressed as a string, look it up and return Oid
3157 convert_foreign_data_wrapper_name(text *fdwname)
3159 char *fdwstr = text_to_cstring(fdwname);
3161 return GetForeignDataWrapperOidByName(fdwstr, false);
3165 * convert_foreign_data_wrapper_priv_string
3166 * Convert text string to AclMode value.
3169 convert_foreign_data_wrapper_priv_string(text *priv_type_text)
3171 static const priv_map foreign_data_wrapper_priv_map[] = {
3172 {"USAGE", ACL_USAGE},
3173 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3177 return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
3182 * has_function_privilege variants
3183 * These are all named "has_function_privilege" at the SQL level.
3184 * They take various combinations of function name, function OID,
3185 * user name, user OID, or implicit user = current_user.
3187 * The result is a boolean value: true if user has the indicated
3188 * privilege, false if not, or NULL if object doesn't exist.
3192 * has_function_privilege_name_name
3193 * Check user privileges on a function given
3194 * name username, text functionname, and text priv name.
3197 has_function_privilege_name_name(PG_FUNCTION_ARGS)
3199 Name username = PG_GETARG_NAME(0);
3200 text *functionname = PG_GETARG_TEXT_P(1);
3201 text *priv_type_text = PG_GETARG_TEXT_P(2);
3205 AclResult aclresult;
3207 roleid = get_role_oid_or_public(NameStr(*username));
3208 functionoid = convert_function_name(functionname);
3209 mode = convert_function_priv_string(priv_type_text);
3211 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
3213 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3217 * has_function_privilege_name
3218 * Check user privileges on a function given
3219 * text functionname and text priv name.
3220 * current_user is assumed
3223 has_function_privilege_name(PG_FUNCTION_ARGS)
3225 text *functionname = PG_GETARG_TEXT_P(0);
3226 text *priv_type_text = PG_GETARG_TEXT_P(1);
3230 AclResult aclresult;
3232 roleid = GetUserId();
3233 functionoid = convert_function_name(functionname);
3234 mode = convert_function_priv_string(priv_type_text);
3236 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
3238 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3242 * has_function_privilege_name_id
3243 * Check user privileges on a function given
3244 * name usename, function oid, and text priv name.
3247 has_function_privilege_name_id(PG_FUNCTION_ARGS)
3249 Name username = PG_GETARG_NAME(0);
3250 Oid functionoid = PG_GETARG_OID(1);
3251 text *priv_type_text = PG_GETARG_TEXT_P(2);
3254 AclResult aclresult;
3256 roleid = get_role_oid_or_public(NameStr(*username));
3257 mode = convert_function_priv_string(priv_type_text);
3259 if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
3262 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
3264 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3268 * has_function_privilege_id
3269 * Check user privileges on a function given
3270 * function oid, and text priv name.
3271 * current_user is assumed
3274 has_function_privilege_id(PG_FUNCTION_ARGS)
3276 Oid functionoid = PG_GETARG_OID(0);
3277 text *priv_type_text = PG_GETARG_TEXT_P(1);
3280 AclResult aclresult;
3282 roleid = GetUserId();
3283 mode = convert_function_priv_string(priv_type_text);
3285 if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
3288 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
3290 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3294 * has_function_privilege_id_name
3295 * Check user privileges on a function given
3296 * roleid, text functionname, and text priv name.
3299 has_function_privilege_id_name(PG_FUNCTION_ARGS)
3301 Oid roleid = PG_GETARG_OID(0);
3302 text *functionname = PG_GETARG_TEXT_P(1);
3303 text *priv_type_text = PG_GETARG_TEXT_P(2);
3306 AclResult aclresult;
3308 functionoid = convert_function_name(functionname);
3309 mode = convert_function_priv_string(priv_type_text);
3311 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
3313 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3317 * has_function_privilege_id_id
3318 * Check user privileges on a function given
3319 * roleid, function oid, and text priv name.
3322 has_function_privilege_id_id(PG_FUNCTION_ARGS)
3324 Oid roleid = PG_GETARG_OID(0);
3325 Oid functionoid = PG_GETARG_OID(1);
3326 text *priv_type_text = PG_GETARG_TEXT_P(2);
3328 AclResult aclresult;
3330 mode = convert_function_priv_string(priv_type_text);
3332 if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
3335 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
3337 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3341 * Support routines for has_function_privilege family.
3345 * Given a function name expressed as a string, look it up and return Oid
3348 convert_function_name(text *functionname)
3350 char *funcname = text_to_cstring(functionname);
3353 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
3354 CStringGetDatum(funcname)));
3356 if (!OidIsValid(oid))
3358 (errcode(ERRCODE_UNDEFINED_FUNCTION),
3359 errmsg("function \"%s\" does not exist", funcname)));
3365 * convert_function_priv_string
3366 * Convert text string to AclMode value.
3369 convert_function_priv_string(text *priv_type_text)
3371 static const priv_map function_priv_map[] = {
3372 {"EXECUTE", ACL_EXECUTE},
3373 {"EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE)},
3377 return convert_any_priv_string(priv_type_text, function_priv_map);
3382 * has_language_privilege variants
3383 * These are all named "has_language_privilege" at the SQL level.
3384 * They take various combinations of language name, language OID,
3385 * user name, user OID, or implicit user = current_user.
3387 * The result is a boolean value: true if user has the indicated
3388 * privilege, false if not, or NULL if object doesn't exist.
3392 * has_language_privilege_name_name
3393 * Check user privileges on a language given
3394 * name username, text languagename, and text priv name.
3397 has_language_privilege_name_name(PG_FUNCTION_ARGS)
3399 Name username = PG_GETARG_NAME(0);
3400 text *languagename = PG_GETARG_TEXT_P(1);
3401 text *priv_type_text = PG_GETARG_TEXT_P(2);
3405 AclResult aclresult;
3407 roleid = get_role_oid_or_public(NameStr(*username));
3408 languageoid = convert_language_name(languagename);
3409 mode = convert_language_priv_string(priv_type_text);
3411 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3413 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3417 * has_language_privilege_name
3418 * Check user privileges on a language given
3419 * text languagename and text priv name.
3420 * current_user is assumed
3423 has_language_privilege_name(PG_FUNCTION_ARGS)
3425 text *languagename = PG_GETARG_TEXT_P(0);
3426 text *priv_type_text = PG_GETARG_TEXT_P(1);
3430 AclResult aclresult;
3432 roleid = GetUserId();
3433 languageoid = convert_language_name(languagename);
3434 mode = convert_language_priv_string(priv_type_text);
3436 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3438 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3442 * has_language_privilege_name_id
3443 * Check user privileges on a language given
3444 * name usename, language oid, and text priv name.
3447 has_language_privilege_name_id(PG_FUNCTION_ARGS)
3449 Name username = PG_GETARG_NAME(0);
3450 Oid languageoid = PG_GETARG_OID(1);
3451 text *priv_type_text = PG_GETARG_TEXT_P(2);
3454 AclResult aclresult;
3456 roleid = get_role_oid_or_public(NameStr(*username));
3457 mode = convert_language_priv_string(priv_type_text);
3459 if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
3462 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3464 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3468 * has_language_privilege_id
3469 * Check user privileges on a language given
3470 * language oid, and text priv name.
3471 * current_user is assumed
3474 has_language_privilege_id(PG_FUNCTION_ARGS)
3476 Oid languageoid = PG_GETARG_OID(0);
3477 text *priv_type_text = PG_GETARG_TEXT_P(1);
3480 AclResult aclresult;
3482 roleid = GetUserId();
3483 mode = convert_language_priv_string(priv_type_text);
3485 if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
3488 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3490 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3494 * has_language_privilege_id_name
3495 * Check user privileges on a language given
3496 * roleid, text languagename, and text priv name.
3499 has_language_privilege_id_name(PG_FUNCTION_ARGS)
3501 Oid roleid = PG_GETARG_OID(0);
3502 text *languagename = PG_GETARG_TEXT_P(1);
3503 text *priv_type_text = PG_GETARG_TEXT_P(2);
3506 AclResult aclresult;
3508 languageoid = convert_language_name(languagename);
3509 mode = convert_language_priv_string(priv_type_text);
3511 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3513 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3517 * has_language_privilege_id_id
3518 * Check user privileges on a language given
3519 * roleid, language oid, and text priv name.
3522 has_language_privilege_id_id(PG_FUNCTION_ARGS)
3524 Oid roleid = PG_GETARG_OID(0);
3525 Oid languageoid = PG_GETARG_OID(1);
3526 text *priv_type_text = PG_GETARG_TEXT_P(2);
3528 AclResult aclresult;
3530 mode = convert_language_priv_string(priv_type_text);
3532 if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
3535 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3537 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3541 * Support routines for has_language_privilege family.
3545 * Given a language name expressed as a string, look it up and return Oid
3548 convert_language_name(text *languagename)
3550 char *langname = text_to_cstring(languagename);
3552 return get_language_oid(langname, false);
3556 * convert_language_priv_string
3557 * Convert text string to AclMode value.
3560 convert_language_priv_string(text *priv_type_text)
3562 static const priv_map language_priv_map[] = {
3563 {"USAGE", ACL_USAGE},
3564 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3568 return convert_any_priv_string(priv_type_text, language_priv_map);
3573 * has_schema_privilege variants
3574 * These are all named "has_schema_privilege" at the SQL level.
3575 * They take various combinations of schema name, schema OID,
3576 * user name, user OID, or implicit user = current_user.
3578 * The result is a boolean value: true if user has the indicated
3579 * privilege, false if not, or NULL if object doesn't exist.
3583 * has_schema_privilege_name_name
3584 * Check user privileges on a schema given
3585 * name username, text schemaname, and text priv name.
3588 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
3590 Name username = PG_GETARG_NAME(0);
3591 text *schemaname = PG_GETARG_TEXT_P(1);
3592 text *priv_type_text = PG_GETARG_TEXT_P(2);
3596 AclResult aclresult;
3598 roleid = get_role_oid_or_public(NameStr(*username));
3599 schemaoid = convert_schema_name(schemaname);
3600 mode = convert_schema_priv_string(priv_type_text);
3602 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3604 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3608 * has_schema_privilege_name
3609 * Check user privileges on a schema given
3610 * text schemaname and text priv name.
3611 * current_user is assumed
3614 has_schema_privilege_name(PG_FUNCTION_ARGS)
3616 text *schemaname = PG_GETARG_TEXT_P(0);
3617 text *priv_type_text = PG_GETARG_TEXT_P(1);
3621 AclResult aclresult;
3623 roleid = GetUserId();
3624 schemaoid = convert_schema_name(schemaname);
3625 mode = convert_schema_priv_string(priv_type_text);
3627 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3629 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3633 * has_schema_privilege_name_id
3634 * Check user privileges on a schema given
3635 * name usename, schema oid, and text priv name.
3638 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
3640 Name username = PG_GETARG_NAME(0);
3641 Oid schemaoid = PG_GETARG_OID(1);
3642 text *priv_type_text = PG_GETARG_TEXT_P(2);
3645 AclResult aclresult;
3647 roleid = get_role_oid_or_public(NameStr(*username));
3648 mode = convert_schema_priv_string(priv_type_text);
3650 if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
3653 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3655 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3659 * has_schema_privilege_id
3660 * Check user privileges on a schema given
3661 * schema oid, and text priv name.
3662 * current_user is assumed
3665 has_schema_privilege_id(PG_FUNCTION_ARGS)
3667 Oid schemaoid = PG_GETARG_OID(0);
3668 text *priv_type_text = PG_GETARG_TEXT_P(1);
3671 AclResult aclresult;
3673 roleid = GetUserId();
3674 mode = convert_schema_priv_string(priv_type_text);
3676 if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
3679 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3681 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3685 * has_schema_privilege_id_name
3686 * Check user privileges on a schema given
3687 * roleid, text schemaname, and text priv name.
3690 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
3692 Oid roleid = PG_GETARG_OID(0);
3693 text *schemaname = PG_GETARG_TEXT_P(1);
3694 text *priv_type_text = PG_GETARG_TEXT_P(2);
3697 AclResult aclresult;
3699 schemaoid = convert_schema_name(schemaname);
3700 mode = convert_schema_priv_string(priv_type_text);
3702 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3704 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3708 * has_schema_privilege_id_id
3709 * Check user privileges on a schema given
3710 * roleid, schema oid, and text priv name.
3713 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
3715 Oid roleid = PG_GETARG_OID(0);
3716 Oid schemaoid = PG_GETARG_OID(1);
3717 text *priv_type_text = PG_GETARG_TEXT_P(2);
3719 AclResult aclresult;
3721 mode = convert_schema_priv_string(priv_type_text);
3723 if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
3726 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3728 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3732 * Support routines for has_schema_privilege family.
3736 * Given a schema name expressed as a string, look it up and return Oid
3739 convert_schema_name(text *schemaname)
3741 char *nspname = text_to_cstring(schemaname);
3743 return get_namespace_oid(nspname, false);
3747 * convert_schema_priv_string
3748 * Convert text string to AclMode value.
3751 convert_schema_priv_string(text *priv_type_text)
3753 static const priv_map schema_priv_map[] = {
3754 {"CREATE", ACL_CREATE},
3755 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
3756 {"USAGE", ACL_USAGE},
3757 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3761 return convert_any_priv_string(priv_type_text, schema_priv_map);
3766 * has_server_privilege variants
3767 * These are all named "has_server_privilege" at the SQL level.
3768 * They take various combinations of foreign server name,
3769 * server OID, user name, user OID, or implicit user = current_user.
3771 * The result is a boolean value: true if user has the indicated
3772 * privilege, false if not.
3776 * has_server_privilege_name_name
3777 * Check user privileges on a foreign server given
3778 * name username, text servername, and text priv name.
3781 has_server_privilege_name_name(PG_FUNCTION_ARGS)
3783 Name username = PG_GETARG_NAME(0);
3784 text *servername = PG_GETARG_TEXT_P(1);
3785 text *priv_type_text = PG_GETARG_TEXT_P(2);
3789 AclResult aclresult;
3791 roleid = get_role_oid_or_public(NameStr(*username));
3792 serverid = convert_server_name(servername);
3793 mode = convert_server_priv_string(priv_type_text);
3795 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3797 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3801 * has_server_privilege_name
3802 * Check user privileges on a foreign server given
3803 * text servername and text priv name.
3804 * current_user is assumed
3807 has_server_privilege_name(PG_FUNCTION_ARGS)
3809 text *servername = PG_GETARG_TEXT_P(0);
3810 text *priv_type_text = PG_GETARG_TEXT_P(1);
3814 AclResult aclresult;
3816 roleid = GetUserId();
3817 serverid = convert_server_name(servername);
3818 mode = convert_server_priv_string(priv_type_text);
3820 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3822 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3826 * has_server_privilege_name_id
3827 * Check user privileges on a foreign server given
3828 * name usename, foreign server oid, and text priv name.
3831 has_server_privilege_name_id(PG_FUNCTION_ARGS)
3833 Name username = PG_GETARG_NAME(0);
3834 Oid serverid = PG_GETARG_OID(1);
3835 text *priv_type_text = PG_GETARG_TEXT_P(2);
3838 AclResult aclresult;
3840 roleid = get_role_oid_or_public(NameStr(*username));
3841 mode = convert_server_priv_string(priv_type_text);
3843 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3845 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3849 * has_server_privilege_id
3850 * Check user privileges on a foreign server given
3851 * server oid, and text priv name.
3852 * current_user is assumed
3855 has_server_privilege_id(PG_FUNCTION_ARGS)
3857 Oid serverid = PG_GETARG_OID(0);
3858 text *priv_type_text = PG_GETARG_TEXT_P(1);
3861 AclResult aclresult;
3863 roleid = GetUserId();
3864 mode = convert_server_priv_string(priv_type_text);
3866 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3868 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3872 * has_server_privilege_id_name
3873 * Check user privileges on a foreign server given
3874 * roleid, text servername, and text priv name.
3877 has_server_privilege_id_name(PG_FUNCTION_ARGS)
3879 Oid roleid = PG_GETARG_OID(0);
3880 text *servername = PG_GETARG_TEXT_P(1);
3881 text *priv_type_text = PG_GETARG_TEXT_P(2);
3884 AclResult aclresult;
3886 serverid = convert_server_name(servername);
3887 mode = convert_server_priv_string(priv_type_text);
3889 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3891 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3895 * has_server_privilege_id_id
3896 * Check user privileges on a foreign server given
3897 * roleid, server oid, and text priv name.
3900 has_server_privilege_id_id(PG_FUNCTION_ARGS)
3902 Oid roleid = PG_GETARG_OID(0);
3903 Oid serverid = PG_GETARG_OID(1);
3904 text *priv_type_text = PG_GETARG_TEXT_P(2);
3906 AclResult aclresult;
3908 mode = convert_server_priv_string(priv_type_text);
3910 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3912 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3916 * Support routines for has_server_privilege family.
3920 * Given a server name expressed as a string, look it up and return Oid
3923 convert_server_name(text *servername)
3925 char *serverstr = text_to_cstring(servername);
3927 return GetForeignServerOidByName(serverstr, false);
3931 * convert_server_priv_string
3932 * Convert text string to AclMode value.
3935 convert_server_priv_string(text *priv_type_text)
3937 static const priv_map server_priv_map[] = {
3938 {"USAGE", ACL_USAGE},
3939 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3943 return convert_any_priv_string(priv_type_text, server_priv_map);
3948 * has_tablespace_privilege variants
3949 * These are all named "has_tablespace_privilege" at the SQL level.
3950 * They take various combinations of tablespace name, tablespace OID,
3951 * user name, user OID, or implicit user = current_user.
3953 * The result is a boolean value: true if user has the indicated
3954 * privilege, false if not.
3958 * has_tablespace_privilege_name_name
3959 * Check user privileges on a tablespace given
3960 * name username, text tablespacename, and text priv name.
3963 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
3965 Name username = PG_GETARG_NAME(0);
3966 text *tablespacename = PG_GETARG_TEXT_P(1);
3967 text *priv_type_text = PG_GETARG_TEXT_P(2);
3971 AclResult aclresult;
3973 roleid = get_role_oid_or_public(NameStr(*username));
3974 tablespaceoid = convert_tablespace_name(tablespacename);
3975 mode = convert_tablespace_priv_string(priv_type_text);
3977 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3979 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3983 * has_tablespace_privilege_name
3984 * Check user privileges on a tablespace given
3985 * text tablespacename and text priv name.
3986 * current_user is assumed
3989 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
3991 text *tablespacename = PG_GETARG_TEXT_P(0);
3992 text *priv_type_text = PG_GETARG_TEXT_P(1);
3996 AclResult aclresult;
3998 roleid = GetUserId();
3999 tablespaceoid = convert_tablespace_name(tablespacename);
4000 mode = convert_tablespace_priv_string(priv_type_text);
4002 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
4004 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4008 * has_tablespace_privilege_name_id
4009 * Check user privileges on a tablespace given
4010 * name usename, tablespace oid, and text priv name.
4013 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
4015 Name username = PG_GETARG_NAME(0);
4016 Oid tablespaceoid = PG_GETARG_OID(1);
4017 text *priv_type_text = PG_GETARG_TEXT_P(2);
4020 AclResult aclresult;
4022 roleid = get_role_oid_or_public(NameStr(*username));
4023 mode = convert_tablespace_priv_string(priv_type_text);
4025 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
4027 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4031 * has_tablespace_privilege_id
4032 * Check user privileges on a tablespace given
4033 * tablespace oid, and text priv name.
4034 * current_user is assumed
4037 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
4039 Oid tablespaceoid = PG_GETARG_OID(0);
4040 text *priv_type_text = PG_GETARG_TEXT_P(1);
4043 AclResult aclresult;
4045 roleid = GetUserId();
4046 mode = convert_tablespace_priv_string(priv_type_text);
4048 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
4050 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4054 * has_tablespace_privilege_id_name
4055 * Check user privileges on a tablespace given
4056 * roleid, text tablespacename, and text priv name.
4059 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
4061 Oid roleid = PG_GETARG_OID(0);
4062 text *tablespacename = PG_GETARG_TEXT_P(1);
4063 text *priv_type_text = PG_GETARG_TEXT_P(2);
4066 AclResult aclresult;
4068 tablespaceoid = convert_tablespace_name(tablespacename);
4069 mode = convert_tablespace_priv_string(priv_type_text);
4071 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
4073 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4077 * has_tablespace_privilege_id_id
4078 * Check user privileges on a tablespace given
4079 * roleid, tablespace oid, and text priv name.
4082 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
4084 Oid roleid = PG_GETARG_OID(0);
4085 Oid tablespaceoid = PG_GETARG_OID(1);
4086 text *priv_type_text = PG_GETARG_TEXT_P(2);
4088 AclResult aclresult;
4090 mode = convert_tablespace_priv_string(priv_type_text);
4092 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
4094 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4098 * Support routines for has_tablespace_privilege family.
4102 * Given a tablespace name expressed as a string, look it up and return Oid
4105 convert_tablespace_name(text *tablespacename)
4107 char *spcname = text_to_cstring(tablespacename);
4109 return get_tablespace_oid(spcname, false);
4113 * convert_tablespace_priv_string
4114 * Convert text string to AclMode value.
4117 convert_tablespace_priv_string(text *priv_type_text)
4119 static const priv_map tablespace_priv_map[] = {
4120 {"CREATE", ACL_CREATE},
4121 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4125 return convert_any_priv_string(priv_type_text, tablespace_priv_map);
4129 * pg_has_role variants
4130 * These are all named "pg_has_role" at the SQL level.
4131 * They take various combinations of role name, role OID,
4132 * user name, user OID, or implicit user = current_user.
4134 * The result is a boolean value: true if user has the indicated
4135 * privilege, false if not.
4139 * pg_has_role_name_name
4140 * Check user privileges on a role given
4141 * name username, name rolename, and text priv name.
4144 pg_has_role_name_name(PG_FUNCTION_ARGS)
4146 Name username = PG_GETARG_NAME(0);
4147 Name rolename = PG_GETARG_NAME(1);
4148 text *priv_type_text = PG_GETARG_TEXT_P(2);
4152 AclResult aclresult;
4154 roleid = get_role_oid(NameStr(*username), false);
4155 roleoid = get_role_oid(NameStr(*rolename), false);
4156 mode = convert_role_priv_string(priv_type_text);
4158 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4160 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4165 * Check user privileges on a role given
4166 * name rolename and text priv name.
4167 * current_user is assumed
4170 pg_has_role_name(PG_FUNCTION_ARGS)
4172 Name rolename = PG_GETARG_NAME(0);
4173 text *priv_type_text = PG_GETARG_TEXT_P(1);
4177 AclResult aclresult;
4179 roleid = GetUserId();
4180 roleoid = get_role_oid(NameStr(*rolename), false);
4181 mode = convert_role_priv_string(priv_type_text);
4183 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4185 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4189 * pg_has_role_name_id
4190 * Check user privileges on a role given
4191 * name usename, role oid, and text priv name.
4194 pg_has_role_name_id(PG_FUNCTION_ARGS)
4196 Name username = PG_GETARG_NAME(0);
4197 Oid roleoid = PG_GETARG_OID(1);
4198 text *priv_type_text = PG_GETARG_TEXT_P(2);
4201 AclResult aclresult;
4203 roleid = get_role_oid(NameStr(*username), false);
4204 mode = convert_role_priv_string(priv_type_text);
4206 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4208 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4213 * Check user privileges on a role given
4214 * role oid, and text priv name.
4215 * current_user is assumed
4218 pg_has_role_id(PG_FUNCTION_ARGS)
4220 Oid roleoid = PG_GETARG_OID(0);
4221 text *priv_type_text = PG_GETARG_TEXT_P(1);
4224 AclResult aclresult;
4226 roleid = GetUserId();
4227 mode = convert_role_priv_string(priv_type_text);
4229 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4231 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4235 * pg_has_role_id_name
4236 * Check user privileges on a role given
4237 * roleid, name rolename, and text priv name.
4240 pg_has_role_id_name(PG_FUNCTION_ARGS)
4242 Oid roleid = PG_GETARG_OID(0);
4243 Name rolename = PG_GETARG_NAME(1);
4244 text *priv_type_text = PG_GETARG_TEXT_P(2);
4247 AclResult aclresult;
4249 roleoid = get_role_oid(NameStr(*rolename), false);
4250 mode = convert_role_priv_string(priv_type_text);
4252 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4254 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4259 * Check user privileges on a role given
4260 * roleid, role oid, and text priv name.
4263 pg_has_role_id_id(PG_FUNCTION_ARGS)
4265 Oid roleid = PG_GETARG_OID(0);
4266 Oid roleoid = PG_GETARG_OID(1);
4267 text *priv_type_text = PG_GETARG_TEXT_P(2);
4269 AclResult aclresult;
4271 mode = convert_role_priv_string(priv_type_text);
4273 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4275 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4279 * Support routines for pg_has_role family.
4283 * convert_role_priv_string
4284 * Convert text string to AclMode value.
4286 * We use USAGE to denote whether the privileges of the role are accessible
4287 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
4288 * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
4289 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
4290 * is shared only with pg_role_aclcheck, below.
4293 convert_role_priv_string(text *priv_type_text)
4295 static const priv_map role_priv_map[] = {
4296 {"USAGE", ACL_USAGE},
4297 {"MEMBER", ACL_CREATE},
4298 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4299 {"USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4300 {"MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4301 {"MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4305 return convert_any_priv_string(priv_type_text, role_priv_map);
4310 * Quick-and-dirty support for pg_has_role
4313 pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
4315 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
4317 if (is_admin_of_role(roleid, role_oid))
4320 if (mode & ACL_CREATE)
4322 if (is_member_of_role(roleid, role_oid))
4325 if (mode & ACL_USAGE)
4327 if (has_privs_of_role(roleid, role_oid))
4330 return ACLCHECK_NO_PRIV;
4335 * initialization function (called by InitPostgres)
4338 initialize_acl(void)
4340 if (!IsBootstrapProcessingMode())
4343 * In normal mode, set a callback on any syscache invalidation of
4344 * pg_auth_members rows
4346 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
4347 RoleMembershipCacheCallback,
4353 * RoleMembershipCacheCallback
4354 * Syscache inval callback function
4357 RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
4359 /* Force membership caches to be recomputed on next use */
4360 cached_privs_role = InvalidOid;
4361 cached_member_role = InvalidOid;
4365 /* Check if specified role has rolinherit set */
4367 has_rolinherit(Oid roleid)
4369 bool result = false;
4372 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4373 if (HeapTupleIsValid(utup))
4375 result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
4376 ReleaseSysCache(utup);
4383 * Get a list of roles that the specified roleid has the privileges of
4385 * This is defined not to recurse through roles that don't have rolinherit
4386 * set; for such roles, membership implies the ability to do SET ROLE, but
4387 * the privileges are not available until you've done so.
4389 * Since indirect membership testing is relatively expensive, we cache
4390 * a list of memberships. Hence, the result is only guaranteed good until
4391 * the next call of roles_has_privs_of()!
4393 * For the benefit of select_best_grantor, the result is defined to be
4394 * in breadth-first order, ie, closer relationships earlier.
4397 roles_has_privs_of(Oid roleid)
4401 List *new_cached_privs_roles;
4402 MemoryContext oldctx;
4404 /* If cache is already valid, just return the list */
4405 if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
4406 return cached_privs_roles;
4409 * Find all the roles that roleid is a member of, including multi-level
4410 * recursion. The role itself will always be the first element of the
4413 * Each element of the list is scanned to see if it adds any indirect
4414 * memberships. We can use a single list as both the record of
4415 * already-found memberships and the agenda of roles yet to be scanned.
4416 * This is a bit tricky but works because the foreach() macro doesn't
4417 * fetch the next list element until the bottom of the loop.
4419 roles_list = list_make1_oid(roleid);
4421 foreach(l, roles_list)
4423 Oid memberid = lfirst_oid(l);
4427 /* Ignore non-inheriting roles */
4428 if (!has_rolinherit(memberid))
4431 /* Find roles that memberid is directly a member of */
4432 memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
4433 ObjectIdGetDatum(memberid));
4434 for (i = 0; i < memlist->n_members; i++)
4436 HeapTuple tup = &memlist->members[i]->tuple;
4437 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
4440 * Even though there shouldn't be any loops in the membership
4441 * graph, we must test for having already seen this role. It is
4442 * legal for instance to have both A->B and A->C->B.
4444 roles_list = list_append_unique_oid(roles_list, otherid);
4446 ReleaseSysCacheList(memlist);
4450 * Copy the completed list into TopMemoryContext so it will persist.
4452 oldctx = MemoryContextSwitchTo(TopMemoryContext);
4453 new_cached_privs_roles = list_copy(roles_list);
4454 MemoryContextSwitchTo(oldctx);
4455 list_free(roles_list);
4458 * Now safe to assign to state variable
4460 cached_privs_role = InvalidOid; /* just paranoia */
4461 list_free(cached_privs_roles);
4462 cached_privs_roles = new_cached_privs_roles;
4463 cached_privs_role = roleid;
4465 /* And now we can return the answer */
4466 return cached_privs_roles;
4471 * Get a list of roles that the specified roleid is a member of
4473 * This is defined to recurse through roles regardless of rolinherit.
4475 * Since indirect membership testing is relatively expensive, we cache
4476 * a list of memberships. Hence, the result is only guaranteed good until
4477 * the next call of roles_is_member_of()!
4480 roles_is_member_of(Oid roleid)
4484 List *new_cached_membership_roles;
4485 MemoryContext oldctx;
4487 /* If cache is already valid, just return the list */
4488 if (OidIsValid(cached_member_role) && cached_member_role == roleid)
4489 return cached_membership_roles;
4492 * Find all the roles that roleid is a member of, including multi-level
4493 * recursion. The role itself will always be the first element of the
4496 * Each element of the list is scanned to see if it adds any indirect
4497 * memberships. We can use a single list as both the record of
4498 * already-found memberships and the agenda of roles yet to be scanned.
4499 * This is a bit tricky but works because the foreach() macro doesn't
4500 * fetch the next list element until the bottom of the loop.
4502 roles_list = list_make1_oid(roleid);
4504 foreach(l, roles_list)
4506 Oid memberid = lfirst_oid(l);
4510 /* Find roles that memberid is directly a member of */
4511 memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
4512 ObjectIdGetDatum(memberid));
4513 for (i = 0; i < memlist->n_members; i++)
4515 HeapTuple tup = &memlist->members[i]->tuple;
4516 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
4519 * Even though there shouldn't be any loops in the membership
4520 * graph, we must test for having already seen this role. It is
4521 * legal for instance to have both A->B and A->C->B.
4523 roles_list = list_append_unique_oid(roles_list, otherid);
4525 ReleaseSysCacheList(memlist);
4529 * Copy the completed list into TopMemoryContext so it will persist.
4531 oldctx = MemoryContextSwitchTo(TopMemoryContext);
4532 new_cached_membership_roles = list_copy(roles_list);
4533 MemoryContextSwitchTo(oldctx);
4534 list_free(roles_list);
4537 * Now safe to assign to state variable
4539 cached_member_role = InvalidOid; /* just paranoia */
4540 list_free(cached_membership_roles);
4541 cached_membership_roles = new_cached_membership_roles;
4542 cached_member_role = roleid;
4544 /* And now we can return the answer */
4545 return cached_membership_roles;
4550 * Does member have the privileges of role (directly or indirectly)?
4552 * This is defined not to recurse through roles that don't have rolinherit
4553 * set; for such roles, membership implies the ability to do SET ROLE, but
4554 * the privileges are not available until you've done so.
4557 has_privs_of_role(Oid member, Oid role)
4559 /* Fast path for simple case */
4563 /* Superusers have every privilege, so are part of every role */
4564 if (superuser_arg(member))
4568 * Find all the roles that member has the privileges of, including
4569 * multi-level recursion, then see if target role is any one of them.
4571 return list_member_oid(roles_has_privs_of(member), role);
4576 * Is member a member of role (directly or indirectly)?
4578 * This is defined to recurse through roles regardless of rolinherit.
4581 is_member_of_role(Oid member, Oid role)
4583 /* Fast path for simple case */
4587 /* Superusers have every privilege, so are part of every role */
4588 if (superuser_arg(member))
4592 * Find all the roles that member is a member of, including multi-level
4593 * recursion, then see if target role is any one of them.
4595 return list_member_oid(roles_is_member_of(member), role);
4599 * check_is_member_of_role
4600 * is_member_of_role with a standard permission-violation error if not
4603 check_is_member_of_role(Oid member, Oid role)
4605 if (!is_member_of_role(member, role))
4607 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4608 errmsg("must be member of role \"%s\"",
4609 GetUserNameFromId(role))));
4613 * Is member a member of role, not considering superuserness?
4615 * This is identical to is_member_of_role except we ignore superuser
4619 is_member_of_role_nosuper(Oid member, Oid role)
4621 /* Fast path for simple case */
4626 * Find all the roles that member is a member of, including multi-level
4627 * recursion, then see if target role is any one of them.
4629 return list_member_oid(roles_is_member_of(member), role);
4634 * Is member an admin of role (directly or indirectly)? That is, is it
4635 * a member WITH ADMIN OPTION?
4637 * We could cache the result as for is_member_of_role, but currently this
4638 * is not used in any performance-critical paths, so we don't.
4641 is_admin_of_role(Oid member, Oid role)
4643 bool result = false;
4647 /* Fast path for simple case */
4651 /* Superusers have every privilege, so are part of every role */
4652 if (superuser_arg(member))
4656 * Find all the roles that member is a member of, including multi-level
4657 * recursion. We build a list in the same way that is_member_of_role does
4658 * to track visited and unvisited roles.
4660 roles_list = list_make1_oid(member);
4662 foreach(l, roles_list)
4664 Oid memberid = lfirst_oid(l);
4668 /* Find roles that memberid is directly a member of */
4669 memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
4670 ObjectIdGetDatum(memberid));
4671 for (i = 0; i < memlist->n_members; i++)
4673 HeapTuple tup = &memlist->members[i]->tuple;
4674 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
4676 if (otherid == role &&
4677 ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
4679 /* Found what we came for, so can stop searching */
4684 roles_list = list_append_unique_oid(roles_list, otherid);
4686 ReleaseSysCacheList(memlist);
4691 list_free(roles_list);
4697 /* does what it says ... */
4699 count_one_bits(AclMode mask)
4703 /* this code relies on AclMode being an unsigned type */
4715 * Select the effective grantor ID for a GRANT or REVOKE operation.
4717 * The grantor must always be either the object owner or some role that has
4718 * been explicitly granted grant options. This ensures that all granted
4719 * privileges appear to flow from the object owner, and there are never
4720 * multiple "original sources" of a privilege. Therefore, if the would-be
4721 * grantor is a member of a role that has the needed grant options, we have
4722 * to do the grant as that role instead.
4724 * It is possible that the would-be grantor is a member of several roles
4725 * that have different subsets of the desired grant options, but no one
4726 * role has 'em all. In this case we pick a role with the largest number
4727 * of desired options. Ties are broken in favor of closer ancestors.
4729 * roleId: the role attempting to do the GRANT/REVOKE
4730 * privileges: the privileges to be granted/revoked
4731 * acl: the ACL of the object in question
4732 * ownerId: the role owning the object in question
4733 * *grantorId: receives the OID of the role to do the grant as
4734 * *grantOptions: receives the grant options actually held by grantorId
4736 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
4739 select_best_grantor(Oid roleId, AclMode privileges,
4740 const Acl *acl, Oid ownerId,
4741 Oid *grantorId, AclMode *grantOptions)
4743 AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
4749 * The object owner is always treated as having all grant options, so if
4750 * roleId is the owner it's easy. Also, if roleId is a superuser it's
4751 * easy: superusers are implicitly members of every role, so they act as
4754 if (roleId == ownerId || superuser_arg(roleId))
4756 *grantorId = ownerId;
4757 *grantOptions = needed_goptions;
4762 * Otherwise we have to do a careful search to see if roleId has the
4763 * privileges of any suitable role. Note: we can hang onto the result of
4764 * roles_has_privs_of() throughout this loop, because aclmask_direct()
4765 * doesn't query any role memberships.
4767 roles_list = roles_has_privs_of(roleId);
4769 /* initialize candidate result as default */
4770 *grantorId = roleId;
4771 *grantOptions = ACL_NO_RIGHTS;
4774 foreach(l, roles_list)
4776 Oid otherrole = lfirst_oid(l);
4779 otherprivs = aclmask_direct(acl, otherrole, ownerId,
4780 needed_goptions, ACLMASK_ALL);
4781 if (otherprivs == needed_goptions)
4783 /* Found a suitable grantor */
4784 *grantorId = otherrole;
4785 *grantOptions = otherprivs;
4790 * If it has just some of the needed privileges, remember best
4793 if (otherprivs != ACL_NO_RIGHTS)
4795 int nnewrights = count_one_bits(otherprivs);
4797 if (nnewrights > nrights)
4799 *grantorId = otherrole;
4800 *grantOptions = otherprivs;
4801 nrights = nnewrights;
4808 * get_role_oid - Given a role name, look up the role's OID.
4810 * If missing_ok is false, throw an error if tablespace name not found. If
4811 * true, just return InvalidOid.
4814 get_role_oid(const char *rolname, bool missing_ok)
4818 oid = GetSysCacheOid1(AUTHNAME, CStringGetDatum(rolname));
4819 if (!OidIsValid(oid) && !missing_ok)
4821 (errcode(ERRCODE_UNDEFINED_OBJECT),
4822 errmsg("role \"%s\" does not exist", rolname)));
4827 * get_role_oid_or_public - As above, but return ACL_ID_PUBLIC if the
4828 * role name is "public".
4831 get_role_oid_or_public(const char *rolname)
4833 if (strcmp(rolname, "public") == 0)
4834 return ACL_ID_PUBLIC;
4836 return get_role_oid(rolname, false);