1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.146 2009/01/22 20:16:06 tgl Exp $
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 "commands/dbcommands.h"
24 #include "commands/tablespace.h"
25 #include "foreign/foreign.h"
26 #include "miscadmin.h"
27 #include "utils/acl.h"
28 #include "utils/builtins.h"
29 #include "utils/inval.h"
30 #include "utils/lsyscache.h"
31 #include "utils/memutils.h"
32 #include "utils/syscache.h"
36 * We frequently need to test whether a given role is a member of some other
37 * role. In most of these tests the "given role" is the same, namely the
38 * active current user. So we can optimize it by keeping a cached list of
39 * all the roles the "given role" is a member of, directly or indirectly.
40 * The cache is flushed whenever we detect a change in pg_auth_members.
42 * There are actually two caches, one computed under "has_privs" rules
43 * (do not recurse where rolinherit isn't true) and one computed under
44 * "is_member" rules (recurse regardless of rolinherit).
46 * Possibly this mechanism should be generalized to allow caching membership
47 * info for multiple roles?
49 * The has_privs cache is:
50 * cached_privs_role is the role OID the cache is for.
51 * cached_privs_roles is an OID list of roles that cached_privs_role
52 * has the privileges of (always including itself).
53 * The cache is valid if cached_privs_role is not InvalidOid.
55 * The is_member cache is similarly:
56 * cached_member_role is the role OID the cache is for.
57 * cached_membership_roles is an OID list of roles that cached_member_role
58 * is a member of (always including itself).
59 * The cache is valid if cached_member_role is not InvalidOid.
61 static Oid cached_privs_role = InvalidOid;
62 static List *cached_privs_roles = NIL;
63 static Oid cached_member_role = InvalidOid;
64 static List *cached_membership_roles = NIL;
67 static const char *getid(const char *s, char *n);
68 static void putid(char *p, const char *s);
69 static Acl *allocacl(int n);
70 static void check_acl(const Acl *acl);
71 static const char *aclparse(const char *s, AclItem *aip);
72 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
73 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
75 static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
76 Oid ownerId, DropBehavior behavior);
77 static int oidComparator(const void *arg1, const void *arg2);
79 static AclMode convert_priv_string(text *priv_type_text);
81 static Oid convert_table_name(text *tablename);
82 static AclMode convert_table_priv_string(text *priv_type_text);
83 static Oid convert_database_name(text *databasename);
84 static AclMode convert_database_priv_string(text *priv_type_text);
85 static Oid convert_function_name(text *functionname);
86 static AclMode convert_function_priv_string(text *priv_type_text);
87 static Oid convert_language_name(text *languagename);
88 static AclMode convert_language_priv_string(text *priv_type_text);
89 static Oid convert_schema_name(text *schemaname);
90 static AclMode convert_schema_priv_string(text *priv_type_text);
91 static Oid convert_tablespace_name(text *tablespacename);
92 static AclMode convert_tablespace_priv_string(text *priv_type_text);
93 static AclMode convert_role_priv_string(text *priv_type_text);
94 static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
96 static void RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
101 * Consumes the first alphanumeric string (identifier) found in string
102 * 's', ignoring any leading white space. If it finds a double quote
103 * it returns the word inside the quotes.
106 * the string position in 's' that points to the next non-space character
107 * in 's', after any quotes. Also:
108 * - loads the identifier into 'n'. (If no identifier is found, 'n'
109 * contains an empty string.) 'n' must be NAMEDATALEN bytes.
112 getid(const char *s, char *n)
115 bool in_quotes = false;
119 while (isspace((unsigned char) *s))
121 /* This code had better match what putid() does, below */
124 (isalnum((unsigned char) *s) ||
132 /* safe to look at next char (could be '\0' though) */
135 in_quotes = !in_quotes;
138 /* it's an escaped double quote; skip the escaping char */
142 /* Add the character to the string */
143 if (len >= NAMEDATALEN - 1)
145 (errcode(ERRCODE_NAME_TOO_LONG),
146 errmsg("identifier too long"),
147 errdetail("Identifier must be less than %d characters.",
153 while (isspace((unsigned char) *s))
159 * Write a role name at *p, adding double quotes if needed.
160 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
161 * This needs to be kept in sync with copyAclUserName in pg_dump/dumputils.c
164 putid(char *p, const char *s)
169 for (src = s; *src; src++)
171 /* This test had better match what getid() does, above */
172 if (!isalnum((unsigned char) *src) && *src != '_')
180 for (src = s; *src; src++)
182 /* A double quote character in a username is encoded as "" */
194 * Consumes and parses an ACL specification of the form:
195 * [group|user] [A-Za-z0-9]*=[rwaR]*
196 * from string 's', ignoring any leading white space or white space
197 * between the optional id type keyword (group|user) and the actual
200 * The group|user decoration is unnecessary in the roles world,
201 * but we still accept it for backward compatibility.
203 * This routine is called by the parser as well as aclitemin(), hence
204 * the added generality.
207 * the string position in 's' immediately following the ACL
208 * specification. Also:
209 * - loads the structure pointed to by 'aip' with the appropriate
210 * UID/GID, id type identifier and mode type values.
213 aclparse(const char *s, AclItem *aip)
218 char name[NAMEDATALEN];
219 char name2[NAMEDATALEN];
224 elog(LOG, "aclparse: input = \"%s\"", s);
229 /* we just read a keyword, not a name */
230 if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
232 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
233 errmsg("unrecognized key word: \"%s\"", name),
234 errhint("ACL key word must be \"group\" or \"user\".")));
235 s = getid(s, name); /* move s to the name beyond the keyword */
238 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
239 errmsg("missing name"),
240 errhint("A name must follow the \"group\" or \"user\" key word.")));
245 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
246 errmsg("missing \"=\" sign")));
248 privs = goption = ACL_NO_RIGHTS;
250 for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
269 case ACL_TRUNCATE_CHR:
272 case ACL_REFERENCES_CHR:
273 read = ACL_REFERENCES;
275 case ACL_TRIGGER_CHR:
278 case ACL_EXECUTE_CHR:
287 case ACL_CREATE_TEMP_CHR:
288 read = ACL_CREATE_TEMP;
290 case ACL_CONNECT_CHR:
293 case 'R': /* ignore old RULE privileges */
298 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
299 errmsg("invalid mode character: must be one of \"%s\"",
300 ACL_ALL_RIGHTS_STR)));
307 aip->ai_grantee = ACL_ID_PUBLIC;
309 aip->ai_grantee = get_roleid_checked(name);
312 * XXX Allow a degree of backward compatibility by defaulting the grantor
317 s = getid(s + 1, name2);
318 if (name2[0] == '\0')
320 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
321 errmsg("a name must follow the \"/\" sign")));
322 aip->ai_grantor = get_roleid_checked(name2);
326 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
328 (errcode(ERRCODE_INVALID_GRANTOR),
329 errmsg("defaulting grantor to user ID %u",
330 BOOTSTRAP_SUPERUSERID)));
333 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
336 elog(LOG, "aclparse: correctly read [%u %x %x]",
337 aip->ai_grantee, privs, goption);
345 * Allocates storage for a new Acl with 'n' entries.
357 elog(ERROR, "invalid size: %d", n);
358 size = ACL_N_SIZE(n);
359 new_acl = (Acl *) palloc0(size);
360 SET_VARSIZE(new_acl, size);
362 new_acl->dataoffset = 0; /* we never put in any nulls */
363 new_acl->elemtype = ACLITEMOID;
364 ARR_LBOUND(new_acl)[0] = 1;
365 ARR_DIMS(new_acl)[0] = n;
373 aclcopy(const Acl *orig_acl)
377 result_acl = allocacl(ACL_NUM(orig_acl));
379 memcpy(ACL_DAT(result_acl),
381 ACL_NUM(orig_acl) * sizeof(AclItem));
387 * Concatenate two ACLs
389 * This is a bit cheesy, since we may produce an ACL with redundant entries.
390 * Be careful what the result is used for!
393 aclconcat(const Acl *left_acl, const Acl *right_acl)
397 result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
399 memcpy(ACL_DAT(result_acl),
401 ACL_NUM(left_acl) * sizeof(AclItem));
403 memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
405 ACL_NUM(right_acl) * sizeof(AclItem));
411 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
414 check_acl(const Acl *acl)
416 if (ARR_ELEMTYPE(acl) != ACLITEMOID)
418 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
419 errmsg("ACL array contains wrong data type")));
420 if (ARR_NDIM(acl) != 1)
422 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
423 errmsg("ACL arrays must be one-dimensional")));
424 if (ARR_HASNULL(acl))
426 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
427 errmsg("ACL arrays must not contain null values")));
432 * Allocates storage for, and fills in, a new AclItem given a string
433 * 's' that contains an ACL specification. See aclparse for details.
439 aclitemin(PG_FUNCTION_ARGS)
441 const char *s = PG_GETARG_CSTRING(0);
444 aip = (AclItem *) palloc(sizeof(AclItem));
445 s = aclparse(s, aip);
446 while (isspace((unsigned char) *s))
450 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
451 errmsg("extra garbage at the end of the ACL specification")));
453 PG_RETURN_ACLITEM_P(aip);
458 * Allocates storage for, and fills in, a new null-delimited string
459 * containing a formatted ACL specification. See aclparse for details.
465 aclitemout(PG_FUNCTION_ARGS)
467 AclItem *aip = PG_GETARG_ACLITEM_P(0);
473 out = palloc(strlen("=/") +
475 2 * (2 * NAMEDATALEN + 2) +
481 if (aip->ai_grantee != ACL_ID_PUBLIC)
483 htup = SearchSysCache(AUTHOID,
484 ObjectIdGetDatum(aip->ai_grantee),
486 if (HeapTupleIsValid(htup))
488 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
489 ReleaseSysCache(htup);
493 /* Generate numeric OID if we don't find an entry */
494 sprintf(p, "%u", aip->ai_grantee);
502 for (i = 0; i < N_ACL_RIGHTS; ++i)
504 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
505 *p++ = ACL_ALL_RIGHTS_STR[i];
506 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
513 htup = SearchSysCache(AUTHOID,
514 ObjectIdGetDatum(aip->ai_grantor),
516 if (HeapTupleIsValid(htup))
518 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
519 ReleaseSysCache(htup);
523 /* Generate numeric OID if we don't find an entry */
524 sprintf(p, "%u", aip->ai_grantor);
527 PG_RETURN_CSTRING(out);
532 * Two AclItems are considered to match iff they have the same
533 * grantee and grantor; the privileges are ignored.
536 aclitem_match(const AclItem *a1, const AclItem *a2)
538 return a1->ai_grantee == a2->ai_grantee &&
539 a1->ai_grantor == a2->ai_grantor;
543 * aclitem equality operator
546 aclitem_eq(PG_FUNCTION_ARGS)
548 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
549 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
552 result = a1->ai_privs == a2->ai_privs &&
553 a1->ai_grantee == a2->ai_grantee &&
554 a1->ai_grantor == a2->ai_grantor;
555 PG_RETURN_BOOL(result);
559 * aclitem hash function
561 * We make aclitems hashable not so much because anyone is likely to hash
562 * them, as because we want array equality to work on aclitem arrays, and
563 * with the typcache mechanism we must have a hash or btree opclass.
566 hash_aclitem(PG_FUNCTION_ARGS)
568 AclItem *a = PG_GETARG_ACLITEM_P(0);
570 /* not very bright, but avoids any issue of padding in struct */
571 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
576 * acldefault() --- create an ACL describing default access permissions
578 * Change this routine if you want to alter the default access policy for
579 * newly-created objects (or any object with a NULL acl entry).
582 acldefault(GrantObjectType objtype, Oid ownerId)
584 AclMode world_default;
585 AclMode owner_default;
592 case ACL_OBJECT_COLUMN:
593 /* by default, columns have no extra privileges */
594 world_default = ACL_NO_RIGHTS;
595 owner_default = ACL_NO_RIGHTS;
597 case ACL_OBJECT_RELATION:
598 world_default = ACL_NO_RIGHTS;
599 owner_default = ACL_ALL_RIGHTS_RELATION;
601 case ACL_OBJECT_SEQUENCE:
602 world_default = ACL_NO_RIGHTS;
603 owner_default = ACL_ALL_RIGHTS_SEQUENCE;
605 case ACL_OBJECT_DATABASE:
606 /* for backwards compatibility, grant some rights by default */
607 world_default = ACL_CREATE_TEMP | ACL_CONNECT;
608 owner_default = ACL_ALL_RIGHTS_DATABASE;
610 case ACL_OBJECT_FUNCTION:
611 /* Grant EXECUTE by default, for now */
612 world_default = ACL_EXECUTE;
613 owner_default = ACL_ALL_RIGHTS_FUNCTION;
615 case ACL_OBJECT_LANGUAGE:
616 /* Grant USAGE by default, for now */
617 world_default = ACL_USAGE;
618 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
620 case ACL_OBJECT_NAMESPACE:
621 world_default = ACL_NO_RIGHTS;
622 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
624 case ACL_OBJECT_TABLESPACE:
625 world_default = ACL_NO_RIGHTS;
626 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
629 world_default = ACL_NO_RIGHTS;
630 owner_default = ACL_ALL_RIGHTS_FDW;
632 case ACL_OBJECT_FOREIGN_SERVER:
633 world_default = ACL_NO_RIGHTS;
634 owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
637 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
638 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
639 owner_default = ACL_NO_RIGHTS;
644 if (world_default != ACL_NO_RIGHTS)
646 if (owner_default != ACL_NO_RIGHTS)
649 acl = allocacl(nacl);
652 if (world_default != ACL_NO_RIGHTS)
654 aip->ai_grantee = ACL_ID_PUBLIC;
655 aip->ai_grantor = ownerId;
656 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
661 * Note that the owner's entry shows all ordinary privileges but no grant
662 * options. This is because his grant options come "from the system" and
663 * not from his own efforts. (The SQL spec says that the owner's rights
664 * come from a "_SYSTEM" authid.) However, we do consider that the
665 * owner's ordinary privileges are self-granted; this lets him revoke
666 * them. We implement the owner's grant options without any explicit
667 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
668 * whereever we are testing grant options.
670 if (owner_default != ACL_NO_RIGHTS)
672 aip->ai_grantee = ownerId;
673 aip->ai_grantor = ownerId;
674 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
682 * Update an ACL array to add or remove specified privileges.
684 * old_acl: the input ACL array
685 * mod_aip: defines the privileges to be added, removed, or substituted
686 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
687 * ownerId: Oid of object owner
688 * behavior: RESTRICT or CASCADE behavior for recursive removal
690 * ownerid and behavior are only relevant when the update operation specifies
691 * deletion of grant options.
693 * The result is a modified copy; the input object is not changed.
695 * NB: caller is responsible for having detoasted the input ACL, if needed.
698 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
699 int modechg, Oid ownerId, DropBehavior behavior)
711 /* Caller probably already checked old_acl, but be safe */
714 /* If granting grant options, check for circularity */
715 if (modechg != ACL_MODECHG_DEL &&
716 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
717 check_circularity(old_acl, mod_aip, ownerId);
719 num = ACL_NUM(old_acl);
720 old_aip = ACL_DAT(old_acl);
723 * Search the ACL for an existing entry for this grantee and grantor. If
724 * one exists, just modify the entry in-place (well, in the same position,
725 * since we actually return a copy); otherwise, insert the new entry at
729 for (dst = 0; dst < num; ++dst)
731 if (aclitem_match(mod_aip, old_aip + dst))
733 /* found a match, so modify existing item */
734 new_acl = allocacl(num);
735 new_aip = ACL_DAT(new_acl);
736 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
743 /* need to append a new item */
744 new_acl = allocacl(num + 1);
745 new_aip = ACL_DAT(new_acl);
746 memcpy(new_aip, old_aip, num * sizeof(AclItem));
748 /* initialize the new entry with no permissions */
749 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
750 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
751 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
752 ACL_NO_RIGHTS, ACL_NO_RIGHTS);
753 num++; /* set num to the size of new_acl */
756 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
757 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
759 /* apply the specified permissions change */
762 case ACL_MODECHG_ADD:
763 ACLITEM_SET_RIGHTS(new_aip[dst],
764 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
766 case ACL_MODECHG_DEL:
767 ACLITEM_SET_RIGHTS(new_aip[dst],
768 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
770 case ACL_MODECHG_EQL:
771 ACLITEM_SET_RIGHTS(new_aip[dst],
772 ACLITEM_GET_RIGHTS(*mod_aip));
776 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
777 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
780 * If the adjusted entry has no permissions, delete it from the list.
782 if (new_rights == ACL_NO_RIGHTS)
784 memmove(new_aip + dst,
786 (num - dst - 1) * sizeof(AclItem));
787 /* Adjust array size to be 'num - 1' items */
788 ARR_DIMS(new_acl)[0] = num - 1;
789 SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
793 * Remove abandoned privileges (cascading revoke). Currently we can only
794 * handle this when the grantee is not PUBLIC.
796 if ((old_goptions & ~new_goptions) != 0)
798 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
799 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
800 (old_goptions & ~new_goptions),
808 * Update an ACL array to reflect a change of owner to the parent object
810 * old_acl: the input ACL array (must not be NULL)
811 * oldOwnerId: Oid of the old object owner
812 * newOwnerId: Oid of the new object owner
814 * The result is a modified copy; the input object is not changed.
816 * NB: caller is responsible for having detoasted the input ACL, if needed.
819 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
827 bool newpresent = false;
836 * Make a copy of the given ACL, substituting new owner ID for old
837 * wherever it appears as either grantor or grantee. Also note if the new
838 * owner ID is already present.
840 num = ACL_NUM(old_acl);
841 old_aip = ACL_DAT(old_acl);
842 new_acl = allocacl(num);
843 new_aip = ACL_DAT(new_acl);
844 memcpy(new_aip, old_aip, num * sizeof(AclItem));
845 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
847 if (dst_aip->ai_grantor == oldOwnerId)
848 dst_aip->ai_grantor = newOwnerId;
849 else if (dst_aip->ai_grantor == newOwnerId)
851 if (dst_aip->ai_grantee == oldOwnerId)
852 dst_aip->ai_grantee = newOwnerId;
853 else if (dst_aip->ai_grantee == newOwnerId)
858 * If the old ACL contained any references to the new owner, then we may
859 * now have generated an ACL containing duplicate entries. Find them and
860 * merge them so that there are not duplicates. (This is relatively
861 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
862 * be the normal case.)
864 * To simplify deletion of duplicate entries, we temporarily leave them in
865 * the array but set their privilege masks to zero; when we reach such an
866 * entry it's just skipped. (Thus, a side effect of this code will be to
867 * remove privilege-free entries, should there be any in the input.) dst
868 * is the next output slot, targ is the currently considered input slot
869 * (always >= dst), and src scans entries to the right of targ looking for
870 * duplicates. Once an entry has been emitted to dst it is known
871 * duplicate-free and need not be considered anymore.
876 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
878 /* ignore if deleted in an earlier pass */
879 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
881 /* find and merge any duplicates */
882 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
885 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
887 if (aclitem_match(targ_aip, src_aip))
889 ACLITEM_SET_RIGHTS(*targ_aip,
890 ACLITEM_GET_RIGHTS(*targ_aip) |
891 ACLITEM_GET_RIGHTS(*src_aip));
892 /* mark the duplicate deleted */
893 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
896 /* and emit to output */
897 new_aip[dst] = *targ_aip;
900 /* Adjust array size to be 'dst' items */
901 ARR_DIMS(new_acl)[0] = dst;
902 SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
910 * When granting grant options, we must disallow attempts to set up circular
911 * chains of grant options. Suppose A (the object owner) grants B some
912 * privileges with grant option, and B re-grants them to C. If C could
913 * grant the privileges to B as well, then A would be unable to effectively
914 * revoke the privileges from B, since recursive_revoke would consider that
915 * B still has 'em from C.
917 * We check for this by recursively deleting all grant options belonging to
918 * the target grantee, and then seeing if the would-be grantor still has the
919 * grant option or not.
922 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
934 * For now, grant options can only be granted to roles, not PUBLIC.
935 * Otherwise we'd have to work a bit harder here.
937 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
939 /* The owner always has grant options, no need to check */
940 if (mod_aip->ai_grantor == ownerId)
943 /* Make a working copy */
944 acl = allocacl(ACL_NUM(old_acl));
945 memcpy(acl, old_acl, ACL_SIZE(old_acl));
947 /* Zap all grant options of target grantee, plus what depends on 'em */
951 for (i = 0; i < num; i++)
953 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
954 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
958 /* We'll actually zap ordinary privs too, but no matter */
959 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
960 ownerId, DROP_CASCADE);
969 /* Now we can compute grantor's independently-derived privileges */
970 own_privs = aclmask(acl,
973 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
975 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
977 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
979 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
980 errmsg("grant options cannot be granted back to your own grantor")));
987 * Ensure that no privilege is "abandoned". A privilege is abandoned
988 * if the user that granted the privilege loses the grant option. (So
989 * the chain through which it was granted is broken.) Either the
990 * abandoned privileges are revoked as well, or an error message is
991 * printed, depending on the drop behavior option.
993 * acl: the input ACL list
994 * grantee: the user from whom some grant options have been revoked
995 * revoke_privs: the grant options being revoked
996 * ownerId: Oid of object owner
997 * behavior: RESTRICT or CASCADE behavior for recursive removal
999 * The input Acl object is pfree'd if replaced.
1002 recursive_revoke(Acl *acl,
1004 AclMode revoke_privs,
1006 DropBehavior behavior)
1015 /* The owner can never truly lose grant options, so short-circuit */
1016 if (grantee == ownerId)
1019 /* The grantee might still have the privileges via another grantor */
1020 still_has = aclmask(acl, grantee, ownerId,
1021 ACL_GRANT_OPTION_FOR(revoke_privs),
1023 revoke_privs &= ~still_has;
1024 if (revoke_privs == ACL_NO_RIGHTS)
1030 for (i = 0; i < num; i++)
1032 if (aip[i].ai_grantor == grantee
1033 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1038 if (behavior == DROP_RESTRICT)
1040 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1041 errmsg("dependent privileges exist"),
1042 errhint("Use CASCADE to revoke them too.")));
1044 mod_acl.ai_grantor = grantee;
1045 mod_acl.ai_grantee = aip[i].ai_grantee;
1046 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
1050 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1065 * aclmask --- compute bitmask of all privileges held by roleid.
1067 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1068 * held by the given roleid according to the given ACL list, ANDed
1069 * with 'mask'. (The point of passing 'mask' is to let the routine
1070 * exit early if all privileges of interest have been found.)
1072 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1073 * is known true. (This lets us exit soonest in cases where the
1074 * caller is only going to test for zero or nonzero result.)
1078 * To see if any of a set of privileges are held:
1079 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1081 * To see if all of a set of privileges are held:
1082 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1084 * To determine exactly which of a set of privileges are held:
1085 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1088 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1089 AclMode mask, AclMaskHow how)
1098 * Null ACL should not happen, since caller should have inserted
1099 * appropriate default
1102 elog(ERROR, "null ACL");
1106 /* Quick exit for mask == 0 */
1112 /* Owner always implicitly has all grant options */
1113 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1114 has_privs_of_role(roleid, ownerId))
1116 result = mask & ACLITEM_ALL_GOPTION_BITS;
1117 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1122 aidat = ACL_DAT(acl);
1125 * Check privileges granted directly to roleid or to public
1127 for (i = 0; i < num; i++)
1129 AclItem *aidata = &aidat[i];
1131 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1132 aidata->ai_grantee == roleid)
1134 result |= aidata->ai_privs & mask;
1135 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1141 * Check privileges granted indirectly via role memberships. We do this in
1142 * a separate pass to minimize expensive indirect membership tests. In
1143 * particular, it's worth testing whether a given ACL entry grants any
1144 * privileges still of interest before we perform the has_privs_of_role
1147 remaining = mask & ~result;
1148 for (i = 0; i < num; i++)
1150 AclItem *aidata = &aidat[i];
1152 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1153 aidata->ai_grantee == roleid)
1154 continue; /* already checked it */
1156 if ((aidata->ai_privs & remaining) &&
1157 has_privs_of_role(roleid, aidata->ai_grantee))
1159 result |= aidata->ai_privs & mask;
1160 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1162 remaining = mask & ~result;
1171 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1173 * This is exactly like aclmask() except that we consider only privileges
1174 * held *directly* by roleid, not those inherited via role membership.
1177 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1178 AclMode mask, AclMaskHow how)
1186 * Null ACL should not happen, since caller should have inserted
1187 * appropriate default
1190 elog(ERROR, "null ACL");
1194 /* Quick exit for mask == 0 */
1200 /* Owner always implicitly has all grant options */
1201 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1204 result = mask & ACLITEM_ALL_GOPTION_BITS;
1205 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1210 aidat = ACL_DAT(acl);
1213 * Check privileges granted directly to roleid (and not to public)
1215 for (i = 0; i < num; i++)
1217 AclItem *aidata = &aidat[i];
1219 if (aidata->ai_grantee == roleid)
1221 result |= aidata->ai_privs & mask;
1222 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1233 * Find out all the roleids mentioned in an Acl.
1234 * Note that we do not distinguish grantors from grantees.
1236 * *roleids is set to point to a palloc'd array containing distinct OIDs
1237 * in sorted order. The length of the array is the function result.
1240 aclmembers(const Acl *acl, Oid **roleids)
1243 const AclItem *acldat;
1248 if (acl == NULL || ACL_NUM(acl) == 0)
1256 /* Allocate the worst-case space requirement */
1257 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1258 acldat = ACL_DAT(acl);
1261 * Walk the ACL collecting mentioned RoleIds.
1264 for (i = 0; i < ACL_NUM(acl); i++)
1266 const AclItem *ai = &acldat[i];
1268 if (ai->ai_grantee != ACL_ID_PUBLIC)
1269 list[j++] = ai->ai_grantee;
1270 /* grantor is currently never PUBLIC, but let's check anyway */
1271 if (ai->ai_grantor != ACL_ID_PUBLIC)
1272 list[j++] = ai->ai_grantor;
1275 /* Sort the array */
1276 qsort(list, j, sizeof(Oid), oidComparator);
1278 /* Remove duplicates from the array */
1280 for (i = 1; i < j; i++)
1282 if (list[k] != list[i])
1283 list[++k] = list[i];
1287 * We could repalloc the array down to minimum size, but it's hardly worth
1288 * it since it's only transient memory.
1297 * qsort comparison function for Oids
1300 oidComparator(const void *arg1, const void *arg2)
1302 Oid oid1 = *(const Oid *) arg1;
1303 Oid oid2 = *(const Oid *) arg2;
1314 * aclinsert (exported function)
1317 aclinsert(PG_FUNCTION_ARGS)
1320 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1321 errmsg("aclinsert is no longer supported")));
1323 PG_RETURN_NULL(); /* keep compiler quiet */
1327 aclremove(PG_FUNCTION_ARGS)
1330 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1331 errmsg("aclremove is no longer supported")));
1333 PG_RETURN_NULL(); /* keep compiler quiet */
1337 aclcontains(PG_FUNCTION_ARGS)
1339 Acl *acl = PG_GETARG_ACL_P(0);
1340 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1347 aidat = ACL_DAT(acl);
1348 for (i = 0; i < num; ++i)
1350 if (aip->ai_grantee == aidat[i].ai_grantee &&
1351 aip->ai_grantor == aidat[i].ai_grantor &&
1352 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1353 PG_RETURN_BOOL(true);
1355 PG_RETURN_BOOL(false);
1359 makeaclitem(PG_FUNCTION_ARGS)
1361 Oid grantee = PG_GETARG_OID(0);
1362 Oid grantor = PG_GETARG_OID(1);
1363 text *privtext = PG_GETARG_TEXT_P(2);
1364 bool goption = PG_GETARG_BOOL(3);
1368 priv = convert_priv_string(privtext);
1370 result = (AclItem *) palloc(sizeof(AclItem));
1372 result->ai_grantee = grantee;
1373 result->ai_grantor = grantor;
1375 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1376 (goption ? priv : ACL_NO_RIGHTS));
1378 PG_RETURN_ACLITEM_P(result);
1382 convert_priv_string(text *priv_type_text)
1384 char *priv_type = text_to_cstring(priv_type_text);
1386 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1388 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1390 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1392 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1394 if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
1395 return ACL_TRUNCATE;
1396 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1397 return ACL_REFERENCES;
1398 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1400 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1402 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1404 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1406 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1407 return ACL_CREATE_TEMP;
1408 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1409 return ACL_CREATE_TEMP;
1410 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1412 if (pg_strcasecmp(priv_type, "RULE") == 0)
1413 return 0; /* ignore old RULE privileges */
1416 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1417 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1418 return ACL_NO_RIGHTS; /* keep compiler quiet */
1423 * has_table_privilege variants
1424 * These are all named "has_table_privilege" at the SQL level.
1425 * They take various combinations of relation name, relation OID,
1426 * user name, user OID, or implicit user = current_user.
1428 * The result is a boolean value: true if user has the indicated
1429 * privilege, false if not. The variants that take a relation OID
1430 * return NULL if the OID doesn't exist (rather than failing, as
1431 * they did before Postgres 8.4).
1435 * has_table_privilege_name_name
1436 * Check user privileges on a table given
1437 * name username, text tablename, and text priv name.
1440 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1442 Name rolename = PG_GETARG_NAME(0);
1443 text *tablename = PG_GETARG_TEXT_P(1);
1444 text *priv_type_text = PG_GETARG_TEXT_P(2);
1448 AclResult aclresult;
1450 roleid = get_roleid_checked(NameStr(*rolename));
1451 tableoid = convert_table_name(tablename);
1452 mode = convert_table_priv_string(priv_type_text);
1454 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1456 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1460 * has_table_privilege_name
1461 * Check user privileges on a table given
1462 * text tablename and text priv name.
1463 * current_user is assumed
1466 has_table_privilege_name(PG_FUNCTION_ARGS)
1468 text *tablename = PG_GETARG_TEXT_P(0);
1469 text *priv_type_text = PG_GETARG_TEXT_P(1);
1473 AclResult aclresult;
1475 roleid = GetUserId();
1476 tableoid = convert_table_name(tablename);
1477 mode = convert_table_priv_string(priv_type_text);
1479 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1481 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1485 * has_table_privilege_name_id
1486 * Check user privileges on a table given
1487 * name usename, table oid, and text priv name.
1490 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1492 Name username = PG_GETARG_NAME(0);
1493 Oid tableoid = PG_GETARG_OID(1);
1494 text *priv_type_text = PG_GETARG_TEXT_P(2);
1497 AclResult aclresult;
1499 roleid = get_roleid_checked(NameStr(*username));
1500 mode = convert_table_priv_string(priv_type_text);
1502 if (!SearchSysCacheExists(RELOID,
1503 ObjectIdGetDatum(tableoid),
1507 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1509 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1513 * has_table_privilege_id
1514 * Check user privileges on a table given
1515 * table oid, and text priv name.
1516 * current_user is assumed
1519 has_table_privilege_id(PG_FUNCTION_ARGS)
1521 Oid tableoid = PG_GETARG_OID(0);
1522 text *priv_type_text = PG_GETARG_TEXT_P(1);
1525 AclResult aclresult;
1527 roleid = GetUserId();
1528 mode = convert_table_priv_string(priv_type_text);
1530 if (!SearchSysCacheExists(RELOID,
1531 ObjectIdGetDatum(tableoid),
1535 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1537 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1541 * has_table_privilege_id_name
1542 * Check user privileges on a table given
1543 * roleid, text tablename, and text priv name.
1546 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1548 Oid roleid = PG_GETARG_OID(0);
1549 text *tablename = PG_GETARG_TEXT_P(1);
1550 text *priv_type_text = PG_GETARG_TEXT_P(2);
1553 AclResult aclresult;
1555 tableoid = convert_table_name(tablename);
1556 mode = convert_table_priv_string(priv_type_text);
1558 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1560 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1564 * has_table_privilege_id_id
1565 * Check user privileges on a table given
1566 * roleid, table oid, and text priv name.
1569 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1571 Oid roleid = PG_GETARG_OID(0);
1572 Oid tableoid = PG_GETARG_OID(1);
1573 text *priv_type_text = PG_GETARG_TEXT_P(2);
1575 AclResult aclresult;
1577 mode = convert_table_priv_string(priv_type_text);
1579 if (!SearchSysCacheExists(RELOID,
1580 ObjectIdGetDatum(tableoid),
1584 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1586 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1590 * Support routines for has_table_privilege family.
1594 * Given a table name expressed as a string, look it up and return Oid
1597 convert_table_name(text *tablename)
1601 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1603 return RangeVarGetRelid(relrv, false);
1607 * convert_table_priv_string
1608 * Convert text string to AclMode value.
1611 convert_table_priv_string(text *priv_type_text)
1613 char *priv_type = text_to_cstring(priv_type_text);
1616 * Return mode from priv_type string
1618 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1620 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1621 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1623 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1625 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1626 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1628 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1630 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1631 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1633 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1635 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1636 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1638 if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
1639 return ACL_TRUNCATE;
1640 if (pg_strcasecmp(priv_type, "TRUNCATE WITH GRANT OPTION") == 0)
1641 return ACL_GRANT_OPTION_FOR(ACL_TRUNCATE);
1643 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1644 return ACL_REFERENCES;
1645 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1646 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1648 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1650 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1651 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1653 if (pg_strcasecmp(priv_type, "RULE") == 0)
1654 return 0; /* ignore old RULE privileges */
1655 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1659 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1660 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1661 return ACL_NO_RIGHTS; /* keep compiler quiet */
1666 * has_database_privilege variants
1667 * These are all named "has_database_privilege" at the SQL level.
1668 * They take various combinations of database name, database OID,
1669 * user name, user OID, or implicit user = current_user.
1671 * The result is a boolean value: true if user has the indicated
1672 * privilege, false if not, or NULL if object doesn't exist.
1676 * has_database_privilege_name_name
1677 * Check user privileges on a database given
1678 * name username, text databasename, and text priv name.
1681 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1683 Name username = PG_GETARG_NAME(0);
1684 text *databasename = PG_GETARG_TEXT_P(1);
1685 text *priv_type_text = PG_GETARG_TEXT_P(2);
1689 AclResult aclresult;
1691 roleid = get_roleid_checked(NameStr(*username));
1692 databaseoid = convert_database_name(databasename);
1693 mode = convert_database_priv_string(priv_type_text);
1695 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1697 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1701 * has_database_privilege_name
1702 * Check user privileges on a database given
1703 * text databasename and text priv name.
1704 * current_user is assumed
1707 has_database_privilege_name(PG_FUNCTION_ARGS)
1709 text *databasename = PG_GETARG_TEXT_P(0);
1710 text *priv_type_text = PG_GETARG_TEXT_P(1);
1714 AclResult aclresult;
1716 roleid = GetUserId();
1717 databaseoid = convert_database_name(databasename);
1718 mode = convert_database_priv_string(priv_type_text);
1720 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1722 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1726 * has_database_privilege_name_id
1727 * Check user privileges on a database given
1728 * name usename, database oid, and text priv name.
1731 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1733 Name username = PG_GETARG_NAME(0);
1734 Oid databaseoid = PG_GETARG_OID(1);
1735 text *priv_type_text = PG_GETARG_TEXT_P(2);
1738 AclResult aclresult;
1740 roleid = get_roleid_checked(NameStr(*username));
1741 mode = convert_database_priv_string(priv_type_text);
1743 if (!SearchSysCacheExists(DATABASEOID,
1744 ObjectIdGetDatum(databaseoid),
1748 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1750 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1754 * has_database_privilege_id
1755 * Check user privileges on a database given
1756 * database oid, and text priv name.
1757 * current_user is assumed
1760 has_database_privilege_id(PG_FUNCTION_ARGS)
1762 Oid databaseoid = PG_GETARG_OID(0);
1763 text *priv_type_text = PG_GETARG_TEXT_P(1);
1766 AclResult aclresult;
1768 roleid = GetUserId();
1769 mode = convert_database_priv_string(priv_type_text);
1771 if (!SearchSysCacheExists(DATABASEOID,
1772 ObjectIdGetDatum(databaseoid),
1776 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1778 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1782 * has_database_privilege_id_name
1783 * Check user privileges on a database given
1784 * roleid, text databasename, and text priv name.
1787 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1789 Oid roleid = PG_GETARG_OID(0);
1790 text *databasename = PG_GETARG_TEXT_P(1);
1791 text *priv_type_text = PG_GETARG_TEXT_P(2);
1794 AclResult aclresult;
1796 databaseoid = convert_database_name(databasename);
1797 mode = convert_database_priv_string(priv_type_text);
1799 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1801 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1805 * has_database_privilege_id_id
1806 * Check user privileges on a database given
1807 * roleid, database oid, and text priv name.
1810 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1812 Oid roleid = PG_GETARG_OID(0);
1813 Oid databaseoid = PG_GETARG_OID(1);
1814 text *priv_type_text = PG_GETARG_TEXT_P(2);
1816 AclResult aclresult;
1818 mode = convert_database_priv_string(priv_type_text);
1820 if (!SearchSysCacheExists(DATABASEOID,
1821 ObjectIdGetDatum(databaseoid),
1825 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1827 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1831 * Support routines for has_database_privilege family.
1835 * Given a database name expressed as a string, look it up and return Oid
1838 convert_database_name(text *databasename)
1840 char *dbname = text_to_cstring(databasename);
1843 oid = get_database_oid(dbname);
1844 if (!OidIsValid(oid))
1846 (errcode(ERRCODE_UNDEFINED_DATABASE),
1847 errmsg("database \"%s\" does not exist", dbname)));
1853 * convert_database_priv_string
1854 * Convert text string to AclMode value.
1857 convert_database_priv_string(text *priv_type_text)
1859 char *priv_type = text_to_cstring(priv_type_text);
1862 * Return mode from priv_type string
1864 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1866 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1867 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1869 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1870 return ACL_CREATE_TEMP;
1871 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1872 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1874 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1875 return ACL_CREATE_TEMP;
1876 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1877 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1879 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1881 if (pg_strcasecmp(priv_type, "CONNECT WITH GRANT OPTION") == 0)
1882 return ACL_GRANT_OPTION_FOR(ACL_CONNECT);
1885 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1886 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1887 return ACL_NO_RIGHTS; /* keep compiler quiet */
1892 * has_foreign_data_wrapper_privilege variants
1893 * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
1894 * They take various combinations of foreign-data wrapper name,
1895 * fdw OID, user name, user OID, or implicit user = current_user.
1897 * The result is a boolean value: true if user has the indicated
1898 * privilege, false if not. The variants that take an OID return
1899 * NULL if the OID doesn't exist.
1903 * has_foreign_data_wrapper_privilege
1904 * Check user privileges on a foreign-data wrapper.
1907 has_foreign_data_wrapper_privilege(Oid roleid, Oid fdwid, text *priv_type_text)
1909 AclResult aclresult;
1910 AclMode mode = ACL_NO_RIGHTS;
1911 char *priv_type = text_to_cstring(priv_type_text);
1913 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1915 else if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1916 mode = ACL_GRANT_OPTION_FOR(ACL_USAGE);
1919 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1920 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1922 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
1924 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1928 * has_foreign_data_wrapper_privilege_name_name
1929 * Check user privileges on a foreign-data wrapper given
1930 * name username, text fdwname, and text priv name.
1933 has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
1935 Name username = PG_GETARG_NAME(0);
1936 char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(1));
1937 text *priv_type_text = PG_GETARG_TEXT_P(2);
1939 return has_foreign_data_wrapper_privilege(get_roleid_checked(NameStr(*username)),
1940 GetForeignDataWrapperOidByName(fdwname, false),
1945 * has_foreign_data_wrapper_privilege_name
1946 * Check user privileges on a foreign-data wrapper given
1947 * text fdwname and text priv name.
1948 * current_user is assumed
1951 has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
1953 char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(0));
1954 text *priv_type_text = PG_GETARG_TEXT_P(1);
1956 return has_foreign_data_wrapper_privilege(GetUserId(),
1957 GetForeignDataWrapperOidByName(fdwname, false),
1962 * has_foreign_data_wrapper_privilege_name_id
1963 * Check user privileges on a foreign-data wrapper given
1964 * name usename, foreign-data wrapper oid, and text priv name.
1967 has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
1969 Name username = PG_GETARG_NAME(0);
1970 Oid fdwid = PG_GETARG_OID(1);
1971 text *priv_type_text = PG_GETARG_TEXT_P(2);
1973 if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
1974 ObjectIdGetDatum(fdwid),
1978 return has_foreign_data_wrapper_privilege(get_roleid_checked(NameStr(*username)),
1979 fdwid, priv_type_text);
1983 * has_foreign_data_wrapper_privilege_id
1984 * Check user privileges on a foreign-data wrapper given
1985 * foreign-data wrapper oid, and text priv name.
1986 * current_user is assumed
1989 has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
1991 Oid fdwid = PG_GETARG_OID(0);
1992 text *priv_type_text = PG_GETARG_TEXT_P(1);
1994 if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
1995 ObjectIdGetDatum(fdwid),
1999 return has_foreign_data_wrapper_privilege(GetUserId(), fdwid,
2004 * has_foreign_data_wrapper_privilege_id_name
2005 * Check user privileges on a foreign-data wrapper given
2006 * roleid, text fdwname, and text priv name.
2009 has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
2011 Oid roleid = PG_GETARG_OID(0);
2012 char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(1));
2013 text *priv_type_text = PG_GETARG_TEXT_P(2);
2015 return has_foreign_data_wrapper_privilege(roleid,
2016 GetForeignDataWrapperOidByName(fdwname, false),
2021 * has_foreign_data_wrapper_privilege_id_id
2022 * Check user privileges on a foreign-data wrapper given
2023 * roleid, fdw oid, and text priv name.
2026 has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
2028 Oid roleid = PG_GETARG_OID(0);
2029 Oid fdwid = PG_GETARG_OID(1);
2030 text *priv_type_text = PG_GETARG_TEXT_P(2);
2032 if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
2033 ObjectIdGetDatum(fdwid),
2037 return has_foreign_data_wrapper_privilege(roleid, fdwid, priv_type_text);
2042 * has_function_privilege variants
2043 * These are all named "has_function_privilege" at the SQL level.
2044 * They take various combinations of function name, function OID,
2045 * user name, user OID, or implicit user = current_user.
2047 * The result is a boolean value: true if user has the indicated
2048 * privilege, false if not, or NULL if object doesn't exist.
2052 * has_function_privilege_name_name
2053 * Check user privileges on a function given
2054 * name username, text functionname, and text priv name.
2057 has_function_privilege_name_name(PG_FUNCTION_ARGS)
2059 Name username = PG_GETARG_NAME(0);
2060 text *functionname = PG_GETARG_TEXT_P(1);
2061 text *priv_type_text = PG_GETARG_TEXT_P(2);
2065 AclResult aclresult;
2067 roleid = get_roleid_checked(NameStr(*username));
2068 functionoid = convert_function_name(functionname);
2069 mode = convert_function_priv_string(priv_type_text);
2071 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2073 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2077 * has_function_privilege_name
2078 * Check user privileges on a function given
2079 * text functionname and text priv name.
2080 * current_user is assumed
2083 has_function_privilege_name(PG_FUNCTION_ARGS)
2085 text *functionname = PG_GETARG_TEXT_P(0);
2086 text *priv_type_text = PG_GETARG_TEXT_P(1);
2090 AclResult aclresult;
2092 roleid = GetUserId();
2093 functionoid = convert_function_name(functionname);
2094 mode = convert_function_priv_string(priv_type_text);
2096 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2098 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2102 * has_function_privilege_name_id
2103 * Check user privileges on a function given
2104 * name usename, function oid, and text priv name.
2107 has_function_privilege_name_id(PG_FUNCTION_ARGS)
2109 Name username = PG_GETARG_NAME(0);
2110 Oid functionoid = PG_GETARG_OID(1);
2111 text *priv_type_text = PG_GETARG_TEXT_P(2);
2114 AclResult aclresult;
2116 roleid = get_roleid_checked(NameStr(*username));
2117 mode = convert_function_priv_string(priv_type_text);
2119 if (!SearchSysCacheExists(PROCOID,
2120 ObjectIdGetDatum(functionoid),
2124 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2126 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2130 * has_function_privilege_id
2131 * Check user privileges on a function given
2132 * function oid, and text priv name.
2133 * current_user is assumed
2136 has_function_privilege_id(PG_FUNCTION_ARGS)
2138 Oid functionoid = PG_GETARG_OID(0);
2139 text *priv_type_text = PG_GETARG_TEXT_P(1);
2142 AclResult aclresult;
2144 roleid = GetUserId();
2145 mode = convert_function_priv_string(priv_type_text);
2147 if (!SearchSysCacheExists(PROCOID,
2148 ObjectIdGetDatum(functionoid),
2152 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2154 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2158 * has_function_privilege_id_name
2159 * Check user privileges on a function given
2160 * roleid, text functionname, and text priv name.
2163 has_function_privilege_id_name(PG_FUNCTION_ARGS)
2165 Oid roleid = PG_GETARG_OID(0);
2166 text *functionname = PG_GETARG_TEXT_P(1);
2167 text *priv_type_text = PG_GETARG_TEXT_P(2);
2170 AclResult aclresult;
2172 functionoid = convert_function_name(functionname);
2173 mode = convert_function_priv_string(priv_type_text);
2175 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2177 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2181 * has_function_privilege_id_id
2182 * Check user privileges on a function given
2183 * roleid, function oid, and text priv name.
2186 has_function_privilege_id_id(PG_FUNCTION_ARGS)
2188 Oid roleid = PG_GETARG_OID(0);
2189 Oid functionoid = PG_GETARG_OID(1);
2190 text *priv_type_text = PG_GETARG_TEXT_P(2);
2192 AclResult aclresult;
2194 mode = convert_function_priv_string(priv_type_text);
2196 if (!SearchSysCacheExists(PROCOID,
2197 ObjectIdGetDatum(functionoid),
2201 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2203 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2207 * Support routines for has_function_privilege family.
2211 * Given a function name expressed as a string, look it up and return Oid
2214 convert_function_name(text *functionname)
2216 char *funcname = text_to_cstring(functionname);
2219 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
2220 CStringGetDatum(funcname)));
2222 if (!OidIsValid(oid))
2224 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2225 errmsg("function \"%s\" does not exist", funcname)));
2231 * convert_function_priv_string
2232 * Convert text string to AclMode value.
2235 convert_function_priv_string(text *priv_type_text)
2237 char *priv_type = text_to_cstring(priv_type_text);
2240 * Return mode from priv_type string
2242 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
2244 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
2245 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
2248 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2249 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2250 return ACL_NO_RIGHTS; /* keep compiler quiet */
2255 * has_language_privilege variants
2256 * These are all named "has_language_privilege" at the SQL level.
2257 * They take various combinations of language name, language OID,
2258 * user name, user OID, or implicit user = current_user.
2260 * The result is a boolean value: true if user has the indicated
2261 * privilege, false if not, or NULL if object doesn't exist.
2265 * has_language_privilege_name_name
2266 * Check user privileges on a language given
2267 * name username, text languagename, and text priv name.
2270 has_language_privilege_name_name(PG_FUNCTION_ARGS)
2272 Name username = PG_GETARG_NAME(0);
2273 text *languagename = PG_GETARG_TEXT_P(1);
2274 text *priv_type_text = PG_GETARG_TEXT_P(2);
2278 AclResult aclresult;
2280 roleid = get_roleid_checked(NameStr(*username));
2281 languageoid = convert_language_name(languagename);
2282 mode = convert_language_priv_string(priv_type_text);
2284 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2286 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2290 * has_language_privilege_name
2291 * Check user privileges on a language given
2292 * text languagename and text priv name.
2293 * current_user is assumed
2296 has_language_privilege_name(PG_FUNCTION_ARGS)
2298 text *languagename = PG_GETARG_TEXT_P(0);
2299 text *priv_type_text = PG_GETARG_TEXT_P(1);
2303 AclResult aclresult;
2305 roleid = GetUserId();
2306 languageoid = convert_language_name(languagename);
2307 mode = convert_language_priv_string(priv_type_text);
2309 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2311 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2315 * has_language_privilege_name_id
2316 * Check user privileges on a language given
2317 * name usename, language oid, and text priv name.
2320 has_language_privilege_name_id(PG_FUNCTION_ARGS)
2322 Name username = PG_GETARG_NAME(0);
2323 Oid languageoid = PG_GETARG_OID(1);
2324 text *priv_type_text = PG_GETARG_TEXT_P(2);
2327 AclResult aclresult;
2329 roleid = get_roleid_checked(NameStr(*username));
2330 mode = convert_language_priv_string(priv_type_text);
2332 if (!SearchSysCacheExists(LANGOID,
2333 ObjectIdGetDatum(languageoid),
2337 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2339 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2343 * has_language_privilege_id
2344 * Check user privileges on a language given
2345 * language oid, and text priv name.
2346 * current_user is assumed
2349 has_language_privilege_id(PG_FUNCTION_ARGS)
2351 Oid languageoid = PG_GETARG_OID(0);
2352 text *priv_type_text = PG_GETARG_TEXT_P(1);
2355 AclResult aclresult;
2357 roleid = GetUserId();
2358 mode = convert_language_priv_string(priv_type_text);
2360 if (!SearchSysCacheExists(LANGOID,
2361 ObjectIdGetDatum(languageoid),
2365 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2367 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2371 * has_language_privilege_id_name
2372 * Check user privileges on a language given
2373 * roleid, text languagename, and text priv name.
2376 has_language_privilege_id_name(PG_FUNCTION_ARGS)
2378 Oid roleid = PG_GETARG_OID(0);
2379 text *languagename = PG_GETARG_TEXT_P(1);
2380 text *priv_type_text = PG_GETARG_TEXT_P(2);
2383 AclResult aclresult;
2385 languageoid = convert_language_name(languagename);
2386 mode = convert_language_priv_string(priv_type_text);
2388 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2390 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2394 * has_language_privilege_id_id
2395 * Check user privileges on a language given
2396 * roleid, language oid, and text priv name.
2399 has_language_privilege_id_id(PG_FUNCTION_ARGS)
2401 Oid roleid = PG_GETARG_OID(0);
2402 Oid languageoid = PG_GETARG_OID(1);
2403 text *priv_type_text = PG_GETARG_TEXT_P(2);
2405 AclResult aclresult;
2407 mode = convert_language_priv_string(priv_type_text);
2409 if (!SearchSysCacheExists(LANGOID,
2410 ObjectIdGetDatum(languageoid),
2414 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2416 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2420 * Support routines for has_language_privilege family.
2424 * Given a language name expressed as a string, look it up and return Oid
2427 convert_language_name(text *languagename)
2429 char *langname = text_to_cstring(languagename);
2432 oid = GetSysCacheOid(LANGNAME,
2433 CStringGetDatum(langname),
2435 if (!OidIsValid(oid))
2437 (errcode(ERRCODE_UNDEFINED_OBJECT),
2438 errmsg("language \"%s\" does not exist", langname)));
2444 * convert_language_priv_string
2445 * Convert text string to AclMode value.
2448 convert_language_priv_string(text *priv_type_text)
2450 char *priv_type = text_to_cstring(priv_type_text);
2453 * Return mode from priv_type string
2455 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2457 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2458 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2461 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2462 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2463 return ACL_NO_RIGHTS; /* keep compiler quiet */
2468 * has_schema_privilege variants
2469 * These are all named "has_schema_privilege" at the SQL level.
2470 * They take various combinations of schema name, schema OID,
2471 * user name, user OID, or implicit user = current_user.
2473 * The result is a boolean value: true if user has the indicated
2474 * privilege, false if not, or NULL if object doesn't exist.
2478 * has_schema_privilege_name_name
2479 * Check user privileges on a schema given
2480 * name username, text schemaname, and text priv name.
2483 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2485 Name username = PG_GETARG_NAME(0);
2486 text *schemaname = PG_GETARG_TEXT_P(1);
2487 text *priv_type_text = PG_GETARG_TEXT_P(2);
2491 AclResult aclresult;
2493 roleid = get_roleid_checked(NameStr(*username));
2494 schemaoid = convert_schema_name(schemaname);
2495 mode = convert_schema_priv_string(priv_type_text);
2497 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2499 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2503 * has_schema_privilege_name
2504 * Check user privileges on a schema given
2505 * text schemaname and text priv name.
2506 * current_user is assumed
2509 has_schema_privilege_name(PG_FUNCTION_ARGS)
2511 text *schemaname = PG_GETARG_TEXT_P(0);
2512 text *priv_type_text = PG_GETARG_TEXT_P(1);
2516 AclResult aclresult;
2518 roleid = GetUserId();
2519 schemaoid = convert_schema_name(schemaname);
2520 mode = convert_schema_priv_string(priv_type_text);
2522 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2524 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2528 * has_schema_privilege_name_id
2529 * Check user privileges on a schema given
2530 * name usename, schema oid, and text priv name.
2533 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2535 Name username = PG_GETARG_NAME(0);
2536 Oid schemaoid = PG_GETARG_OID(1);
2537 text *priv_type_text = PG_GETARG_TEXT_P(2);
2540 AclResult aclresult;
2542 roleid = get_roleid_checked(NameStr(*username));
2543 mode = convert_schema_priv_string(priv_type_text);
2545 if (!SearchSysCacheExists(NAMESPACEOID,
2546 ObjectIdGetDatum(schemaoid),
2550 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2552 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2556 * has_schema_privilege_id
2557 * Check user privileges on a schema given
2558 * schema oid, and text priv name.
2559 * current_user is assumed
2562 has_schema_privilege_id(PG_FUNCTION_ARGS)
2564 Oid schemaoid = PG_GETARG_OID(0);
2565 text *priv_type_text = PG_GETARG_TEXT_P(1);
2568 AclResult aclresult;
2570 roleid = GetUserId();
2571 mode = convert_schema_priv_string(priv_type_text);
2573 if (!SearchSysCacheExists(NAMESPACEOID,
2574 ObjectIdGetDatum(schemaoid),
2578 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2580 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2584 * has_schema_privilege_id_name
2585 * Check user privileges on a schema given
2586 * roleid, text schemaname, and text priv name.
2589 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2591 Oid roleid = PG_GETARG_OID(0);
2592 text *schemaname = PG_GETARG_TEXT_P(1);
2593 text *priv_type_text = PG_GETARG_TEXT_P(2);
2596 AclResult aclresult;
2598 schemaoid = convert_schema_name(schemaname);
2599 mode = convert_schema_priv_string(priv_type_text);
2601 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2603 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2607 * has_schema_privilege_id_id
2608 * Check user privileges on a schema given
2609 * roleid, schema oid, and text priv name.
2612 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2614 Oid roleid = PG_GETARG_OID(0);
2615 Oid schemaoid = PG_GETARG_OID(1);
2616 text *priv_type_text = PG_GETARG_TEXT_P(2);
2618 AclResult aclresult;
2620 mode = convert_schema_priv_string(priv_type_text);
2622 if (!SearchSysCacheExists(NAMESPACEOID,
2623 ObjectIdGetDatum(schemaoid),
2627 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2629 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2633 * Support routines for has_schema_privilege family.
2637 * Given a schema name expressed as a string, look it up and return Oid
2640 convert_schema_name(text *schemaname)
2642 char *nspname = text_to_cstring(schemaname);
2645 oid = GetSysCacheOid(NAMESPACENAME,
2646 CStringGetDatum(nspname),
2648 if (!OidIsValid(oid))
2650 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2651 errmsg("schema \"%s\" does not exist", nspname)));
2657 * convert_schema_priv_string
2658 * Convert text string to AclMode value.
2661 convert_schema_priv_string(text *priv_type_text)
2663 char *priv_type = text_to_cstring(priv_type_text);
2666 * Return mode from priv_type string
2668 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2670 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2671 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2673 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2675 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2676 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2679 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2680 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2681 return ACL_NO_RIGHTS; /* keep compiler quiet */
2685 * has_server_privilege variants
2686 * These are all named "has_server_privilege" at the SQL level.
2687 * They take various combinations of foreign server name,
2688 * server OID, user name, user OID, or implicit user = current_user.
2690 * The result is a boolean value: true if user has the indicated
2691 * privilege, false if not.
2695 * has_server_privilege
2696 * Check user privileges on a foreign server.
2699 has_server_privilege(Oid roleid, Oid serverid, text *priv_type_text)
2701 AclResult aclresult;
2702 AclMode mode = ACL_NO_RIGHTS;
2703 char *priv_type = text_to_cstring(priv_type_text);
2705 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2707 else if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2708 mode = ACL_GRANT_OPTION_FOR(ACL_USAGE);
2711 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2712 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2714 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
2716 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2720 * has_server_privilege_name_name
2721 * Check user privileges on a foreign server given
2722 * name username, text servername, and text priv name.
2725 has_server_privilege_name_name(PG_FUNCTION_ARGS)
2727 Name username = PG_GETARG_NAME(0);
2728 char *servername = text_to_cstring(PG_GETARG_TEXT_P(1));
2729 text *priv_type_text = PG_GETARG_TEXT_P(2);
2731 return has_server_privilege(get_roleid_checked(NameStr(*username)),
2732 GetForeignServerOidByName(servername, false),
2737 * has_server_privilege_name
2738 * Check user privileges on a foreign server given
2739 * text servername and text priv name.
2740 * current_user is assumed
2743 has_server_privilege_name(PG_FUNCTION_ARGS)
2745 char *servername = text_to_cstring(PG_GETARG_TEXT_P(0));
2746 text *priv_type_text = PG_GETARG_TEXT_P(1);
2748 return has_server_privilege(GetUserId(),
2749 GetForeignServerOidByName(servername, false),
2754 * has_server_privilege_name_id
2755 * Check user privileges on a foreign server given
2756 * name usename, foreign server oid, and text priv name.
2759 has_server_privilege_name_id(PG_FUNCTION_ARGS)
2761 Name username = PG_GETARG_NAME(0);
2762 Oid serverid = PG_GETARG_OID(1);
2763 text *priv_type_text = PG_GETARG_TEXT_P(2);
2765 if (!SearchSysCacheExists(FOREIGNSERVEROID,
2766 ObjectIdGetDatum(serverid),
2770 return has_server_privilege(get_roleid_checked(NameStr(*username)), serverid,
2775 * has_server_privilege_id
2776 * Check user privileges on a foreign server given
2777 * server oid, and text priv name.
2778 * current_user is assumed
2781 has_server_privilege_id(PG_FUNCTION_ARGS)
2783 Oid serverid = PG_GETARG_OID(0);
2784 text *priv_type_text = PG_GETARG_TEXT_P(1);
2786 if (!SearchSysCacheExists(FOREIGNSERVEROID,
2787 ObjectIdGetDatum(serverid),
2791 return has_server_privilege(GetUserId(), serverid, priv_type_text);
2795 * has_server_privilege_id_name
2796 * Check user privileges on a foreign server given
2797 * roleid, text servername, and text priv name.
2800 has_server_privilege_id_name(PG_FUNCTION_ARGS)
2802 Oid roleid = PG_GETARG_OID(0);
2803 char *servername = text_to_cstring(PG_GETARG_TEXT_P(1));
2804 text *priv_type_text = PG_GETARG_TEXT_P(2);
2806 return has_server_privilege(roleid,
2807 GetForeignServerOidByName(servername, false),
2812 * has_server_privilege_id_id
2813 * Check user privileges on a foreign server given
2814 * roleid, server oid, and text priv name.
2817 has_server_privilege_id_id(PG_FUNCTION_ARGS)
2819 Oid roleid = PG_GETARG_OID(0);
2820 Oid serverid = PG_GETARG_OID(1);
2821 text *priv_type_text = PG_GETARG_TEXT_P(2);
2823 if (!SearchSysCacheExists(FOREIGNSERVEROID,
2824 ObjectIdGetDatum(serverid),
2828 return has_server_privilege(roleid, serverid, priv_type_text);
2833 * has_tablespace_privilege variants
2834 * These are all named "has_tablespace_privilege" at the SQL level.
2835 * They take various combinations of tablespace name, tablespace OID,
2836 * user name, user OID, or implicit user = current_user.
2838 * The result is a boolean value: true if user has the indicated
2839 * privilege, false if not.
2843 * has_tablespace_privilege_name_name
2844 * Check user privileges on a tablespace given
2845 * name username, text tablespacename, and text priv name.
2848 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2850 Name username = PG_GETARG_NAME(0);
2851 text *tablespacename = PG_GETARG_TEXT_P(1);
2852 text *priv_type_text = PG_GETARG_TEXT_P(2);
2856 AclResult aclresult;
2858 roleid = get_roleid_checked(NameStr(*username));
2859 tablespaceoid = convert_tablespace_name(tablespacename);
2860 mode = convert_tablespace_priv_string(priv_type_text);
2862 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2864 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2868 * has_tablespace_privilege_name
2869 * Check user privileges on a tablespace given
2870 * text tablespacename and text priv name.
2871 * current_user is assumed
2874 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2876 text *tablespacename = PG_GETARG_TEXT_P(0);
2877 text *priv_type_text = PG_GETARG_TEXT_P(1);
2881 AclResult aclresult;
2883 roleid = GetUserId();
2884 tablespaceoid = convert_tablespace_name(tablespacename);
2885 mode = convert_tablespace_priv_string(priv_type_text);
2887 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2889 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2893 * has_tablespace_privilege_name_id
2894 * Check user privileges on a tablespace given
2895 * name usename, tablespace oid, and text priv name.
2898 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2900 Name username = PG_GETARG_NAME(0);
2901 Oid tablespaceoid = PG_GETARG_OID(1);
2902 text *priv_type_text = PG_GETARG_TEXT_P(2);
2905 AclResult aclresult;
2907 roleid = get_roleid_checked(NameStr(*username));
2908 mode = convert_tablespace_priv_string(priv_type_text);
2910 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2912 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2916 * has_tablespace_privilege_id
2917 * Check user privileges on a tablespace given
2918 * tablespace oid, and text priv name.
2919 * current_user is assumed
2922 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2924 Oid tablespaceoid = PG_GETARG_OID(0);
2925 text *priv_type_text = PG_GETARG_TEXT_P(1);
2928 AclResult aclresult;
2930 roleid = GetUserId();
2931 mode = convert_tablespace_priv_string(priv_type_text);
2933 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2935 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2939 * has_tablespace_privilege_id_name
2940 * Check user privileges on a tablespace given
2941 * roleid, text tablespacename, and text priv name.
2944 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2946 Oid roleid = PG_GETARG_OID(0);
2947 text *tablespacename = PG_GETARG_TEXT_P(1);
2948 text *priv_type_text = PG_GETARG_TEXT_P(2);
2951 AclResult aclresult;
2953 tablespaceoid = convert_tablespace_name(tablespacename);
2954 mode = convert_tablespace_priv_string(priv_type_text);
2956 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2958 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2962 * has_tablespace_privilege_id_id
2963 * Check user privileges on a tablespace given
2964 * roleid, tablespace oid, and text priv name.
2967 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2969 Oid roleid = PG_GETARG_OID(0);
2970 Oid tablespaceoid = PG_GETARG_OID(1);
2971 text *priv_type_text = PG_GETARG_TEXT_P(2);
2973 AclResult aclresult;
2975 mode = convert_tablespace_priv_string(priv_type_text);
2977 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2979 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2983 * Support routines for has_tablespace_privilege family.
2987 * Given a tablespace name expressed as a string, look it up and return Oid
2990 convert_tablespace_name(text *tablespacename)
2992 char *spcname = text_to_cstring(tablespacename);
2995 oid = get_tablespace_oid(spcname);
2997 if (!OidIsValid(oid))
2999 (errcode(ERRCODE_UNDEFINED_OBJECT),
3000 errmsg("tablespace \"%s\" does not exist", spcname)));
3006 * convert_tablespace_priv_string
3007 * Convert text string to AclMode value.
3010 convert_tablespace_priv_string(text *priv_type_text)
3012 char *priv_type = text_to_cstring(priv_type_text);
3015 * Return mode from priv_type string
3017 if (pg_strcasecmp(priv_type, "CREATE") == 0)
3019 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
3020 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
3023 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3024 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
3025 return ACL_NO_RIGHTS; /* keep compiler quiet */
3029 * pg_has_role variants
3030 * These are all named "pg_has_role" at the SQL level.
3031 * They take various combinations of role name, role OID,
3032 * user name, user OID, or implicit user = current_user.
3034 * The result is a boolean value: true if user has the indicated
3035 * privilege, false if not.
3039 * pg_has_role_name_name
3040 * Check user privileges on a role given
3041 * name username, name rolename, and text priv name.
3044 pg_has_role_name_name(PG_FUNCTION_ARGS)
3046 Name username = PG_GETARG_NAME(0);
3047 Name rolename = PG_GETARG_NAME(1);
3048 text *priv_type_text = PG_GETARG_TEXT_P(2);
3052 AclResult aclresult;
3054 roleid = get_roleid_checked(NameStr(*username));
3055 roleoid = get_roleid_checked(NameStr(*rolename));
3056 mode = convert_role_priv_string(priv_type_text);
3058 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3060 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3065 * Check user privileges on a role given
3066 * name rolename and text priv name.
3067 * current_user is assumed
3070 pg_has_role_name(PG_FUNCTION_ARGS)
3072 Name rolename = PG_GETARG_NAME(0);
3073 text *priv_type_text = PG_GETARG_TEXT_P(1);
3077 AclResult aclresult;
3079 roleid = GetUserId();
3080 roleoid = get_roleid_checked(NameStr(*rolename));
3081 mode = convert_role_priv_string(priv_type_text);
3083 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3085 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3089 * pg_has_role_name_id
3090 * Check user privileges on a role given
3091 * name usename, role oid, and text priv name.
3094 pg_has_role_name_id(PG_FUNCTION_ARGS)
3096 Name username = PG_GETARG_NAME(0);
3097 Oid roleoid = PG_GETARG_OID(1);
3098 text *priv_type_text = PG_GETARG_TEXT_P(2);
3101 AclResult aclresult;
3103 roleid = get_roleid_checked(NameStr(*username));
3104 mode = convert_role_priv_string(priv_type_text);
3106 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3108 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3113 * Check user privileges on a role given
3114 * role oid, and text priv name.
3115 * current_user is assumed
3118 pg_has_role_id(PG_FUNCTION_ARGS)
3120 Oid roleoid = PG_GETARG_OID(0);
3121 text *priv_type_text = PG_GETARG_TEXT_P(1);
3124 AclResult aclresult;
3126 roleid = GetUserId();
3127 mode = convert_role_priv_string(priv_type_text);
3129 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3131 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3135 * pg_has_role_id_name
3136 * Check user privileges on a role given
3137 * roleid, name rolename, and text priv name.
3140 pg_has_role_id_name(PG_FUNCTION_ARGS)
3142 Oid roleid = PG_GETARG_OID(0);
3143 Name rolename = PG_GETARG_NAME(1);
3144 text *priv_type_text = PG_GETARG_TEXT_P(2);
3147 AclResult aclresult;
3149 roleoid = get_roleid_checked(NameStr(*rolename));
3150 mode = convert_role_priv_string(priv_type_text);
3152 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3154 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3159 * Check user privileges on a role given
3160 * roleid, role oid, and text priv name.
3163 pg_has_role_id_id(PG_FUNCTION_ARGS)
3165 Oid roleid = PG_GETARG_OID(0);
3166 Oid roleoid = PG_GETARG_OID(1);
3167 text *priv_type_text = PG_GETARG_TEXT_P(2);
3169 AclResult aclresult;
3171 mode = convert_role_priv_string(priv_type_text);
3173 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3175 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3179 * Support routines for pg_has_role family.
3183 * convert_role_priv_string
3184 * Convert text string to AclMode value.
3186 * We use USAGE to denote whether the privileges of the role are accessible
3187 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
3188 * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
3189 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
3190 * is shared only with pg_role_aclcheck, below.
3193 convert_role_priv_string(text *priv_type_text)
3195 char *priv_type = text_to_cstring(priv_type_text);
3198 * Return mode from priv_type string
3200 if (pg_strcasecmp(priv_type, "USAGE") == 0)
3202 if (pg_strcasecmp(priv_type, "MEMBER") == 0)
3204 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0 ||
3205 pg_strcasecmp(priv_type, "USAGE WITH ADMIN OPTION") == 0 ||
3206 pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0 ||
3207 pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
3208 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
3211 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3212 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
3213 return ACL_NO_RIGHTS; /* keep compiler quiet */
3218 * Quick-and-dirty support for pg_has_role
3221 pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
3223 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
3225 if (is_admin_of_role(roleid, role_oid))
3228 if (mode & ACL_CREATE)
3230 if (is_member_of_role(roleid, role_oid))
3233 if (mode & ACL_USAGE)
3235 if (has_privs_of_role(roleid, role_oid))
3238 return ACLCHECK_NO_PRIV;
3243 * initialization function (called by InitPostgres)
3246 initialize_acl(void)
3248 if (!IsBootstrapProcessingMode())
3251 * In normal mode, set a callback on any syscache invalidation of
3252 * pg_auth_members rows
3254 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
3255 RoleMembershipCacheCallback,
3261 * RoleMembershipCacheCallback
3262 * Syscache inval callback function
3265 RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
3267 /* Force membership caches to be recomputed on next use */
3268 cached_privs_role = InvalidOid;
3269 cached_member_role = InvalidOid;
3273 /* Check if specified role has rolinherit set */
3275 has_rolinherit(Oid roleid)
3277 bool result = false;
3280 utup = SearchSysCache(AUTHOID,
3281 ObjectIdGetDatum(roleid),
3283 if (HeapTupleIsValid(utup))
3285 result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
3286 ReleaseSysCache(utup);
3293 * Get a list of roles that the specified roleid has the privileges of
3295 * This is defined not to recurse through roles that don't have rolinherit
3296 * set; for such roles, membership implies the ability to do SET ROLE, but
3297 * the privileges are not available until you've done so.
3299 * Since indirect membership testing is relatively expensive, we cache
3300 * a list of memberships. Hence, the result is only guaranteed good until
3301 * the next call of roles_has_privs_of()!
3303 * For the benefit of select_best_grantor, the result is defined to be
3304 * in breadth-first order, ie, closer relationships earlier.
3307 roles_has_privs_of(Oid roleid)
3311 List *new_cached_privs_roles;
3312 MemoryContext oldctx;
3314 /* If cache is already valid, just return the list */
3315 if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
3316 return cached_privs_roles;
3319 * Find all the roles that roleid is a member of, including multi-level
3320 * recursion. The role itself will always be the first element of the
3323 * Each element of the list is scanned to see if it adds any indirect
3324 * memberships. We can use a single list as both the record of
3325 * already-found memberships and the agenda of roles yet to be scanned.
3326 * This is a bit tricky but works because the foreach() macro doesn't
3327 * fetch the next list element until the bottom of the loop.
3329 roles_list = list_make1_oid(roleid);
3331 foreach(l, roles_list)
3333 Oid memberid = lfirst_oid(l);
3337 /* Ignore non-inheriting roles */
3338 if (!has_rolinherit(memberid))
3341 /* Find roles that memberid is directly a member of */
3342 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3343 ObjectIdGetDatum(memberid),
3345 for (i = 0; i < memlist->n_members; i++)
3347 HeapTuple tup = &memlist->members[i]->tuple;
3348 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3351 * Even though there shouldn't be any loops in the membership
3352 * graph, we must test for having already seen this role. It is
3353 * legal for instance to have both A->B and A->C->B.
3355 roles_list = list_append_unique_oid(roles_list, otherid);
3357 ReleaseSysCacheList(memlist);
3361 * Copy the completed list into TopMemoryContext so it will persist.
3363 oldctx = MemoryContextSwitchTo(TopMemoryContext);
3364 new_cached_privs_roles = list_copy(roles_list);
3365 MemoryContextSwitchTo(oldctx);
3366 list_free(roles_list);
3369 * Now safe to assign to state variable
3371 cached_privs_role = InvalidOid; /* just paranoia */
3372 list_free(cached_privs_roles);
3373 cached_privs_roles = new_cached_privs_roles;
3374 cached_privs_role = roleid;
3376 /* And now we can return the answer */
3377 return cached_privs_roles;
3382 * Get a list of roles that the specified roleid is a member of
3384 * This is defined to recurse through roles regardless of rolinherit.
3386 * Since indirect membership testing is relatively expensive, we cache
3387 * a list of memberships. Hence, the result is only guaranteed good until
3388 * the next call of roles_is_member_of()!
3391 roles_is_member_of(Oid roleid)
3395 List *new_cached_membership_roles;
3396 MemoryContext oldctx;
3398 /* If cache is already valid, just return the list */
3399 if (OidIsValid(cached_member_role) && cached_member_role == roleid)
3400 return cached_membership_roles;
3403 * Find all the roles that roleid is a member of, including multi-level
3404 * recursion. The role itself will always be the first element of the
3407 * Each element of the list is scanned to see if it adds any indirect
3408 * memberships. We can use a single list as both the record of
3409 * already-found memberships and the agenda of roles yet to be scanned.
3410 * This is a bit tricky but works because the foreach() macro doesn't
3411 * fetch the next list element until the bottom of the loop.
3413 roles_list = list_make1_oid(roleid);
3415 foreach(l, roles_list)
3417 Oid memberid = lfirst_oid(l);
3421 /* Find roles that memberid is directly a member of */
3422 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3423 ObjectIdGetDatum(memberid),
3425 for (i = 0; i < memlist->n_members; i++)
3427 HeapTuple tup = &memlist->members[i]->tuple;
3428 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3431 * Even though there shouldn't be any loops in the membership
3432 * graph, we must test for having already seen this role. It is
3433 * legal for instance to have both A->B and A->C->B.
3435 roles_list = list_append_unique_oid(roles_list, otherid);
3437 ReleaseSysCacheList(memlist);
3441 * Copy the completed list into TopMemoryContext so it will persist.
3443 oldctx = MemoryContextSwitchTo(TopMemoryContext);
3444 new_cached_membership_roles = list_copy(roles_list);
3445 MemoryContextSwitchTo(oldctx);
3446 list_free(roles_list);
3449 * Now safe to assign to state variable
3451 cached_member_role = InvalidOid; /* just paranoia */
3452 list_free(cached_membership_roles);
3453 cached_membership_roles = new_cached_membership_roles;
3454 cached_member_role = roleid;
3456 /* And now we can return the answer */
3457 return cached_membership_roles;
3462 * Does member have the privileges of role (directly or indirectly)?
3464 * This is defined not to recurse through roles that don't have rolinherit
3465 * set; for such roles, membership implies the ability to do SET ROLE, but
3466 * the privileges are not available until you've done so.
3469 has_privs_of_role(Oid member, Oid role)
3471 /* Fast path for simple case */
3475 /* Superusers have every privilege, so are part of every role */
3476 if (superuser_arg(member))
3480 * Find all the roles that member has the privileges of, including
3481 * multi-level recursion, then see if target role is any one of them.
3483 return list_member_oid(roles_has_privs_of(member), role);
3488 * Is member a member of role (directly or indirectly)?
3490 * This is defined to recurse through roles regardless of rolinherit.
3493 is_member_of_role(Oid member, Oid role)
3495 /* Fast path for simple case */
3499 /* Superusers have every privilege, so are part of every role */
3500 if (superuser_arg(member))
3504 * Find all the roles that member is a member of, including multi-level
3505 * recursion, then see if target role is any one of them.
3507 return list_member_oid(roles_is_member_of(member), role);
3511 * check_is_member_of_role
3512 * is_member_of_role with a standard permission-violation error if not
3515 check_is_member_of_role(Oid member, Oid role)
3517 if (!is_member_of_role(member, role))
3519 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3520 errmsg("must be member of role \"%s\"",
3521 GetUserNameFromId(role))));
3525 * Is member a member of role, not considering superuserness?
3527 * This is identical to is_member_of_role except we ignore superuser
3531 is_member_of_role_nosuper(Oid member, Oid role)
3533 /* Fast path for simple case */
3538 * Find all the roles that member is a member of, including multi-level
3539 * recursion, then see if target role is any one of them.
3541 return list_member_oid(roles_is_member_of(member), role);
3546 * Is member an admin of role (directly or indirectly)? That is, is it
3547 * a member WITH ADMIN OPTION?
3549 * We could cache the result as for is_member_of_role, but currently this
3550 * is not used in any performance-critical paths, so we don't.
3553 is_admin_of_role(Oid member, Oid role)
3555 bool result = false;
3559 /* Fast path for simple case */
3563 /* Superusers have every privilege, so are part of every role */
3564 if (superuser_arg(member))
3568 * Find all the roles that member is a member of, including multi-level
3569 * recursion. We build a list in the same way that is_member_of_role does
3570 * to track visited and unvisited roles.
3572 roles_list = list_make1_oid(member);
3574 foreach(l, roles_list)
3576 Oid memberid = lfirst_oid(l);
3580 /* Find roles that memberid is directly a member of */
3581 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3582 ObjectIdGetDatum(memberid),
3584 for (i = 0; i < memlist->n_members; i++)
3586 HeapTuple tup = &memlist->members[i]->tuple;
3587 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3589 if (otherid == role &&
3590 ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
3592 /* Found what we came for, so can stop searching */
3597 roles_list = list_append_unique_oid(roles_list, otherid);
3599 ReleaseSysCacheList(memlist);
3604 list_free(roles_list);
3610 /* does what it says ... */
3612 count_one_bits(AclMode mask)
3616 /* this code relies on AclMode being an unsigned type */
3628 * Select the effective grantor ID for a GRANT or REVOKE operation.
3630 * The grantor must always be either the object owner or some role that has
3631 * been explicitly granted grant options. This ensures that all granted
3632 * privileges appear to flow from the object owner, and there are never
3633 * multiple "original sources" of a privilege. Therefore, if the would-be
3634 * grantor is a member of a role that has the needed grant options, we have
3635 * to do the grant as that role instead.
3637 * It is possible that the would-be grantor is a member of several roles
3638 * that have different subsets of the desired grant options, but no one
3639 * role has 'em all. In this case we pick a role with the largest number
3640 * of desired options. Ties are broken in favor of closer ancestors.
3642 * roleId: the role attempting to do the GRANT/REVOKE
3643 * privileges: the privileges to be granted/revoked
3644 * acl: the ACL of the object in question
3645 * ownerId: the role owning the object in question
3646 * *grantorId: receives the OID of the role to do the grant as
3647 * *grantOptions: receives the grant options actually held by grantorId
3649 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
3652 select_best_grantor(Oid roleId, AclMode privileges,
3653 const Acl *acl, Oid ownerId,
3654 Oid *grantorId, AclMode *grantOptions)
3656 AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
3662 * The object owner is always treated as having all grant options, so if
3663 * roleId is the owner it's easy. Also, if roleId is a superuser it's
3664 * easy: superusers are implicitly members of every role, so they act as
3667 if (roleId == ownerId || superuser_arg(roleId))
3669 *grantorId = ownerId;
3670 *grantOptions = needed_goptions;
3675 * Otherwise we have to do a careful search to see if roleId has the
3676 * privileges of any suitable role. Note: we can hang onto the result of
3677 * roles_has_privs_of() throughout this loop, because aclmask_direct()
3678 * doesn't query any role memberships.
3680 roles_list = roles_has_privs_of(roleId);
3682 /* initialize candidate result as default */
3683 *grantorId = roleId;
3684 *grantOptions = ACL_NO_RIGHTS;
3687 foreach(l, roles_list)
3689 Oid otherrole = lfirst_oid(l);
3692 otherprivs = aclmask_direct(acl, otherrole, ownerId,
3693 needed_goptions, ACLMASK_ALL);
3694 if (otherprivs == needed_goptions)
3696 /* Found a suitable grantor */
3697 *grantorId = otherrole;
3698 *grantOptions = otherprivs;
3703 * If it has just some of the needed privileges, remember best
3706 if (otherprivs != ACL_NO_RIGHTS)
3708 int nnewrights = count_one_bits(otherprivs);
3710 if (nnewrights > nrights)
3712 *grantorId = otherrole;
3713 *grantOptions = otherprivs;
3714 nrights = nnewrights;