1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2008, 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.144 2008/12/19 16:25:17 petere 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;
370 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
373 check_acl(const Acl *acl)
375 if (ARR_ELEMTYPE(acl) != ACLITEMOID)
377 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
378 errmsg("ACL array contains wrong data type")));
379 if (ARR_NDIM(acl) != 1)
381 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
382 errmsg("ACL arrays must be one-dimensional")));
383 if (ARR_HASNULL(acl))
385 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
386 errmsg("ACL arrays must not contain null values")));
391 * Allocates storage for, and fills in, a new AclItem given a string
392 * 's' that contains an ACL specification. See aclparse for details.
398 aclitemin(PG_FUNCTION_ARGS)
400 const char *s = PG_GETARG_CSTRING(0);
403 aip = (AclItem *) palloc(sizeof(AclItem));
404 s = aclparse(s, aip);
405 while (isspace((unsigned char) *s))
409 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
410 errmsg("extra garbage at the end of the ACL specification")));
412 PG_RETURN_ACLITEM_P(aip);
417 * Allocates storage for, and fills in, a new null-delimited string
418 * containing a formatted ACL specification. See aclparse for details.
424 aclitemout(PG_FUNCTION_ARGS)
426 AclItem *aip = PG_GETARG_ACLITEM_P(0);
432 out = palloc(strlen("=/") +
434 2 * (2 * NAMEDATALEN + 2) +
440 if (aip->ai_grantee != ACL_ID_PUBLIC)
442 htup = SearchSysCache(AUTHOID,
443 ObjectIdGetDatum(aip->ai_grantee),
445 if (HeapTupleIsValid(htup))
447 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
448 ReleaseSysCache(htup);
452 /* Generate numeric OID if we don't find an entry */
453 sprintf(p, "%u", aip->ai_grantee);
461 for (i = 0; i < N_ACL_RIGHTS; ++i)
463 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
464 *p++ = ACL_ALL_RIGHTS_STR[i];
465 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
472 htup = SearchSysCache(AUTHOID,
473 ObjectIdGetDatum(aip->ai_grantor),
475 if (HeapTupleIsValid(htup))
477 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
478 ReleaseSysCache(htup);
482 /* Generate numeric OID if we don't find an entry */
483 sprintf(p, "%u", aip->ai_grantor);
486 PG_RETURN_CSTRING(out);
491 * Two AclItems are considered to match iff they have the same
492 * grantee and grantor; the privileges are ignored.
495 aclitem_match(const AclItem *a1, const AclItem *a2)
497 return a1->ai_grantee == a2->ai_grantee &&
498 a1->ai_grantor == a2->ai_grantor;
502 * aclitem equality operator
505 aclitem_eq(PG_FUNCTION_ARGS)
507 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
508 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
511 result = a1->ai_privs == a2->ai_privs &&
512 a1->ai_grantee == a2->ai_grantee &&
513 a1->ai_grantor == a2->ai_grantor;
514 PG_RETURN_BOOL(result);
518 * aclitem hash function
520 * We make aclitems hashable not so much because anyone is likely to hash
521 * them, as because we want array equality to work on aclitem arrays, and
522 * with the typcache mechanism we must have a hash or btree opclass.
525 hash_aclitem(PG_FUNCTION_ARGS)
527 AclItem *a = PG_GETARG_ACLITEM_P(0);
529 /* not very bright, but avoids any issue of padding in struct */
530 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
535 * acldefault() --- create an ACL describing default access permissions
537 * Change this routine if you want to alter the default access policy for
538 * newly-created objects (or any object with a NULL acl entry).
541 acldefault(GrantObjectType objtype, Oid ownerId)
543 AclMode world_default;
544 AclMode owner_default;
550 case ACL_OBJECT_RELATION:
551 world_default = ACL_NO_RIGHTS;
552 owner_default = ACL_ALL_RIGHTS_RELATION;
554 case ACL_OBJECT_SEQUENCE:
555 world_default = ACL_NO_RIGHTS;
556 owner_default = ACL_ALL_RIGHTS_SEQUENCE;
558 case ACL_OBJECT_DATABASE:
559 /* for backwards compatibility, grant some rights by default */
560 world_default = ACL_CREATE_TEMP | ACL_CONNECT;
561 owner_default = ACL_ALL_RIGHTS_DATABASE;
563 case ACL_OBJECT_FUNCTION:
564 /* Grant EXECUTE by default, for now */
565 world_default = ACL_EXECUTE;
566 owner_default = ACL_ALL_RIGHTS_FUNCTION;
568 case ACL_OBJECT_LANGUAGE:
569 /* Grant USAGE by default, for now */
570 world_default = ACL_USAGE;
571 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
573 case ACL_OBJECT_NAMESPACE:
574 world_default = ACL_NO_RIGHTS;
575 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
577 case ACL_OBJECT_TABLESPACE:
578 world_default = ACL_NO_RIGHTS;
579 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
582 world_default = ACL_NO_RIGHTS;
583 owner_default = ACL_ALL_RIGHTS_FDW;
585 case ACL_OBJECT_FOREIGN_SERVER:
586 world_default = ACL_NO_RIGHTS;
587 owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
590 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
591 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
592 owner_default = ACL_NO_RIGHTS;
596 acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);
599 if (world_default != ACL_NO_RIGHTS)
601 aip->ai_grantee = ACL_ID_PUBLIC;
602 aip->ai_grantor = ownerId;
603 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
608 * Note that the owner's entry shows all ordinary privileges but no grant
609 * options. This is because his grant options come "from the system" and
610 * not from his own efforts. (The SQL spec says that the owner's rights
611 * come from a "_SYSTEM" authid.) However, we do consider that the
612 * owner's ordinary privileges are self-granted; this lets him revoke
613 * them. We implement the owner's grant options without any explicit
614 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
615 * whereever we are testing grant options.
617 aip->ai_grantee = ownerId;
618 aip->ai_grantor = ownerId;
619 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
626 * Update an ACL array to add or remove specified privileges.
628 * old_acl: the input ACL array
629 * mod_aip: defines the privileges to be added, removed, or substituted
630 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
631 * ownerId: Oid of object owner
632 * behavior: RESTRICT or CASCADE behavior for recursive removal
634 * ownerid and behavior are only relevant when the update operation specifies
635 * deletion of grant options.
637 * The result is a modified copy; the input object is not changed.
639 * NB: caller is responsible for having detoasted the input ACL, if needed.
642 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
643 int modechg, Oid ownerId, DropBehavior behavior)
655 /* Caller probably already checked old_acl, but be safe */
658 /* If granting grant options, check for circularity */
659 if (modechg != ACL_MODECHG_DEL &&
660 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
661 check_circularity(old_acl, mod_aip, ownerId);
663 num = ACL_NUM(old_acl);
664 old_aip = ACL_DAT(old_acl);
667 * Search the ACL for an existing entry for this grantee and grantor. If
668 * one exists, just modify the entry in-place (well, in the same position,
669 * since we actually return a copy); otherwise, insert the new entry at
673 for (dst = 0; dst < num; ++dst)
675 if (aclitem_match(mod_aip, old_aip + dst))
677 /* found a match, so modify existing item */
678 new_acl = allocacl(num);
679 new_aip = ACL_DAT(new_acl);
680 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
687 /* need to append a new item */
688 new_acl = allocacl(num + 1);
689 new_aip = ACL_DAT(new_acl);
690 memcpy(new_aip, old_aip, num * sizeof(AclItem));
692 /* initialize the new entry with no permissions */
693 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
694 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
695 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
696 ACL_NO_RIGHTS, ACL_NO_RIGHTS);
697 num++; /* set num to the size of new_acl */
700 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
701 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
703 /* apply the specified permissions change */
706 case ACL_MODECHG_ADD:
707 ACLITEM_SET_RIGHTS(new_aip[dst],
708 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
710 case ACL_MODECHG_DEL:
711 ACLITEM_SET_RIGHTS(new_aip[dst],
712 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
714 case ACL_MODECHG_EQL:
715 ACLITEM_SET_RIGHTS(new_aip[dst],
716 ACLITEM_GET_RIGHTS(*mod_aip));
720 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
721 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
724 * If the adjusted entry has no permissions, delete it from the list.
726 if (new_rights == ACL_NO_RIGHTS)
728 memmove(new_aip + dst,
730 (num - dst - 1) * sizeof(AclItem));
731 /* Adjust array size to be 'num - 1' items */
732 ARR_DIMS(new_acl)[0] = num - 1;
733 SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
737 * Remove abandoned privileges (cascading revoke). Currently we can only
738 * handle this when the grantee is not PUBLIC.
740 if ((old_goptions & ~new_goptions) != 0)
742 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
743 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
744 (old_goptions & ~new_goptions),
752 * Update an ACL array to reflect a change of owner to the parent object
754 * old_acl: the input ACL array (must not be NULL)
755 * oldOwnerId: Oid of the old object owner
756 * newOwnerId: Oid of the new object owner
758 * The result is a modified copy; the input object is not changed.
760 * NB: caller is responsible for having detoasted the input ACL, if needed.
763 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
771 bool newpresent = false;
780 * Make a copy of the given ACL, substituting new owner ID for old
781 * wherever it appears as either grantor or grantee. Also note if the new
782 * owner ID is already present.
784 num = ACL_NUM(old_acl);
785 old_aip = ACL_DAT(old_acl);
786 new_acl = allocacl(num);
787 new_aip = ACL_DAT(new_acl);
788 memcpy(new_aip, old_aip, num * sizeof(AclItem));
789 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
791 if (dst_aip->ai_grantor == oldOwnerId)
792 dst_aip->ai_grantor = newOwnerId;
793 else if (dst_aip->ai_grantor == newOwnerId)
795 if (dst_aip->ai_grantee == oldOwnerId)
796 dst_aip->ai_grantee = newOwnerId;
797 else if (dst_aip->ai_grantee == newOwnerId)
802 * If the old ACL contained any references to the new owner, then we may
803 * now have generated an ACL containing duplicate entries. Find them and
804 * merge them so that there are not duplicates. (This is relatively
805 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
806 * be the normal case.)
808 * To simplify deletion of duplicate entries, we temporarily leave them in
809 * the array but set their privilege masks to zero; when we reach such an
810 * entry it's just skipped. (Thus, a side effect of this code will be to
811 * remove privilege-free entries, should there be any in the input.) dst
812 * is the next output slot, targ is the currently considered input slot
813 * (always >= dst), and src scans entries to the right of targ looking for
814 * duplicates. Once an entry has been emitted to dst it is known
815 * duplicate-free and need not be considered anymore.
820 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
822 /* ignore if deleted in an earlier pass */
823 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
825 /* find and merge any duplicates */
826 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
829 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
831 if (aclitem_match(targ_aip, src_aip))
833 ACLITEM_SET_RIGHTS(*targ_aip,
834 ACLITEM_GET_RIGHTS(*targ_aip) |
835 ACLITEM_GET_RIGHTS(*src_aip));
836 /* mark the duplicate deleted */
837 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
840 /* and emit to output */
841 new_aip[dst] = *targ_aip;
844 /* Adjust array size to be 'dst' items */
845 ARR_DIMS(new_acl)[0] = dst;
846 SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
854 * When granting grant options, we must disallow attempts to set up circular
855 * chains of grant options. Suppose A (the object owner) grants B some
856 * privileges with grant option, and B re-grants them to C. If C could
857 * grant the privileges to B as well, then A would be unable to effectively
858 * revoke the privileges from B, since recursive_revoke would consider that
859 * B still has 'em from C.
861 * We check for this by recursively deleting all grant options belonging to
862 * the target grantee, and then seeing if the would-be grantor still has the
863 * grant option or not.
866 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
878 * For now, grant options can only be granted to roles, not PUBLIC.
879 * Otherwise we'd have to work a bit harder here.
881 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
883 /* The owner always has grant options, no need to check */
884 if (mod_aip->ai_grantor == ownerId)
887 /* Make a working copy */
888 acl = allocacl(ACL_NUM(old_acl));
889 memcpy(acl, old_acl, ACL_SIZE(old_acl));
891 /* Zap all grant options of target grantee, plus what depends on 'em */
895 for (i = 0; i < num; i++)
897 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
898 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
902 /* We'll actually zap ordinary privs too, but no matter */
903 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
904 ownerId, DROP_CASCADE);
913 /* Now we can compute grantor's independently-derived privileges */
914 own_privs = aclmask(acl,
917 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
919 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
921 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
923 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
924 errmsg("grant options cannot be granted back to your own grantor")));
931 * Ensure that no privilege is "abandoned". A privilege is abandoned
932 * if the user that granted the privilege loses the grant option. (So
933 * the chain through which it was granted is broken.) Either the
934 * abandoned privileges are revoked as well, or an error message is
935 * printed, depending on the drop behavior option.
937 * acl: the input ACL list
938 * grantee: the user from whom some grant options have been revoked
939 * revoke_privs: the grant options being revoked
940 * ownerId: Oid of object owner
941 * behavior: RESTRICT or CASCADE behavior for recursive removal
943 * The input Acl object is pfree'd if replaced.
946 recursive_revoke(Acl *acl,
948 AclMode revoke_privs,
950 DropBehavior behavior)
959 /* The owner can never truly lose grant options, so short-circuit */
960 if (grantee == ownerId)
963 /* The grantee might still have the privileges via another grantor */
964 still_has = aclmask(acl, grantee, ownerId,
965 ACL_GRANT_OPTION_FOR(revoke_privs),
967 revoke_privs &= ~still_has;
968 if (revoke_privs == ACL_NO_RIGHTS)
974 for (i = 0; i < num; i++)
976 if (aip[i].ai_grantor == grantee
977 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
982 if (behavior == DROP_RESTRICT)
984 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
985 errmsg("dependent privileges exist"),
986 errhint("Use CASCADE to revoke them too.")));
988 mod_acl.ai_grantor = grantee;
989 mod_acl.ai_grantee = aip[i].ai_grantee;
990 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
994 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1009 * aclmask --- compute bitmask of all privileges held by roleid.
1011 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1012 * held by the given roleid according to the given ACL list, ANDed
1013 * with 'mask'. (The point of passing 'mask' is to let the routine
1014 * exit early if all privileges of interest have been found.)
1016 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1017 * is known true. (This lets us exit soonest in cases where the
1018 * caller is only going to test for zero or nonzero result.)
1022 * To see if any of a set of privileges are held:
1023 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1025 * To see if all of a set of privileges are held:
1026 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1028 * To determine exactly which of a set of privileges are held:
1029 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1032 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1033 AclMode mask, AclMaskHow how)
1042 * Null ACL should not happen, since caller should have inserted
1043 * appropriate default
1046 elog(ERROR, "null ACL");
1050 /* Quick exit for mask == 0 */
1056 /* Owner always implicitly has all grant options */
1057 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1058 has_privs_of_role(roleid, ownerId))
1060 result = mask & ACLITEM_ALL_GOPTION_BITS;
1061 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1066 aidat = ACL_DAT(acl);
1069 * Check privileges granted directly to roleid or to public
1071 for (i = 0; i < num; i++)
1073 AclItem *aidata = &aidat[i];
1075 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1076 aidata->ai_grantee == roleid)
1078 result |= aidata->ai_privs & mask;
1079 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1085 * Check privileges granted indirectly via role memberships. We do this in
1086 * a separate pass to minimize expensive indirect membership tests. In
1087 * particular, it's worth testing whether a given ACL entry grants any
1088 * privileges still of interest before we perform the has_privs_of_role
1091 remaining = mask & ~result;
1092 for (i = 0; i < num; i++)
1094 AclItem *aidata = &aidat[i];
1096 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1097 aidata->ai_grantee == roleid)
1098 continue; /* already checked it */
1100 if ((aidata->ai_privs & remaining) &&
1101 has_privs_of_role(roleid, aidata->ai_grantee))
1103 result |= aidata->ai_privs & mask;
1104 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1106 remaining = mask & ~result;
1115 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1117 * This is exactly like aclmask() except that we consider only privileges
1118 * held *directly* by roleid, not those inherited via role membership.
1121 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1122 AclMode mask, AclMaskHow how)
1130 * Null ACL should not happen, since caller should have inserted
1131 * appropriate default
1134 elog(ERROR, "null ACL");
1138 /* Quick exit for mask == 0 */
1144 /* Owner always implicitly has all grant options */
1145 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1148 result = mask & ACLITEM_ALL_GOPTION_BITS;
1149 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1154 aidat = ACL_DAT(acl);
1157 * Check privileges granted directly to roleid (and not to public)
1159 for (i = 0; i < num; i++)
1161 AclItem *aidata = &aidat[i];
1163 if (aidata->ai_grantee == roleid)
1165 result |= aidata->ai_privs & mask;
1166 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1177 * Find out all the roleids mentioned in an Acl.
1178 * Note that we do not distinguish grantors from grantees.
1180 * *roleids is set to point to a palloc'd array containing distinct OIDs
1181 * in sorted order. The length of the array is the function result.
1184 aclmembers(const Acl *acl, Oid **roleids)
1187 const AclItem *acldat;
1192 if (acl == NULL || ACL_NUM(acl) == 0)
1200 /* Allocate the worst-case space requirement */
1201 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1202 acldat = ACL_DAT(acl);
1205 * Walk the ACL collecting mentioned RoleIds.
1208 for (i = 0; i < ACL_NUM(acl); i++)
1210 const AclItem *ai = &acldat[i];
1212 if (ai->ai_grantee != ACL_ID_PUBLIC)
1213 list[j++] = ai->ai_grantee;
1214 /* grantor is currently never PUBLIC, but let's check anyway */
1215 if (ai->ai_grantor != ACL_ID_PUBLIC)
1216 list[j++] = ai->ai_grantor;
1219 /* Sort the array */
1220 qsort(list, j, sizeof(Oid), oidComparator);
1222 /* Remove duplicates from the array */
1224 for (i = 1; i < j; i++)
1226 if (list[k] != list[i])
1227 list[++k] = list[i];
1231 * We could repalloc the array down to minimum size, but it's hardly worth
1232 * it since it's only transient memory.
1241 * qsort comparison function for Oids
1244 oidComparator(const void *arg1, const void *arg2)
1246 Oid oid1 = *(const Oid *) arg1;
1247 Oid oid2 = *(const Oid *) arg2;
1258 * aclinsert (exported function)
1261 aclinsert(PG_FUNCTION_ARGS)
1264 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1265 errmsg("aclinsert is no longer supported")));
1267 PG_RETURN_NULL(); /* keep compiler quiet */
1271 aclremove(PG_FUNCTION_ARGS)
1274 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1275 errmsg("aclremove is no longer supported")));
1277 PG_RETURN_NULL(); /* keep compiler quiet */
1281 aclcontains(PG_FUNCTION_ARGS)
1283 Acl *acl = PG_GETARG_ACL_P(0);
1284 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1291 aidat = ACL_DAT(acl);
1292 for (i = 0; i < num; ++i)
1294 if (aip->ai_grantee == aidat[i].ai_grantee &&
1295 aip->ai_grantor == aidat[i].ai_grantor &&
1296 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1297 PG_RETURN_BOOL(true);
1299 PG_RETURN_BOOL(false);
1303 makeaclitem(PG_FUNCTION_ARGS)
1305 Oid grantee = PG_GETARG_OID(0);
1306 Oid grantor = PG_GETARG_OID(1);
1307 text *privtext = PG_GETARG_TEXT_P(2);
1308 bool goption = PG_GETARG_BOOL(3);
1312 priv = convert_priv_string(privtext);
1314 result = (AclItem *) palloc(sizeof(AclItem));
1316 result->ai_grantee = grantee;
1317 result->ai_grantor = grantor;
1319 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1320 (goption ? priv : ACL_NO_RIGHTS));
1322 PG_RETURN_ACLITEM_P(result);
1326 convert_priv_string(text *priv_type_text)
1328 char *priv_type = text_to_cstring(priv_type_text);
1330 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1332 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1334 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1336 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1338 if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
1339 return ACL_TRUNCATE;
1340 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1341 return ACL_REFERENCES;
1342 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1344 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1346 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1348 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1350 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1351 return ACL_CREATE_TEMP;
1352 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1353 return ACL_CREATE_TEMP;
1354 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1356 if (pg_strcasecmp(priv_type, "RULE") == 0)
1357 return 0; /* ignore old RULE privileges */
1360 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1361 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1362 return ACL_NO_RIGHTS; /* keep compiler quiet */
1367 * has_table_privilege variants
1368 * These are all named "has_table_privilege" at the SQL level.
1369 * They take various combinations of relation name, relation OID,
1370 * user name, user OID, or implicit user = current_user.
1372 * The result is a boolean value: true if user has the indicated
1373 * privilege, false if not. The variants that take a relation OID
1374 * return NULL if the OID doesn't exist (rather than failing, as
1375 * they did before Postgres 8.4).
1379 * has_table_privilege_name_name
1380 * Check user privileges on a table given
1381 * name username, text tablename, and text priv name.
1384 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1386 Name rolename = PG_GETARG_NAME(0);
1387 text *tablename = PG_GETARG_TEXT_P(1);
1388 text *priv_type_text = PG_GETARG_TEXT_P(2);
1392 AclResult aclresult;
1394 roleid = get_roleid_checked(NameStr(*rolename));
1395 tableoid = convert_table_name(tablename);
1396 mode = convert_table_priv_string(priv_type_text);
1398 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1400 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1404 * has_table_privilege_name
1405 * Check user privileges on a table given
1406 * text tablename and text priv name.
1407 * current_user is assumed
1410 has_table_privilege_name(PG_FUNCTION_ARGS)
1412 text *tablename = PG_GETARG_TEXT_P(0);
1413 text *priv_type_text = PG_GETARG_TEXT_P(1);
1417 AclResult aclresult;
1419 roleid = GetUserId();
1420 tableoid = convert_table_name(tablename);
1421 mode = convert_table_priv_string(priv_type_text);
1423 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1425 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1429 * has_table_privilege_name_id
1430 * Check user privileges on a table given
1431 * name usename, table oid, and text priv name.
1434 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1436 Name username = PG_GETARG_NAME(0);
1437 Oid tableoid = PG_GETARG_OID(1);
1438 text *priv_type_text = PG_GETARG_TEXT_P(2);
1441 AclResult aclresult;
1443 roleid = get_roleid_checked(NameStr(*username));
1444 mode = convert_table_priv_string(priv_type_text);
1446 if (!SearchSysCacheExists(RELOID,
1447 ObjectIdGetDatum(tableoid),
1451 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1453 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1457 * has_table_privilege_id
1458 * Check user privileges on a table given
1459 * table oid, and text priv name.
1460 * current_user is assumed
1463 has_table_privilege_id(PG_FUNCTION_ARGS)
1465 Oid tableoid = PG_GETARG_OID(0);
1466 text *priv_type_text = PG_GETARG_TEXT_P(1);
1469 AclResult aclresult;
1471 roleid = GetUserId();
1472 mode = convert_table_priv_string(priv_type_text);
1474 if (!SearchSysCacheExists(RELOID,
1475 ObjectIdGetDatum(tableoid),
1479 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1481 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1485 * has_table_privilege_id_name
1486 * Check user privileges on a table given
1487 * roleid, text tablename, and text priv name.
1490 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1492 Oid roleid = PG_GETARG_OID(0);
1493 text *tablename = PG_GETARG_TEXT_P(1);
1494 text *priv_type_text = PG_GETARG_TEXT_P(2);
1497 AclResult aclresult;
1499 tableoid = convert_table_name(tablename);
1500 mode = convert_table_priv_string(priv_type_text);
1502 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1504 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1508 * has_table_privilege_id_id
1509 * Check user privileges on a table given
1510 * roleid, table oid, and text priv name.
1513 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1515 Oid roleid = PG_GETARG_OID(0);
1516 Oid tableoid = PG_GETARG_OID(1);
1517 text *priv_type_text = PG_GETARG_TEXT_P(2);
1519 AclResult aclresult;
1521 mode = convert_table_priv_string(priv_type_text);
1523 if (!SearchSysCacheExists(RELOID,
1524 ObjectIdGetDatum(tableoid),
1528 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1530 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1534 * Support routines for has_table_privilege family.
1538 * Given a table name expressed as a string, look it up and return Oid
1541 convert_table_name(text *tablename)
1545 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1547 return RangeVarGetRelid(relrv, false);
1551 * convert_table_priv_string
1552 * Convert text string to AclMode value.
1555 convert_table_priv_string(text *priv_type_text)
1557 char *priv_type = text_to_cstring(priv_type_text);
1560 * Return mode from priv_type string
1562 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1564 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1565 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1567 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1569 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1570 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1572 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1574 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1575 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1577 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1579 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1580 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1582 if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
1583 return ACL_TRUNCATE;
1584 if (pg_strcasecmp(priv_type, "TRUNCATE WITH GRANT OPTION") == 0)
1585 return ACL_GRANT_OPTION_FOR(ACL_TRUNCATE);
1587 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1588 return ACL_REFERENCES;
1589 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1590 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1592 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1594 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1595 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1597 if (pg_strcasecmp(priv_type, "RULE") == 0)
1598 return 0; /* ignore old RULE privileges */
1599 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1603 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1604 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1605 return ACL_NO_RIGHTS; /* keep compiler quiet */
1610 * has_database_privilege variants
1611 * These are all named "has_database_privilege" at the SQL level.
1612 * They take various combinations of database name, database OID,
1613 * user name, user OID, or implicit user = current_user.
1615 * The result is a boolean value: true if user has the indicated
1616 * privilege, false if not, or NULL if object doesn't exist.
1620 * has_database_privilege_name_name
1621 * Check user privileges on a database given
1622 * name username, text databasename, and text priv name.
1625 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1627 Name username = PG_GETARG_NAME(0);
1628 text *databasename = PG_GETARG_TEXT_P(1);
1629 text *priv_type_text = PG_GETARG_TEXT_P(2);
1633 AclResult aclresult;
1635 roleid = get_roleid_checked(NameStr(*username));
1636 databaseoid = convert_database_name(databasename);
1637 mode = convert_database_priv_string(priv_type_text);
1639 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1641 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1645 * has_database_privilege_name
1646 * Check user privileges on a database given
1647 * text databasename and text priv name.
1648 * current_user is assumed
1651 has_database_privilege_name(PG_FUNCTION_ARGS)
1653 text *databasename = PG_GETARG_TEXT_P(0);
1654 text *priv_type_text = PG_GETARG_TEXT_P(1);
1658 AclResult aclresult;
1660 roleid = GetUserId();
1661 databaseoid = convert_database_name(databasename);
1662 mode = convert_database_priv_string(priv_type_text);
1664 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1666 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1670 * has_database_privilege_name_id
1671 * Check user privileges on a database given
1672 * name usename, database oid, and text priv name.
1675 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1677 Name username = PG_GETARG_NAME(0);
1678 Oid databaseoid = PG_GETARG_OID(1);
1679 text *priv_type_text = PG_GETARG_TEXT_P(2);
1682 AclResult aclresult;
1684 roleid = get_roleid_checked(NameStr(*username));
1685 mode = convert_database_priv_string(priv_type_text);
1687 if (!SearchSysCacheExists(DATABASEOID,
1688 ObjectIdGetDatum(databaseoid),
1692 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1694 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1698 * has_database_privilege_id
1699 * Check user privileges on a database given
1700 * database oid, and text priv name.
1701 * current_user is assumed
1704 has_database_privilege_id(PG_FUNCTION_ARGS)
1706 Oid databaseoid = PG_GETARG_OID(0);
1707 text *priv_type_text = PG_GETARG_TEXT_P(1);
1710 AclResult aclresult;
1712 roleid = GetUserId();
1713 mode = convert_database_priv_string(priv_type_text);
1715 if (!SearchSysCacheExists(DATABASEOID,
1716 ObjectIdGetDatum(databaseoid),
1720 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1722 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1726 * has_database_privilege_id_name
1727 * Check user privileges on a database given
1728 * roleid, text databasename, and text priv name.
1731 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1733 Oid roleid = PG_GETARG_OID(0);
1734 text *databasename = PG_GETARG_TEXT_P(1);
1735 text *priv_type_text = PG_GETARG_TEXT_P(2);
1738 AclResult aclresult;
1740 databaseoid = convert_database_name(databasename);
1741 mode = convert_database_priv_string(priv_type_text);
1743 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1745 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1749 * has_database_privilege_id_id
1750 * Check user privileges on a database given
1751 * roleid, database oid, and text priv name.
1754 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1756 Oid roleid = PG_GETARG_OID(0);
1757 Oid databaseoid = PG_GETARG_OID(1);
1758 text *priv_type_text = PG_GETARG_TEXT_P(2);
1760 AclResult aclresult;
1762 mode = convert_database_priv_string(priv_type_text);
1764 if (!SearchSysCacheExists(DATABASEOID,
1765 ObjectIdGetDatum(databaseoid),
1769 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1771 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1775 * Support routines for has_database_privilege family.
1779 * Given a database name expressed as a string, look it up and return Oid
1782 convert_database_name(text *databasename)
1784 char *dbname = text_to_cstring(databasename);
1787 oid = get_database_oid(dbname);
1788 if (!OidIsValid(oid))
1790 (errcode(ERRCODE_UNDEFINED_DATABASE),
1791 errmsg("database \"%s\" does not exist", dbname)));
1797 * convert_database_priv_string
1798 * Convert text string to AclMode value.
1801 convert_database_priv_string(text *priv_type_text)
1803 char *priv_type = text_to_cstring(priv_type_text);
1806 * Return mode from priv_type string
1808 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1810 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1811 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1813 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1814 return ACL_CREATE_TEMP;
1815 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1816 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1818 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1819 return ACL_CREATE_TEMP;
1820 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1821 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1823 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1825 if (pg_strcasecmp(priv_type, "CONNECT WITH GRANT OPTION") == 0)
1826 return ACL_GRANT_OPTION_FOR(ACL_CONNECT);
1829 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1830 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1831 return ACL_NO_RIGHTS; /* keep compiler quiet */
1836 * has_foreign_data_wrapper_privilege variants
1837 * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
1838 * They take various combinations of foreign-data wrapper name,
1839 * fdw OID, user name, user OID, or implicit user = current_user.
1841 * The result is a boolean value: true if user has the indicated
1842 * privilege, false if not. The variants that take an OID return
1843 * NULL if the OID doesn't exist.
1847 * has_foreign_data_wrapper_privilege
1848 * Check user privileges on a foreign-data wrapper.
1851 has_foreign_data_wrapper_privilege(Oid roleid, Oid fdwid, text *priv_type_text)
1853 AclResult aclresult;
1854 AclMode mode = ACL_NO_RIGHTS;
1855 char *priv_type = text_to_cstring(priv_type_text);
1857 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1859 else if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1860 mode = ACL_GRANT_OPTION_FOR(ACL_USAGE);
1863 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1864 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1866 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
1868 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1872 * has_foreign_data_wrapper_privilege_name_name
1873 * Check user privileges on a foreign-data wrapper given
1874 * name username, text fdwname, and text priv name.
1877 has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
1879 Name username = PG_GETARG_NAME(0);
1880 char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(1));
1881 text *priv_type_text = PG_GETARG_TEXT_P(2);
1883 return has_foreign_data_wrapper_privilege(get_roleid_checked(NameStr(*username)),
1884 GetForeignDataWrapperOidByName(fdwname, false),
1889 * has_foreign_data_wrapper_privilege_name
1890 * Check user privileges on a foreign-data wrapper given
1891 * text fdwname and text priv name.
1892 * current_user is assumed
1895 has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
1897 char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(0));
1898 text *priv_type_text = PG_GETARG_TEXT_P(1);
1900 return has_foreign_data_wrapper_privilege(GetUserId(),
1901 GetForeignDataWrapperOidByName(fdwname, false),
1906 * has_foreign_data_wrapper_privilege_name_id
1907 * Check user privileges on a foreign-data wrapper given
1908 * name usename, foreign-data wrapper oid, and text priv name.
1911 has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
1913 Name username = PG_GETARG_NAME(0);
1914 Oid fdwid = PG_GETARG_OID(1);
1915 text *priv_type_text = PG_GETARG_TEXT_P(2);
1917 if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
1918 ObjectIdGetDatum(fdwid),
1922 return has_foreign_data_wrapper_privilege(get_roleid_checked(NameStr(*username)),
1923 fdwid, priv_type_text);
1927 * has_foreign_data_wrapper_privilege_id
1928 * Check user privileges on a foreign-data wrapper given
1929 * foreign-data wrapper oid, and text priv name.
1930 * current_user is assumed
1933 has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
1935 Oid fdwid = PG_GETARG_OID(0);
1936 text *priv_type_text = PG_GETARG_TEXT_P(1);
1938 if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
1939 ObjectIdGetDatum(fdwid),
1943 return has_foreign_data_wrapper_privilege(GetUserId(), fdwid,
1948 * has_foreign_data_wrapper_privilege_id_name
1949 * Check user privileges on a foreign-data wrapper given
1950 * roleid, text fdwname, and text priv name.
1953 has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
1955 Oid roleid = PG_GETARG_OID(0);
1956 char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(1));
1957 text *priv_type_text = PG_GETARG_TEXT_P(2);
1959 return has_foreign_data_wrapper_privilege(roleid,
1960 GetForeignDataWrapperOidByName(fdwname, false),
1965 * has_foreign_data_wrapper_privilege_id_id
1966 * Check user privileges on a foreign-data wrapper given
1967 * roleid, fdw oid, and text priv name.
1970 has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
1972 Oid roleid = PG_GETARG_OID(0);
1973 Oid fdwid = PG_GETARG_OID(1);
1974 text *priv_type_text = PG_GETARG_TEXT_P(2);
1976 if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
1977 ObjectIdGetDatum(fdwid),
1981 return has_foreign_data_wrapper_privilege(roleid, fdwid, priv_type_text);
1986 * has_function_privilege variants
1987 * These are all named "has_function_privilege" at the SQL level.
1988 * They take various combinations of function name, function OID,
1989 * user name, user OID, or implicit user = current_user.
1991 * The result is a boolean value: true if user has the indicated
1992 * privilege, false if not, or NULL if object doesn't exist.
1996 * has_function_privilege_name_name
1997 * Check user privileges on a function given
1998 * name username, text functionname, and text priv name.
2001 has_function_privilege_name_name(PG_FUNCTION_ARGS)
2003 Name username = PG_GETARG_NAME(0);
2004 text *functionname = PG_GETARG_TEXT_P(1);
2005 text *priv_type_text = PG_GETARG_TEXT_P(2);
2009 AclResult aclresult;
2011 roleid = get_roleid_checked(NameStr(*username));
2012 functionoid = convert_function_name(functionname);
2013 mode = convert_function_priv_string(priv_type_text);
2015 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2017 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2021 * has_function_privilege_name
2022 * Check user privileges on a function given
2023 * text functionname and text priv name.
2024 * current_user is assumed
2027 has_function_privilege_name(PG_FUNCTION_ARGS)
2029 text *functionname = PG_GETARG_TEXT_P(0);
2030 text *priv_type_text = PG_GETARG_TEXT_P(1);
2034 AclResult aclresult;
2036 roleid = GetUserId();
2037 functionoid = convert_function_name(functionname);
2038 mode = convert_function_priv_string(priv_type_text);
2040 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2042 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2046 * has_function_privilege_name_id
2047 * Check user privileges on a function given
2048 * name usename, function oid, and text priv name.
2051 has_function_privilege_name_id(PG_FUNCTION_ARGS)
2053 Name username = PG_GETARG_NAME(0);
2054 Oid functionoid = PG_GETARG_OID(1);
2055 text *priv_type_text = PG_GETARG_TEXT_P(2);
2058 AclResult aclresult;
2060 roleid = get_roleid_checked(NameStr(*username));
2061 mode = convert_function_priv_string(priv_type_text);
2063 if (!SearchSysCacheExists(PROCOID,
2064 ObjectIdGetDatum(functionoid),
2068 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2070 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2074 * has_function_privilege_id
2075 * Check user privileges on a function given
2076 * function oid, and text priv name.
2077 * current_user is assumed
2080 has_function_privilege_id(PG_FUNCTION_ARGS)
2082 Oid functionoid = PG_GETARG_OID(0);
2083 text *priv_type_text = PG_GETARG_TEXT_P(1);
2086 AclResult aclresult;
2088 roleid = GetUserId();
2089 mode = convert_function_priv_string(priv_type_text);
2091 if (!SearchSysCacheExists(PROCOID,
2092 ObjectIdGetDatum(functionoid),
2096 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2098 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2102 * has_function_privilege_id_name
2103 * Check user privileges on a function given
2104 * roleid, text functionname, and text priv name.
2107 has_function_privilege_id_name(PG_FUNCTION_ARGS)
2109 Oid roleid = PG_GETARG_OID(0);
2110 text *functionname = PG_GETARG_TEXT_P(1);
2111 text *priv_type_text = PG_GETARG_TEXT_P(2);
2114 AclResult aclresult;
2116 functionoid = convert_function_name(functionname);
2117 mode = convert_function_priv_string(priv_type_text);
2119 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2121 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2125 * has_function_privilege_id_id
2126 * Check user privileges on a function given
2127 * roleid, function oid, and text priv name.
2130 has_function_privilege_id_id(PG_FUNCTION_ARGS)
2132 Oid roleid = PG_GETARG_OID(0);
2133 Oid functionoid = PG_GETARG_OID(1);
2134 text *priv_type_text = PG_GETARG_TEXT_P(2);
2136 AclResult aclresult;
2138 mode = convert_function_priv_string(priv_type_text);
2140 if (!SearchSysCacheExists(PROCOID,
2141 ObjectIdGetDatum(functionoid),
2145 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2147 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2151 * Support routines for has_function_privilege family.
2155 * Given a function name expressed as a string, look it up and return Oid
2158 convert_function_name(text *functionname)
2160 char *funcname = text_to_cstring(functionname);
2163 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
2164 CStringGetDatum(funcname)));
2166 if (!OidIsValid(oid))
2168 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2169 errmsg("function \"%s\" does not exist", funcname)));
2175 * convert_function_priv_string
2176 * Convert text string to AclMode value.
2179 convert_function_priv_string(text *priv_type_text)
2181 char *priv_type = text_to_cstring(priv_type_text);
2184 * Return mode from priv_type string
2186 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
2188 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
2189 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
2192 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2193 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2194 return ACL_NO_RIGHTS; /* keep compiler quiet */
2199 * has_language_privilege variants
2200 * These are all named "has_language_privilege" at the SQL level.
2201 * They take various combinations of language name, language OID,
2202 * user name, user OID, or implicit user = current_user.
2204 * The result is a boolean value: true if user has the indicated
2205 * privilege, false if not, or NULL if object doesn't exist.
2209 * has_language_privilege_name_name
2210 * Check user privileges on a language given
2211 * name username, text languagename, and text priv name.
2214 has_language_privilege_name_name(PG_FUNCTION_ARGS)
2216 Name username = PG_GETARG_NAME(0);
2217 text *languagename = PG_GETARG_TEXT_P(1);
2218 text *priv_type_text = PG_GETARG_TEXT_P(2);
2222 AclResult aclresult;
2224 roleid = get_roleid_checked(NameStr(*username));
2225 languageoid = convert_language_name(languagename);
2226 mode = convert_language_priv_string(priv_type_text);
2228 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2230 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2234 * has_language_privilege_name
2235 * Check user privileges on a language given
2236 * text languagename and text priv name.
2237 * current_user is assumed
2240 has_language_privilege_name(PG_FUNCTION_ARGS)
2242 text *languagename = PG_GETARG_TEXT_P(0);
2243 text *priv_type_text = PG_GETARG_TEXT_P(1);
2247 AclResult aclresult;
2249 roleid = GetUserId();
2250 languageoid = convert_language_name(languagename);
2251 mode = convert_language_priv_string(priv_type_text);
2253 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2255 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2259 * has_language_privilege_name_id
2260 * Check user privileges on a language given
2261 * name usename, language oid, and text priv name.
2264 has_language_privilege_name_id(PG_FUNCTION_ARGS)
2266 Name username = PG_GETARG_NAME(0);
2267 Oid languageoid = PG_GETARG_OID(1);
2268 text *priv_type_text = PG_GETARG_TEXT_P(2);
2271 AclResult aclresult;
2273 roleid = get_roleid_checked(NameStr(*username));
2274 mode = convert_language_priv_string(priv_type_text);
2276 if (!SearchSysCacheExists(LANGOID,
2277 ObjectIdGetDatum(languageoid),
2281 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2283 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2287 * has_language_privilege_id
2288 * Check user privileges on a language given
2289 * language oid, and text priv name.
2290 * current_user is assumed
2293 has_language_privilege_id(PG_FUNCTION_ARGS)
2295 Oid languageoid = PG_GETARG_OID(0);
2296 text *priv_type_text = PG_GETARG_TEXT_P(1);
2299 AclResult aclresult;
2301 roleid = GetUserId();
2302 mode = convert_language_priv_string(priv_type_text);
2304 if (!SearchSysCacheExists(LANGOID,
2305 ObjectIdGetDatum(languageoid),
2309 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2311 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2315 * has_language_privilege_id_name
2316 * Check user privileges on a language given
2317 * roleid, text languagename, and text priv name.
2320 has_language_privilege_id_name(PG_FUNCTION_ARGS)
2322 Oid roleid = PG_GETARG_OID(0);
2323 text *languagename = PG_GETARG_TEXT_P(1);
2324 text *priv_type_text = PG_GETARG_TEXT_P(2);
2327 AclResult aclresult;
2329 languageoid = convert_language_name(languagename);
2330 mode = convert_language_priv_string(priv_type_text);
2332 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2334 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2338 * has_language_privilege_id_id
2339 * Check user privileges on a language given
2340 * roleid, language oid, and text priv name.
2343 has_language_privilege_id_id(PG_FUNCTION_ARGS)
2345 Oid roleid = PG_GETARG_OID(0);
2346 Oid languageoid = PG_GETARG_OID(1);
2347 text *priv_type_text = PG_GETARG_TEXT_P(2);
2349 AclResult aclresult;
2351 mode = convert_language_priv_string(priv_type_text);
2353 if (!SearchSysCacheExists(LANGOID,
2354 ObjectIdGetDatum(languageoid),
2358 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2360 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2364 * Support routines for has_language_privilege family.
2368 * Given a language name expressed as a string, look it up and return Oid
2371 convert_language_name(text *languagename)
2373 char *langname = text_to_cstring(languagename);
2376 oid = GetSysCacheOid(LANGNAME,
2377 CStringGetDatum(langname),
2379 if (!OidIsValid(oid))
2381 (errcode(ERRCODE_UNDEFINED_OBJECT),
2382 errmsg("language \"%s\" does not exist", langname)));
2388 * convert_language_priv_string
2389 * Convert text string to AclMode value.
2392 convert_language_priv_string(text *priv_type_text)
2394 char *priv_type = text_to_cstring(priv_type_text);
2397 * Return mode from priv_type string
2399 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2401 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2402 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2405 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2406 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2407 return ACL_NO_RIGHTS; /* keep compiler quiet */
2412 * has_schema_privilege variants
2413 * These are all named "has_schema_privilege" at the SQL level.
2414 * They take various combinations of schema name, schema OID,
2415 * user name, user OID, or implicit user = current_user.
2417 * The result is a boolean value: true if user has the indicated
2418 * privilege, false if not, or NULL if object doesn't exist.
2422 * has_schema_privilege_name_name
2423 * Check user privileges on a schema given
2424 * name username, text schemaname, and text priv name.
2427 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2429 Name username = PG_GETARG_NAME(0);
2430 text *schemaname = PG_GETARG_TEXT_P(1);
2431 text *priv_type_text = PG_GETARG_TEXT_P(2);
2435 AclResult aclresult;
2437 roleid = get_roleid_checked(NameStr(*username));
2438 schemaoid = convert_schema_name(schemaname);
2439 mode = convert_schema_priv_string(priv_type_text);
2441 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2443 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2447 * has_schema_privilege_name
2448 * Check user privileges on a schema given
2449 * text schemaname and text priv name.
2450 * current_user is assumed
2453 has_schema_privilege_name(PG_FUNCTION_ARGS)
2455 text *schemaname = PG_GETARG_TEXT_P(0);
2456 text *priv_type_text = PG_GETARG_TEXT_P(1);
2460 AclResult aclresult;
2462 roleid = GetUserId();
2463 schemaoid = convert_schema_name(schemaname);
2464 mode = convert_schema_priv_string(priv_type_text);
2466 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2468 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2472 * has_schema_privilege_name_id
2473 * Check user privileges on a schema given
2474 * name usename, schema oid, and text priv name.
2477 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2479 Name username = PG_GETARG_NAME(0);
2480 Oid schemaoid = PG_GETARG_OID(1);
2481 text *priv_type_text = PG_GETARG_TEXT_P(2);
2484 AclResult aclresult;
2486 roleid = get_roleid_checked(NameStr(*username));
2487 mode = convert_schema_priv_string(priv_type_text);
2489 if (!SearchSysCacheExists(NAMESPACEOID,
2490 ObjectIdGetDatum(schemaoid),
2494 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2496 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2500 * has_schema_privilege_id
2501 * Check user privileges on a schema given
2502 * schema oid, and text priv name.
2503 * current_user is assumed
2506 has_schema_privilege_id(PG_FUNCTION_ARGS)
2508 Oid schemaoid = PG_GETARG_OID(0);
2509 text *priv_type_text = PG_GETARG_TEXT_P(1);
2512 AclResult aclresult;
2514 roleid = GetUserId();
2515 mode = convert_schema_priv_string(priv_type_text);
2517 if (!SearchSysCacheExists(NAMESPACEOID,
2518 ObjectIdGetDatum(schemaoid),
2522 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2524 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2528 * has_schema_privilege_id_name
2529 * Check user privileges on a schema given
2530 * roleid, text schemaname, and text priv name.
2533 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2535 Oid roleid = PG_GETARG_OID(0);
2536 text *schemaname = PG_GETARG_TEXT_P(1);
2537 text *priv_type_text = PG_GETARG_TEXT_P(2);
2540 AclResult aclresult;
2542 schemaoid = convert_schema_name(schemaname);
2543 mode = convert_schema_priv_string(priv_type_text);
2545 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2547 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2551 * has_schema_privilege_id_id
2552 * Check user privileges on a schema given
2553 * roleid, schema oid, and text priv name.
2556 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2558 Oid roleid = PG_GETARG_OID(0);
2559 Oid schemaoid = PG_GETARG_OID(1);
2560 text *priv_type_text = PG_GETARG_TEXT_P(2);
2562 AclResult aclresult;
2564 mode = convert_schema_priv_string(priv_type_text);
2566 if (!SearchSysCacheExists(NAMESPACEOID,
2567 ObjectIdGetDatum(schemaoid),
2571 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2573 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2577 * Support routines for has_schema_privilege family.
2581 * Given a schema name expressed as a string, look it up and return Oid
2584 convert_schema_name(text *schemaname)
2586 char *nspname = text_to_cstring(schemaname);
2589 oid = GetSysCacheOid(NAMESPACENAME,
2590 CStringGetDatum(nspname),
2592 if (!OidIsValid(oid))
2594 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2595 errmsg("schema \"%s\" does not exist", nspname)));
2601 * convert_schema_priv_string
2602 * Convert text string to AclMode value.
2605 convert_schema_priv_string(text *priv_type_text)
2607 char *priv_type = text_to_cstring(priv_type_text);
2610 * Return mode from priv_type string
2612 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2614 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2615 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2617 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2619 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2620 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2623 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2624 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2625 return ACL_NO_RIGHTS; /* keep compiler quiet */
2629 * has_server_privilege variants
2630 * These are all named "has_server_privilege" at the SQL level.
2631 * They take various combinations of foreign server name,
2632 * server OID, user name, user OID, or implicit user = current_user.
2634 * The result is a boolean value: true if user has the indicated
2635 * privilege, false if not.
2639 * has_server_privilege
2640 * Check user privileges on a foreign server.
2643 has_server_privilege(Oid roleid, Oid serverid, text *priv_type_text)
2645 AclResult aclresult;
2646 AclMode mode = ACL_NO_RIGHTS;
2647 char *priv_type = text_to_cstring(priv_type_text);
2649 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2651 else if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2652 mode = ACL_GRANT_OPTION_FOR(ACL_USAGE);
2655 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2656 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2658 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
2660 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2664 * has_server_privilege_name_name
2665 * Check user privileges on a foreign server given
2666 * name username, text servername, and text priv name.
2669 has_server_privilege_name_name(PG_FUNCTION_ARGS)
2671 Name username = PG_GETARG_NAME(0);
2672 char *servername = text_to_cstring(PG_GETARG_TEXT_P(1));
2673 text *priv_type_text = PG_GETARG_TEXT_P(2);
2675 return has_server_privilege(get_roleid_checked(NameStr(*username)),
2676 GetForeignServerOidByName(servername, false),
2681 * has_server_privilege_name
2682 * Check user privileges on a foreign server given
2683 * text servername and text priv name.
2684 * current_user is assumed
2687 has_server_privilege_name(PG_FUNCTION_ARGS)
2689 char *servername = text_to_cstring(PG_GETARG_TEXT_P(0));
2690 text *priv_type_text = PG_GETARG_TEXT_P(1);
2692 return has_server_privilege(GetUserId(),
2693 GetForeignServerOidByName(servername, false),
2698 * has_server_privilege_name_id
2699 * Check user privileges on a foreign server given
2700 * name usename, foreign server oid, and text priv name.
2703 has_server_privilege_name_id(PG_FUNCTION_ARGS)
2705 Name username = PG_GETARG_NAME(0);
2706 Oid serverid = PG_GETARG_OID(1);
2707 text *priv_type_text = PG_GETARG_TEXT_P(2);
2709 if (!SearchSysCacheExists(FOREIGNSERVEROID,
2710 ObjectIdGetDatum(serverid),
2714 return has_server_privilege(get_roleid_checked(NameStr(*username)), serverid,
2719 * has_server_privilege_id
2720 * Check user privileges on a foreign server given
2721 * server oid, and text priv name.
2722 * current_user is assumed
2725 has_server_privilege_id(PG_FUNCTION_ARGS)
2727 Oid serverid = PG_GETARG_OID(0);
2728 text *priv_type_text = PG_GETARG_TEXT_P(1);
2730 if (!SearchSysCacheExists(FOREIGNSERVEROID,
2731 ObjectIdGetDatum(serverid),
2735 return has_server_privilege(GetUserId(), serverid, priv_type_text);
2739 * has_server_privilege_id_name
2740 * Check user privileges on a foreign server given
2741 * roleid, text servername, and text priv name.
2744 has_server_privilege_id_name(PG_FUNCTION_ARGS)
2746 Oid roleid = PG_GETARG_OID(0);
2747 char *servername = text_to_cstring(PG_GETARG_TEXT_P(1));
2748 text *priv_type_text = PG_GETARG_TEXT_P(2);
2750 return has_server_privilege(roleid,
2751 GetForeignServerOidByName(servername, false),
2756 * has_server_privilege_id_id
2757 * Check user privileges on a foreign server given
2758 * roleid, server oid, and text priv name.
2761 has_server_privilege_id_id(PG_FUNCTION_ARGS)
2763 Oid roleid = PG_GETARG_OID(0);
2764 Oid serverid = PG_GETARG_OID(1);
2765 text *priv_type_text = PG_GETARG_TEXT_P(2);
2767 if (!SearchSysCacheExists(FOREIGNSERVEROID,
2768 ObjectIdGetDatum(serverid),
2772 return has_server_privilege(roleid, serverid, priv_type_text);
2777 * has_tablespace_privilege variants
2778 * These are all named "has_tablespace_privilege" at the SQL level.
2779 * They take various combinations of tablespace name, tablespace OID,
2780 * user name, user OID, or implicit user = current_user.
2782 * The result is a boolean value: true if user has the indicated
2783 * privilege, false if not.
2787 * has_tablespace_privilege_name_name
2788 * Check user privileges on a tablespace given
2789 * name username, text tablespacename, and text priv name.
2792 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2794 Name username = PG_GETARG_NAME(0);
2795 text *tablespacename = PG_GETARG_TEXT_P(1);
2796 text *priv_type_text = PG_GETARG_TEXT_P(2);
2800 AclResult aclresult;
2802 roleid = get_roleid_checked(NameStr(*username));
2803 tablespaceoid = convert_tablespace_name(tablespacename);
2804 mode = convert_tablespace_priv_string(priv_type_text);
2806 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2808 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2812 * has_tablespace_privilege_name
2813 * Check user privileges on a tablespace given
2814 * text tablespacename and text priv name.
2815 * current_user is assumed
2818 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2820 text *tablespacename = PG_GETARG_TEXT_P(0);
2821 text *priv_type_text = PG_GETARG_TEXT_P(1);
2825 AclResult aclresult;
2827 roleid = GetUserId();
2828 tablespaceoid = convert_tablespace_name(tablespacename);
2829 mode = convert_tablespace_priv_string(priv_type_text);
2831 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2833 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2837 * has_tablespace_privilege_name_id
2838 * Check user privileges on a tablespace given
2839 * name usename, tablespace oid, and text priv name.
2842 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2844 Name username = PG_GETARG_NAME(0);
2845 Oid tablespaceoid = PG_GETARG_OID(1);
2846 text *priv_type_text = PG_GETARG_TEXT_P(2);
2849 AclResult aclresult;
2851 roleid = get_roleid_checked(NameStr(*username));
2852 mode = convert_tablespace_priv_string(priv_type_text);
2854 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2856 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2860 * has_tablespace_privilege_id
2861 * Check user privileges on a tablespace given
2862 * tablespace oid, and text priv name.
2863 * current_user is assumed
2866 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2868 Oid tablespaceoid = PG_GETARG_OID(0);
2869 text *priv_type_text = PG_GETARG_TEXT_P(1);
2872 AclResult aclresult;
2874 roleid = GetUserId();
2875 mode = convert_tablespace_priv_string(priv_type_text);
2877 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2879 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2883 * has_tablespace_privilege_id_name
2884 * Check user privileges on a tablespace given
2885 * roleid, text tablespacename, and text priv name.
2888 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2890 Oid roleid = PG_GETARG_OID(0);
2891 text *tablespacename = PG_GETARG_TEXT_P(1);
2892 text *priv_type_text = PG_GETARG_TEXT_P(2);
2895 AclResult aclresult;
2897 tablespaceoid = convert_tablespace_name(tablespacename);
2898 mode = convert_tablespace_priv_string(priv_type_text);
2900 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2902 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2906 * has_tablespace_privilege_id_id
2907 * Check user privileges on a tablespace given
2908 * roleid, tablespace oid, and text priv name.
2911 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2913 Oid roleid = PG_GETARG_OID(0);
2914 Oid tablespaceoid = PG_GETARG_OID(1);
2915 text *priv_type_text = PG_GETARG_TEXT_P(2);
2917 AclResult aclresult;
2919 mode = convert_tablespace_priv_string(priv_type_text);
2921 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2923 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2927 * Support routines for has_tablespace_privilege family.
2931 * Given a tablespace name expressed as a string, look it up and return Oid
2934 convert_tablespace_name(text *tablespacename)
2936 char *spcname = text_to_cstring(tablespacename);
2939 oid = get_tablespace_oid(spcname);
2941 if (!OidIsValid(oid))
2943 (errcode(ERRCODE_UNDEFINED_OBJECT),
2944 errmsg("tablespace \"%s\" does not exist", spcname)));
2950 * convert_tablespace_priv_string
2951 * Convert text string to AclMode value.
2954 convert_tablespace_priv_string(text *priv_type_text)
2956 char *priv_type = text_to_cstring(priv_type_text);
2959 * Return mode from priv_type string
2961 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2963 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2964 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2967 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2968 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2969 return ACL_NO_RIGHTS; /* keep compiler quiet */
2973 * pg_has_role variants
2974 * These are all named "pg_has_role" at the SQL level.
2975 * They take various combinations of role name, role OID,
2976 * user name, user OID, or implicit user = current_user.
2978 * The result is a boolean value: true if user has the indicated
2979 * privilege, false if not.
2983 * pg_has_role_name_name
2984 * Check user privileges on a role given
2985 * name username, name rolename, and text priv name.
2988 pg_has_role_name_name(PG_FUNCTION_ARGS)
2990 Name username = PG_GETARG_NAME(0);
2991 Name rolename = PG_GETARG_NAME(1);
2992 text *priv_type_text = PG_GETARG_TEXT_P(2);
2996 AclResult aclresult;
2998 roleid = get_roleid_checked(NameStr(*username));
2999 roleoid = get_roleid_checked(NameStr(*rolename));
3000 mode = convert_role_priv_string(priv_type_text);
3002 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3004 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3009 * Check user privileges on a role given
3010 * name rolename and text priv name.
3011 * current_user is assumed
3014 pg_has_role_name(PG_FUNCTION_ARGS)
3016 Name rolename = PG_GETARG_NAME(0);
3017 text *priv_type_text = PG_GETARG_TEXT_P(1);
3021 AclResult aclresult;
3023 roleid = GetUserId();
3024 roleoid = get_roleid_checked(NameStr(*rolename));
3025 mode = convert_role_priv_string(priv_type_text);
3027 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3029 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3033 * pg_has_role_name_id
3034 * Check user privileges on a role given
3035 * name usename, role oid, and text priv name.
3038 pg_has_role_name_id(PG_FUNCTION_ARGS)
3040 Name username = PG_GETARG_NAME(0);
3041 Oid roleoid = PG_GETARG_OID(1);
3042 text *priv_type_text = PG_GETARG_TEXT_P(2);
3045 AclResult aclresult;
3047 roleid = get_roleid_checked(NameStr(*username));
3048 mode = convert_role_priv_string(priv_type_text);
3050 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3052 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3057 * Check user privileges on a role given
3058 * role oid, and text priv name.
3059 * current_user is assumed
3062 pg_has_role_id(PG_FUNCTION_ARGS)
3064 Oid roleoid = PG_GETARG_OID(0);
3065 text *priv_type_text = PG_GETARG_TEXT_P(1);
3068 AclResult aclresult;
3070 roleid = GetUserId();
3071 mode = convert_role_priv_string(priv_type_text);
3073 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3075 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3079 * pg_has_role_id_name
3080 * Check user privileges on a role given
3081 * roleid, name rolename, and text priv name.
3084 pg_has_role_id_name(PG_FUNCTION_ARGS)
3086 Oid roleid = PG_GETARG_OID(0);
3087 Name rolename = PG_GETARG_NAME(1);
3088 text *priv_type_text = PG_GETARG_TEXT_P(2);
3091 AclResult aclresult;
3093 roleoid = get_roleid_checked(NameStr(*rolename));
3094 mode = convert_role_priv_string(priv_type_text);
3096 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3098 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3103 * Check user privileges on a role given
3104 * roleid, role oid, and text priv name.
3107 pg_has_role_id_id(PG_FUNCTION_ARGS)
3109 Oid roleid = PG_GETARG_OID(0);
3110 Oid roleoid = PG_GETARG_OID(1);
3111 text *priv_type_text = PG_GETARG_TEXT_P(2);
3113 AclResult aclresult;
3115 mode = convert_role_priv_string(priv_type_text);
3117 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3119 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3123 * Support routines for pg_has_role family.
3127 * convert_role_priv_string
3128 * Convert text string to AclMode value.
3130 * We use USAGE to denote whether the privileges of the role are accessible
3131 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
3132 * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
3133 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
3134 * is shared only with pg_role_aclcheck, below.
3137 convert_role_priv_string(text *priv_type_text)
3139 char *priv_type = text_to_cstring(priv_type_text);
3142 * Return mode from priv_type string
3144 if (pg_strcasecmp(priv_type, "USAGE") == 0)
3146 if (pg_strcasecmp(priv_type, "MEMBER") == 0)
3148 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0 ||
3149 pg_strcasecmp(priv_type, "USAGE WITH ADMIN OPTION") == 0 ||
3150 pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0 ||
3151 pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
3152 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
3155 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3156 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
3157 return ACL_NO_RIGHTS; /* keep compiler quiet */
3162 * Quick-and-dirty support for pg_has_role
3165 pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
3167 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
3169 if (is_admin_of_role(roleid, role_oid))
3172 if (mode & ACL_CREATE)
3174 if (is_member_of_role(roleid, role_oid))
3177 if (mode & ACL_USAGE)
3179 if (has_privs_of_role(roleid, role_oid))
3182 return ACLCHECK_NO_PRIV;
3187 * initialization function (called by InitPostgres)
3190 initialize_acl(void)
3192 if (!IsBootstrapProcessingMode())
3195 * In normal mode, set a callback on any syscache invalidation of
3196 * pg_auth_members rows
3198 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
3199 RoleMembershipCacheCallback,
3205 * RoleMembershipCacheCallback
3206 * Syscache inval callback function
3209 RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
3211 /* Force membership caches to be recomputed on next use */
3212 cached_privs_role = InvalidOid;
3213 cached_member_role = InvalidOid;
3217 /* Check if specified role has rolinherit set */
3219 has_rolinherit(Oid roleid)
3221 bool result = false;
3224 utup = SearchSysCache(AUTHOID,
3225 ObjectIdGetDatum(roleid),
3227 if (HeapTupleIsValid(utup))
3229 result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
3230 ReleaseSysCache(utup);
3237 * Get a list of roles that the specified roleid has the privileges of
3239 * This is defined not to recurse through roles that don't have rolinherit
3240 * set; for such roles, membership implies the ability to do SET ROLE, but
3241 * the privileges are not available until you've done so.
3243 * Since indirect membership testing is relatively expensive, we cache
3244 * a list of memberships. Hence, the result is only guaranteed good until
3245 * the next call of roles_has_privs_of()!
3247 * For the benefit of select_best_grantor, the result is defined to be
3248 * in breadth-first order, ie, closer relationships earlier.
3251 roles_has_privs_of(Oid roleid)
3255 List *new_cached_privs_roles;
3256 MemoryContext oldctx;
3258 /* If cache is already valid, just return the list */
3259 if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
3260 return cached_privs_roles;
3263 * Find all the roles that roleid is a member of, including multi-level
3264 * recursion. The role itself will always be the first element of the
3267 * Each element of the list is scanned to see if it adds any indirect
3268 * memberships. We can use a single list as both the record of
3269 * already-found memberships and the agenda of roles yet to be scanned.
3270 * This is a bit tricky but works because the foreach() macro doesn't
3271 * fetch the next list element until the bottom of the loop.
3273 roles_list = list_make1_oid(roleid);
3275 foreach(l, roles_list)
3277 Oid memberid = lfirst_oid(l);
3281 /* Ignore non-inheriting roles */
3282 if (!has_rolinherit(memberid))
3285 /* Find roles that memberid is directly a member of */
3286 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3287 ObjectIdGetDatum(memberid),
3289 for (i = 0; i < memlist->n_members; i++)
3291 HeapTuple tup = &memlist->members[i]->tuple;
3292 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3295 * Even though there shouldn't be any loops in the membership
3296 * graph, we must test for having already seen this role. It is
3297 * legal for instance to have both A->B and A->C->B.
3299 roles_list = list_append_unique_oid(roles_list, otherid);
3301 ReleaseSysCacheList(memlist);
3305 * Copy the completed list into TopMemoryContext so it will persist.
3307 oldctx = MemoryContextSwitchTo(TopMemoryContext);
3308 new_cached_privs_roles = list_copy(roles_list);
3309 MemoryContextSwitchTo(oldctx);
3310 list_free(roles_list);
3313 * Now safe to assign to state variable
3315 cached_privs_role = InvalidOid; /* just paranoia */
3316 list_free(cached_privs_roles);
3317 cached_privs_roles = new_cached_privs_roles;
3318 cached_privs_role = roleid;
3320 /* And now we can return the answer */
3321 return cached_privs_roles;
3326 * Get a list of roles that the specified roleid is a member of
3328 * This is defined to recurse through roles regardless of rolinherit.
3330 * Since indirect membership testing is relatively expensive, we cache
3331 * a list of memberships. Hence, the result is only guaranteed good until
3332 * the next call of roles_is_member_of()!
3335 roles_is_member_of(Oid roleid)
3339 List *new_cached_membership_roles;
3340 MemoryContext oldctx;
3342 /* If cache is already valid, just return the list */
3343 if (OidIsValid(cached_member_role) && cached_member_role == roleid)
3344 return cached_membership_roles;
3347 * Find all the roles that roleid is a member of, including multi-level
3348 * recursion. The role itself will always be the first element of the
3351 * Each element of the list is scanned to see if it adds any indirect
3352 * memberships. We can use a single list as both the record of
3353 * already-found memberships and the agenda of roles yet to be scanned.
3354 * This is a bit tricky but works because the foreach() macro doesn't
3355 * fetch the next list element until the bottom of the loop.
3357 roles_list = list_make1_oid(roleid);
3359 foreach(l, roles_list)
3361 Oid memberid = lfirst_oid(l);
3365 /* Find roles that memberid is directly a member of */
3366 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3367 ObjectIdGetDatum(memberid),
3369 for (i = 0; i < memlist->n_members; i++)
3371 HeapTuple tup = &memlist->members[i]->tuple;
3372 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3375 * Even though there shouldn't be any loops in the membership
3376 * graph, we must test for having already seen this role. It is
3377 * legal for instance to have both A->B and A->C->B.
3379 roles_list = list_append_unique_oid(roles_list, otherid);
3381 ReleaseSysCacheList(memlist);
3385 * Copy the completed list into TopMemoryContext so it will persist.
3387 oldctx = MemoryContextSwitchTo(TopMemoryContext);
3388 new_cached_membership_roles = list_copy(roles_list);
3389 MemoryContextSwitchTo(oldctx);
3390 list_free(roles_list);
3393 * Now safe to assign to state variable
3395 cached_member_role = InvalidOid; /* just paranoia */
3396 list_free(cached_membership_roles);
3397 cached_membership_roles = new_cached_membership_roles;
3398 cached_member_role = roleid;
3400 /* And now we can return the answer */
3401 return cached_membership_roles;
3406 * Does member have the privileges of role (directly or indirectly)?
3408 * This is defined not to recurse through roles that don't have rolinherit
3409 * set; for such roles, membership implies the ability to do SET ROLE, but
3410 * the privileges are not available until you've done so.
3413 has_privs_of_role(Oid member, Oid role)
3415 /* Fast path for simple case */
3419 /* Superusers have every privilege, so are part of every role */
3420 if (superuser_arg(member))
3424 * Find all the roles that member has the privileges of, including
3425 * multi-level recursion, then see if target role is any one of them.
3427 return list_member_oid(roles_has_privs_of(member), role);
3432 * Is member a member of role (directly or indirectly)?
3434 * This is defined to recurse through roles regardless of rolinherit.
3437 is_member_of_role(Oid member, Oid role)
3439 /* Fast path for simple case */
3443 /* Superusers have every privilege, so are part of every role */
3444 if (superuser_arg(member))
3448 * Find all the roles that member is a member of, including multi-level
3449 * recursion, then see if target role is any one of them.
3451 return list_member_oid(roles_is_member_of(member), role);
3455 * check_is_member_of_role
3456 * is_member_of_role with a standard permission-violation error if not
3459 check_is_member_of_role(Oid member, Oid role)
3461 if (!is_member_of_role(member, role))
3463 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3464 errmsg("must be member of role \"%s\"",
3465 GetUserNameFromId(role))));
3469 * Is member a member of role, not considering superuserness?
3471 * This is identical to is_member_of_role except we ignore superuser
3475 is_member_of_role_nosuper(Oid member, Oid role)
3477 /* Fast path for simple case */
3482 * Find all the roles that member is a member of, including multi-level
3483 * recursion, then see if target role is any one of them.
3485 return list_member_oid(roles_is_member_of(member), role);
3490 * Is member an admin of role (directly or indirectly)? That is, is it
3491 * a member WITH ADMIN OPTION?
3493 * We could cache the result as for is_member_of_role, but currently this
3494 * is not used in any performance-critical paths, so we don't.
3497 is_admin_of_role(Oid member, Oid role)
3499 bool result = false;
3503 /* Fast path for simple case */
3507 /* Superusers have every privilege, so are part of every role */
3508 if (superuser_arg(member))
3512 * Find all the roles that member is a member of, including multi-level
3513 * recursion. We build a list in the same way that is_member_of_role does
3514 * to track visited and unvisited roles.
3516 roles_list = list_make1_oid(member);
3518 foreach(l, roles_list)
3520 Oid memberid = lfirst_oid(l);
3524 /* Find roles that memberid is directly a member of */
3525 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3526 ObjectIdGetDatum(memberid),
3528 for (i = 0; i < memlist->n_members; i++)
3530 HeapTuple tup = &memlist->members[i]->tuple;
3531 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3533 if (otherid == role &&
3534 ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
3536 /* Found what we came for, so can stop searching */
3541 roles_list = list_append_unique_oid(roles_list, otherid);
3543 ReleaseSysCacheList(memlist);
3548 list_free(roles_list);
3554 /* does what it says ... */
3556 count_one_bits(AclMode mask)
3560 /* this code relies on AclMode being an unsigned type */
3572 * Select the effective grantor ID for a GRANT or REVOKE operation.
3574 * The grantor must always be either the object owner or some role that has
3575 * been explicitly granted grant options. This ensures that all granted
3576 * privileges appear to flow from the object owner, and there are never
3577 * multiple "original sources" of a privilege. Therefore, if the would-be
3578 * grantor is a member of a role that has the needed grant options, we have
3579 * to do the grant as that role instead.
3581 * It is possible that the would-be grantor is a member of several roles
3582 * that have different subsets of the desired grant options, but no one
3583 * role has 'em all. In this case we pick a role with the largest number
3584 * of desired options. Ties are broken in favor of closer ancestors.
3586 * roleId: the role attempting to do the GRANT/REVOKE
3587 * privileges: the privileges to be granted/revoked
3588 * acl: the ACL of the object in question
3589 * ownerId: the role owning the object in question
3590 * *grantorId: receives the OID of the role to do the grant as
3591 * *grantOptions: receives the grant options actually held by grantorId
3593 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
3596 select_best_grantor(Oid roleId, AclMode privileges,
3597 const Acl *acl, Oid ownerId,
3598 Oid *grantorId, AclMode *grantOptions)
3600 AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
3606 * The object owner is always treated as having all grant options, so if
3607 * roleId is the owner it's easy. Also, if roleId is a superuser it's
3608 * easy: superusers are implicitly members of every role, so they act as
3611 if (roleId == ownerId || superuser_arg(roleId))
3613 *grantorId = ownerId;
3614 *grantOptions = needed_goptions;
3619 * Otherwise we have to do a careful search to see if roleId has the
3620 * privileges of any suitable role. Note: we can hang onto the result of
3621 * roles_has_privs_of() throughout this loop, because aclmask_direct()
3622 * doesn't query any role memberships.
3624 roles_list = roles_has_privs_of(roleId);
3626 /* initialize candidate result as default */
3627 *grantorId = roleId;
3628 *grantOptions = ACL_NO_RIGHTS;
3631 foreach(l, roles_list)
3633 Oid otherrole = lfirst_oid(l);
3636 otherprivs = aclmask_direct(acl, otherrole, ownerId,
3637 needed_goptions, ACLMASK_ALL);
3638 if (otherprivs == needed_goptions)
3640 /* Found a suitable grantor */
3641 *grantorId = otherrole;
3642 *grantOptions = otherprivs;
3647 * If it has just some of the needed privileges, remember best
3650 if (otherprivs != ACL_NO_RIGHTS)
3652 int nnewrights = count_one_bits(otherprivs);
3654 if (nnewrights > nrights)
3656 *grantorId = otherrole;
3657 *grantOptions = otherprivs;
3658 nrights = nnewrights;