1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2007, 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.138 2007/02/27 23:48:07 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 "miscadmin.h"
26 #include "utils/acl.h"
27 #include "utils/builtins.h"
28 #include "utils/inval.h"
29 #include "utils/lsyscache.h"
30 #include "utils/memutils.h"
31 #include "utils/syscache.h"
35 * We frequently need to test whether a given role is a member of some other
36 * role. In most of these tests the "given role" is the same, namely the
37 * active current user. So we can optimize it by keeping a cached list of
38 * all the roles the "given role" is a member of, directly or indirectly.
39 * The cache is flushed whenever we detect a change in pg_auth_members.
41 * There are actually two caches, one computed under "has_privs" rules
42 * (do not recurse where rolinherit isn't true) and one computed under
43 * "is_member" rules (recurse regardless of rolinherit).
45 * Possibly this mechanism should be generalized to allow caching membership
46 * info for multiple roles?
48 * The has_privs cache is:
49 * cached_privs_role is the role OID the cache is for.
50 * cached_privs_roles is an OID list of roles that cached_privs_role
51 * has the privileges of (always including itself).
52 * The cache is valid if cached_privs_role is not InvalidOid.
54 * The is_member cache is similarly:
55 * cached_member_role is the role OID the cache is for.
56 * cached_membership_roles is an OID list of roles that cached_member_role
57 * is a member of (always including itself).
58 * The cache is valid if cached_member_role is not InvalidOid.
60 static Oid cached_privs_role = InvalidOid;
61 static List *cached_privs_roles = NIL;
62 static Oid cached_member_role = InvalidOid;
63 static List *cached_membership_roles = NIL;
66 static const char *getid(const char *s, char *n);
67 static void putid(char *p, const char *s);
68 static Acl *allocacl(int n);
69 static void check_acl(const Acl *acl);
70 static const char *aclparse(const char *s, AclItem *aip);
71 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
72 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
74 static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
75 Oid ownerId, DropBehavior behavior);
76 static int oidComparator(const void *arg1, const void *arg2);
78 static AclMode convert_priv_string(text *priv_type_text);
80 static Oid convert_table_name(text *tablename);
81 static AclMode convert_table_priv_string(text *priv_type_text);
82 static Oid convert_database_name(text *databasename);
83 static AclMode convert_database_priv_string(text *priv_type_text);
84 static Oid convert_function_name(text *functionname);
85 static AclMode convert_function_priv_string(text *priv_type_text);
86 static Oid convert_language_name(text *languagename);
87 static AclMode convert_language_priv_string(text *priv_type_text);
88 static Oid convert_schema_name(text *schemaname);
89 static AclMode convert_schema_priv_string(text *priv_type_text);
90 static Oid convert_tablespace_name(text *tablespacename);
91 static AclMode convert_tablespace_priv_string(text *priv_type_text);
92 static AclMode convert_role_priv_string(text *priv_type_text);
93 static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
95 static void RoleMembershipCacheCallback(Datum arg, Oid relid);
100 * Consumes the first alphanumeric string (identifier) found in string
101 * 's', ignoring any leading white space. If it finds a double quote
102 * it returns the word inside the quotes.
105 * the string position in 's' that points to the next non-space character
106 * in 's', after any quotes. Also:
107 * - loads the identifier into 'n'. (If no identifier is found, 'n'
108 * contains an empty string.) 'n' must be NAMEDATALEN bytes.
111 getid(const char *s, char *n)
114 bool in_quotes = false;
118 while (isspace((unsigned char) *s))
120 /* This code had better match what putid() does, below */
123 (isalnum((unsigned char) *s) ||
131 /* safe to look at next char (could be '\0' though) */
134 in_quotes = !in_quotes;
137 /* it's an escaped double quote; skip the escaping char */
141 /* Add the character to the string */
142 if (len >= NAMEDATALEN - 1)
144 (errcode(ERRCODE_NAME_TOO_LONG),
145 errmsg("identifier too long"),
146 errdetail("Identifier must be less than %d characters.",
152 while (isspace((unsigned char) *s))
158 * Write a role name at *p, adding double quotes if needed.
159 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
160 * This needs to be kept in sync with copyAclUserName in pg_dump/dumputils.c
163 putid(char *p, const char *s)
168 for (src = s; *src; src++)
170 /* This test had better match what getid() does, above */
171 if (!isalnum((unsigned char) *src) && *src != '_')
179 for (src = s; *src; src++)
181 /* A double quote character in a username is encoded as "" */
193 * Consumes and parses an ACL specification of the form:
194 * [group|user] [A-Za-z0-9]*=[rwaR]*
195 * from string 's', ignoring any leading white space or white space
196 * between the optional id type keyword (group|user) and the actual
199 * The group|user decoration is unnecessary in the roles world,
200 * but we still accept it for backward compatibility.
202 * This routine is called by the parser as well as aclitemin(), hence
203 * the added generality.
206 * the string position in 's' immediately following the ACL
207 * specification. Also:
208 * - loads the structure pointed to by 'aip' with the appropriate
209 * UID/GID, id type identifier and mode type values.
212 aclparse(const char *s, AclItem *aip)
217 char name[NAMEDATALEN];
218 char name2[NAMEDATALEN];
223 elog(LOG, "aclparse: input = \"%s\"", s);
228 /* we just read a keyword, not a name */
229 if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
231 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
232 errmsg("unrecognized key word: \"%s\"", name),
233 errhint("ACL key word must be \"group\" or \"user\".")));
234 s = getid(s, name); /* move s to the name beyond the keyword */
237 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
238 errmsg("missing name"),
239 errhint("A name must follow the \"group\" or \"user\" key word.")));
244 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
245 errmsg("missing \"=\" sign")));
247 privs = goption = ACL_NO_RIGHTS;
249 for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
268 case ACL_REFERENCES_CHR:
269 read = ACL_REFERENCES;
271 case ACL_TRIGGER_CHR:
274 case ACL_EXECUTE_CHR:
283 case ACL_CREATE_TEMP_CHR:
284 read = ACL_CREATE_TEMP;
286 case ACL_CONNECT_CHR:
289 case 'R': /* ignore old RULE privileges */
294 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
295 errmsg("invalid mode character: must be one of \"%s\"",
296 ACL_ALL_RIGHTS_STR)));
303 aip->ai_grantee = ACL_ID_PUBLIC;
305 aip->ai_grantee = get_roleid_checked(name);
308 * XXX Allow a degree of backward compatibility by defaulting the grantor
313 s = getid(s + 1, name2);
314 if (name2[0] == '\0')
316 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
317 errmsg("a name must follow the \"/\" sign")));
318 aip->ai_grantor = get_roleid_checked(name2);
322 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
324 (errcode(ERRCODE_INVALID_GRANTOR),
325 errmsg("defaulting grantor to user ID %u",
326 BOOTSTRAP_SUPERUSERID)));
329 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
332 elog(LOG, "aclparse: correctly read [%u %x %x]",
333 aip->ai_grantee, privs, goption);
341 * Allocates storage for a new Acl with 'n' entries.
353 elog(ERROR, "invalid size: %d", n);
354 size = ACL_N_SIZE(n);
355 new_acl = (Acl *) palloc0(size);
356 SET_VARSIZE(new_acl, size);
358 new_acl->dataoffset = 0; /* we never put in any nulls */
359 new_acl->elemtype = ACLITEMOID;
360 ARR_LBOUND(new_acl)[0] = 1;
361 ARR_DIMS(new_acl)[0] = n;
366 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
369 check_acl(const Acl *acl)
371 if (ARR_ELEMTYPE(acl) != ACLITEMOID)
373 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
374 errmsg("ACL array contains wrong data type")));
375 if (ARR_NDIM(acl) != 1)
377 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
378 errmsg("ACL arrays must be one-dimensional")));
379 if (ARR_HASNULL(acl))
381 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
382 errmsg("ACL arrays must not contain null values")));
387 * Allocates storage for, and fills in, a new AclItem given a string
388 * 's' that contains an ACL specification. See aclparse for details.
394 aclitemin(PG_FUNCTION_ARGS)
396 const char *s = PG_GETARG_CSTRING(0);
399 aip = (AclItem *) palloc(sizeof(AclItem));
400 s = aclparse(s, aip);
401 while (isspace((unsigned char) *s))
405 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
406 errmsg("extra garbage at the end of the ACL specification")));
408 PG_RETURN_ACLITEM_P(aip);
413 * Allocates storage for, and fills in, a new null-delimited string
414 * containing a formatted ACL specification. See aclparse for details.
420 aclitemout(PG_FUNCTION_ARGS)
422 AclItem *aip = PG_GETARG_ACLITEM_P(0);
428 out = palloc(strlen("=/") +
430 2 * (2 * NAMEDATALEN + 2) +
436 if (aip->ai_grantee != ACL_ID_PUBLIC)
438 htup = SearchSysCache(AUTHOID,
439 ObjectIdGetDatum(aip->ai_grantee),
441 if (HeapTupleIsValid(htup))
443 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
444 ReleaseSysCache(htup);
448 /* Generate numeric OID if we don't find an entry */
449 sprintf(p, "%u", aip->ai_grantee);
457 for (i = 0; i < N_ACL_RIGHTS; ++i)
459 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
460 *p++ = ACL_ALL_RIGHTS_STR[i];
461 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
468 htup = SearchSysCache(AUTHOID,
469 ObjectIdGetDatum(aip->ai_grantor),
471 if (HeapTupleIsValid(htup))
473 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
474 ReleaseSysCache(htup);
478 /* Generate numeric OID if we don't find an entry */
479 sprintf(p, "%u", aip->ai_grantor);
482 PG_RETURN_CSTRING(out);
487 * Two AclItems are considered to match iff they have the same
488 * grantee and grantor; the privileges are ignored.
491 aclitem_match(const AclItem *a1, const AclItem *a2)
493 return a1->ai_grantee == a2->ai_grantee &&
494 a1->ai_grantor == a2->ai_grantor;
498 * aclitem equality operator
501 aclitem_eq(PG_FUNCTION_ARGS)
503 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
504 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
507 result = a1->ai_privs == a2->ai_privs &&
508 a1->ai_grantee == a2->ai_grantee &&
509 a1->ai_grantor == a2->ai_grantor;
510 PG_RETURN_BOOL(result);
514 * aclitem hash function
516 * We make aclitems hashable not so much because anyone is likely to hash
517 * them, as because we want array equality to work on aclitem arrays, and
518 * with the typcache mechanism we must have a hash or btree opclass.
521 hash_aclitem(PG_FUNCTION_ARGS)
523 AclItem *a = PG_GETARG_ACLITEM_P(0);
525 /* not very bright, but avoids any issue of padding in struct */
526 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
531 * acldefault() --- create an ACL describing default access permissions
533 * Change this routine if you want to alter the default access policy for
534 * newly-created objects (or any object with a NULL acl entry).
537 acldefault(GrantObjectType objtype, Oid ownerId)
539 AclMode world_default;
540 AclMode owner_default;
546 case ACL_OBJECT_RELATION:
547 world_default = ACL_NO_RIGHTS;
548 owner_default = ACL_ALL_RIGHTS_RELATION;
550 case ACL_OBJECT_SEQUENCE:
551 world_default = ACL_NO_RIGHTS;
552 owner_default = ACL_ALL_RIGHTS_SEQUENCE;
554 case ACL_OBJECT_DATABASE:
555 /* for backwards compatibility, grant some rights by default */
556 world_default = ACL_CREATE_TEMP | ACL_CONNECT;
557 owner_default = ACL_ALL_RIGHTS_DATABASE;
559 case ACL_OBJECT_FUNCTION:
560 /* Grant EXECUTE by default, for now */
561 world_default = ACL_EXECUTE;
562 owner_default = ACL_ALL_RIGHTS_FUNCTION;
564 case ACL_OBJECT_LANGUAGE:
565 /* Grant USAGE by default, for now */
566 world_default = ACL_USAGE;
567 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
569 case ACL_OBJECT_NAMESPACE:
570 world_default = ACL_NO_RIGHTS;
571 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
573 case ACL_OBJECT_TABLESPACE:
574 world_default = ACL_NO_RIGHTS;
575 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
578 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
579 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
580 owner_default = ACL_NO_RIGHTS;
584 acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);
587 if (world_default != ACL_NO_RIGHTS)
589 aip->ai_grantee = ACL_ID_PUBLIC;
590 aip->ai_grantor = ownerId;
591 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
596 * Note that the owner's entry shows all ordinary privileges but no grant
597 * options. This is because his grant options come "from the system" and
598 * not from his own efforts. (The SQL spec says that the owner's rights
599 * come from a "_SYSTEM" authid.) However, we do consider that the
600 * owner's ordinary privileges are self-granted; this lets him revoke
601 * them. We implement the owner's grant options without any explicit
602 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
603 * whereever we are testing grant options.
605 aip->ai_grantee = ownerId;
606 aip->ai_grantor = ownerId;
607 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
614 * Update an ACL array to add or remove specified privileges.
616 * old_acl: the input ACL array
617 * mod_aip: defines the privileges to be added, removed, or substituted
618 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
619 * ownerId: Oid of object owner
620 * behavior: RESTRICT or CASCADE behavior for recursive removal
622 * ownerid and behavior are only relevant when the update operation specifies
623 * deletion of grant options.
625 * The result is a modified copy; the input object is not changed.
627 * NB: caller is responsible for having detoasted the input ACL, if needed.
630 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
631 int modechg, Oid ownerId, DropBehavior behavior)
643 /* Caller probably already checked old_acl, but be safe */
646 /* If granting grant options, check for circularity */
647 if (modechg != ACL_MODECHG_DEL &&
648 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
649 check_circularity(old_acl, mod_aip, ownerId);
651 num = ACL_NUM(old_acl);
652 old_aip = ACL_DAT(old_acl);
655 * Search the ACL for an existing entry for this grantee and grantor. If
656 * one exists, just modify the entry in-place (well, in the same position,
657 * since we actually return a copy); otherwise, insert the new entry at
661 for (dst = 0; dst < num; ++dst)
663 if (aclitem_match(mod_aip, old_aip + dst))
665 /* found a match, so modify existing item */
666 new_acl = allocacl(num);
667 new_aip = ACL_DAT(new_acl);
668 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
675 /* need to append a new item */
676 new_acl = allocacl(num + 1);
677 new_aip = ACL_DAT(new_acl);
678 memcpy(new_aip, old_aip, num * sizeof(AclItem));
680 /* initialize the new entry with no permissions */
681 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
682 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
683 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
684 ACL_NO_RIGHTS, ACL_NO_RIGHTS);
685 num++; /* set num to the size of new_acl */
688 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
689 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
691 /* apply the specified permissions change */
694 case ACL_MODECHG_ADD:
695 ACLITEM_SET_RIGHTS(new_aip[dst],
696 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
698 case ACL_MODECHG_DEL:
699 ACLITEM_SET_RIGHTS(new_aip[dst],
700 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
702 case ACL_MODECHG_EQL:
703 ACLITEM_SET_RIGHTS(new_aip[dst],
704 ACLITEM_GET_RIGHTS(*mod_aip));
708 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
709 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
712 * If the adjusted entry has no permissions, delete it from the list.
714 if (new_rights == ACL_NO_RIGHTS)
716 memmove(new_aip + dst,
718 (num - dst - 1) * sizeof(AclItem));
719 /* Adjust array size to be 'num - 1' items */
720 ARR_DIMS(new_acl)[0] = num - 1;
721 SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
725 * Remove abandoned privileges (cascading revoke). Currently we can only
726 * handle this when the grantee is not PUBLIC.
728 if ((old_goptions & ~new_goptions) != 0)
730 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
731 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
732 (old_goptions & ~new_goptions),
740 * Update an ACL array to reflect a change of owner to the parent object
742 * old_acl: the input ACL array (must not be NULL)
743 * oldOwnerId: Oid of the old object owner
744 * newOwnerId: Oid of the new object owner
746 * The result is a modified copy; the input object is not changed.
748 * NB: caller is responsible for having detoasted the input ACL, if needed.
751 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
759 bool newpresent = false;
768 * Make a copy of the given ACL, substituting new owner ID for old
769 * wherever it appears as either grantor or grantee. Also note if the new
770 * owner ID is already present.
772 num = ACL_NUM(old_acl);
773 old_aip = ACL_DAT(old_acl);
774 new_acl = allocacl(num);
775 new_aip = ACL_DAT(new_acl);
776 memcpy(new_aip, old_aip, num * sizeof(AclItem));
777 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
779 if (dst_aip->ai_grantor == oldOwnerId)
780 dst_aip->ai_grantor = newOwnerId;
781 else if (dst_aip->ai_grantor == newOwnerId)
783 if (dst_aip->ai_grantee == oldOwnerId)
784 dst_aip->ai_grantee = newOwnerId;
785 else if (dst_aip->ai_grantee == newOwnerId)
790 * If the old ACL contained any references to the new owner, then we may
791 * now have generated an ACL containing duplicate entries. Find them and
792 * merge them so that there are not duplicates. (This is relatively
793 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
794 * be the normal case.)
796 * To simplify deletion of duplicate entries, we temporarily leave them in
797 * the array but set their privilege masks to zero; when we reach such an
798 * entry it's just skipped. (Thus, a side effect of this code will be to
799 * remove privilege-free entries, should there be any in the input.) dst
800 * is the next output slot, targ is the currently considered input slot
801 * (always >= dst), and src scans entries to the right of targ looking for
802 * duplicates. Once an entry has been emitted to dst it is known
803 * duplicate-free and need not be considered anymore.
808 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
810 /* ignore if deleted in an earlier pass */
811 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
813 /* find and merge any duplicates */
814 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
817 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
819 if (aclitem_match(targ_aip, src_aip))
821 ACLITEM_SET_RIGHTS(*targ_aip,
822 ACLITEM_GET_RIGHTS(*targ_aip) |
823 ACLITEM_GET_RIGHTS(*src_aip));
824 /* mark the duplicate deleted */
825 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
828 /* and emit to output */
829 new_aip[dst] = *targ_aip;
832 /* Adjust array size to be 'dst' items */
833 ARR_DIMS(new_acl)[0] = dst;
834 SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
842 * When granting grant options, we must disallow attempts to set up circular
843 * chains of grant options. Suppose A (the object owner) grants B some
844 * privileges with grant option, and B re-grants them to C. If C could
845 * grant the privileges to B as well, then A would be unable to effectively
846 * revoke the privileges from B, since recursive_revoke would consider that
847 * B still has 'em from C.
849 * We check for this by recursively deleting all grant options belonging to
850 * the target grantee, and then seeing if the would-be grantor still has the
851 * grant option or not.
854 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
866 * For now, grant options can only be granted to roles, not PUBLIC.
867 * Otherwise we'd have to work a bit harder here.
869 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
871 /* The owner always has grant options, no need to check */
872 if (mod_aip->ai_grantor == ownerId)
875 /* Make a working copy */
876 acl = allocacl(ACL_NUM(old_acl));
877 memcpy(acl, old_acl, ACL_SIZE(old_acl));
879 /* Zap all grant options of target grantee, plus what depends on 'em */
883 for (i = 0; i < num; i++)
885 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
886 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
890 /* We'll actually zap ordinary privs too, but no matter */
891 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
892 ownerId, DROP_CASCADE);
901 /* Now we can compute grantor's independently-derived privileges */
902 own_privs = aclmask(acl,
905 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
907 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
909 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
911 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
912 errmsg("grant options cannot be granted back to your own grantor")));
919 * Ensure that no privilege is "abandoned". A privilege is abandoned
920 * if the user that granted the privilege loses the grant option. (So
921 * the chain through which it was granted is broken.) Either the
922 * abandoned privileges are revoked as well, or an error message is
923 * printed, depending on the drop behavior option.
925 * acl: the input ACL list
926 * grantee: the user from whom some grant options have been revoked
927 * revoke_privs: the grant options being revoked
928 * ownerId: Oid of object owner
929 * behavior: RESTRICT or CASCADE behavior for recursive removal
931 * The input Acl object is pfree'd if replaced.
934 recursive_revoke(Acl *acl,
936 AclMode revoke_privs,
938 DropBehavior behavior)
947 /* The owner can never truly lose grant options, so short-circuit */
948 if (grantee == ownerId)
951 /* The grantee might still have the privileges via another grantor */
952 still_has = aclmask(acl, grantee, ownerId,
953 ACL_GRANT_OPTION_FOR(revoke_privs),
955 revoke_privs &= ~still_has;
956 if (revoke_privs == ACL_NO_RIGHTS)
962 for (i = 0; i < num; i++)
964 if (aip[i].ai_grantor == grantee
965 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
970 if (behavior == DROP_RESTRICT)
972 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
973 errmsg("dependent privileges exist"),
974 errhint("Use CASCADE to revoke them too.")));
976 mod_acl.ai_grantor = grantee;
977 mod_acl.ai_grantee = aip[i].ai_grantee;
978 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
982 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
997 * aclmask --- compute bitmask of all privileges held by roleid.
999 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1000 * held by the given roleid according to the given ACL list, ANDed
1001 * with 'mask'. (The point of passing 'mask' is to let the routine
1002 * exit early if all privileges of interest have been found.)
1004 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1005 * is known true. (This lets us exit soonest in cases where the
1006 * caller is only going to test for zero or nonzero result.)
1010 * To see if any of a set of privileges are held:
1011 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1013 * To see if all of a set of privileges are held:
1014 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1016 * To determine exactly which of a set of privileges are held:
1017 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1020 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1021 AclMode mask, AclMaskHow how)
1030 * Null ACL should not happen, since caller should have inserted
1031 * appropriate default
1034 elog(ERROR, "null ACL");
1038 /* Quick exit for mask == 0 */
1044 /* Owner always implicitly has all grant options */
1045 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1046 has_privs_of_role(roleid, ownerId))
1048 result = mask & ACLITEM_ALL_GOPTION_BITS;
1049 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1054 aidat = ACL_DAT(acl);
1057 * Check privileges granted directly to roleid or to public
1059 for (i = 0; i < num; i++)
1061 AclItem *aidata = &aidat[i];
1063 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1064 aidata->ai_grantee == roleid)
1066 result |= aidata->ai_privs & mask;
1067 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1073 * Check privileges granted indirectly via role memberships. We do this in
1074 * a separate pass to minimize expensive indirect membership tests. In
1075 * particular, it's worth testing whether a given ACL entry grants any
1076 * privileges still of interest before we perform the has_privs_of_role
1079 remaining = mask & ~result;
1080 for (i = 0; i < num; i++)
1082 AclItem *aidata = &aidat[i];
1084 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1085 aidata->ai_grantee == roleid)
1086 continue; /* already checked it */
1088 if ((aidata->ai_privs & remaining) &&
1089 has_privs_of_role(roleid, aidata->ai_grantee))
1091 result |= aidata->ai_privs & mask;
1092 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1094 remaining = mask & ~result;
1103 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1105 * This is exactly like aclmask() except that we consider only privileges
1106 * held *directly* by roleid, not those inherited via role membership.
1109 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1110 AclMode mask, AclMaskHow how)
1118 * Null ACL should not happen, since caller should have inserted
1119 * appropriate default
1122 elog(ERROR, "null ACL");
1126 /* Quick exit for mask == 0 */
1132 /* Owner always implicitly has all grant options */
1133 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1136 result = mask & ACLITEM_ALL_GOPTION_BITS;
1137 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1142 aidat = ACL_DAT(acl);
1145 * Check privileges granted directly to roleid (and not to public)
1147 for (i = 0; i < num; i++)
1149 AclItem *aidata = &aidat[i];
1151 if (aidata->ai_grantee == roleid)
1153 result |= aidata->ai_privs & mask;
1154 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1165 * Find out all the roleids mentioned in an Acl.
1166 * Note that we do not distinguish grantors from grantees.
1168 * *roleids is set to point to a palloc'd array containing distinct OIDs
1169 * in sorted order. The length of the array is the function result.
1172 aclmembers(const Acl *acl, Oid **roleids)
1175 const AclItem *acldat;
1180 if (acl == NULL || ACL_NUM(acl) == 0)
1188 /* Allocate the worst-case space requirement */
1189 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1190 acldat = ACL_DAT(acl);
1193 * Walk the ACL collecting mentioned RoleIds.
1196 for (i = 0; i < ACL_NUM(acl); i++)
1198 const AclItem *ai = &acldat[i];
1200 if (ai->ai_grantee != ACL_ID_PUBLIC)
1201 list[j++] = ai->ai_grantee;
1202 /* grantor is currently never PUBLIC, but let's check anyway */
1203 if (ai->ai_grantor != ACL_ID_PUBLIC)
1204 list[j++] = ai->ai_grantor;
1207 /* Sort the array */
1208 qsort(list, j, sizeof(Oid), oidComparator);
1210 /* Remove duplicates from the array */
1212 for (i = 1; i < j; i++)
1214 if (list[k] != list[i])
1215 list[++k] = list[i];
1219 * We could repalloc the array down to minimum size, but it's hardly worth
1220 * it since it's only transient memory.
1229 * qsort comparison function for Oids
1232 oidComparator(const void *arg1, const void *arg2)
1234 Oid oid1 = *(const Oid *) arg1;
1235 Oid oid2 = *(const Oid *) arg2;
1246 * aclinsert (exported function)
1249 aclinsert(PG_FUNCTION_ARGS)
1252 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1253 errmsg("aclinsert is no longer supported")));
1255 PG_RETURN_NULL(); /* keep compiler quiet */
1259 aclremove(PG_FUNCTION_ARGS)
1262 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1263 errmsg("aclremove is no longer supported")));
1265 PG_RETURN_NULL(); /* keep compiler quiet */
1269 aclcontains(PG_FUNCTION_ARGS)
1271 Acl *acl = PG_GETARG_ACL_P(0);
1272 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1279 aidat = ACL_DAT(acl);
1280 for (i = 0; i < num; ++i)
1282 if (aip->ai_grantee == aidat[i].ai_grantee &&
1283 aip->ai_grantor == aidat[i].ai_grantor &&
1284 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1285 PG_RETURN_BOOL(true);
1287 PG_RETURN_BOOL(false);
1291 makeaclitem(PG_FUNCTION_ARGS)
1293 Oid grantee = PG_GETARG_OID(0);
1294 Oid grantor = PG_GETARG_OID(1);
1295 text *privtext = PG_GETARG_TEXT_P(2);
1296 bool goption = PG_GETARG_BOOL(3);
1300 priv = convert_priv_string(privtext);
1302 result = (AclItem *) palloc(sizeof(AclItem));
1304 result->ai_grantee = grantee;
1305 result->ai_grantor = grantor;
1307 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1308 (goption ? priv : ACL_NO_RIGHTS));
1310 PG_RETURN_ACLITEM_P(result);
1314 convert_priv_string(text *priv_type_text)
1318 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1319 PointerGetDatum(priv_type_text)));
1321 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1323 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1325 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1327 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1329 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1330 return ACL_REFERENCES;
1331 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1333 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1335 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1337 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1339 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1340 return ACL_CREATE_TEMP;
1341 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1342 return ACL_CREATE_TEMP;
1343 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1345 if (pg_strcasecmp(priv_type, "RULE") == 0)
1346 return 0; /* ignore old RULE privileges */
1349 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1350 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1351 return ACL_NO_RIGHTS; /* keep compiler quiet */
1356 * has_table_privilege variants
1357 * These are all named "has_table_privilege" at the SQL level.
1358 * They take various combinations of relation name, relation OID,
1359 * user name, user OID, or implicit user = current_user.
1361 * The result is a boolean value: true if user has the indicated
1362 * privilege, false if not.
1366 * has_table_privilege_name_name
1367 * Check user privileges on a table given
1368 * name username, text tablename, and text priv name.
1371 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1373 Name rolename = PG_GETARG_NAME(0);
1374 text *tablename = PG_GETARG_TEXT_P(1);
1375 text *priv_type_text = PG_GETARG_TEXT_P(2);
1379 AclResult aclresult;
1381 roleid = get_roleid_checked(NameStr(*rolename));
1382 tableoid = convert_table_name(tablename);
1383 mode = convert_table_priv_string(priv_type_text);
1385 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1387 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1391 * has_table_privilege_name
1392 * Check user privileges on a table given
1393 * text tablename and text priv name.
1394 * current_user is assumed
1397 has_table_privilege_name(PG_FUNCTION_ARGS)
1399 text *tablename = PG_GETARG_TEXT_P(0);
1400 text *priv_type_text = PG_GETARG_TEXT_P(1);
1404 AclResult aclresult;
1406 roleid = GetUserId();
1407 tableoid = convert_table_name(tablename);
1408 mode = convert_table_priv_string(priv_type_text);
1410 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1412 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1416 * has_table_privilege_name_id
1417 * Check user privileges on a table given
1418 * name usename, table oid, and text priv name.
1421 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1423 Name username = PG_GETARG_NAME(0);
1424 Oid tableoid = PG_GETARG_OID(1);
1425 text *priv_type_text = PG_GETARG_TEXT_P(2);
1428 AclResult aclresult;
1430 roleid = get_roleid_checked(NameStr(*username));
1431 mode = convert_table_priv_string(priv_type_text);
1433 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1435 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1439 * has_table_privilege_id
1440 * Check user privileges on a table given
1441 * table oid, and text priv name.
1442 * current_user is assumed
1445 has_table_privilege_id(PG_FUNCTION_ARGS)
1447 Oid tableoid = PG_GETARG_OID(0);
1448 text *priv_type_text = PG_GETARG_TEXT_P(1);
1451 AclResult aclresult;
1453 roleid = GetUserId();
1454 mode = convert_table_priv_string(priv_type_text);
1456 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1458 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1462 * has_table_privilege_id_name
1463 * Check user privileges on a table given
1464 * roleid, text tablename, and text priv name.
1467 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1469 Oid roleid = PG_GETARG_OID(0);
1470 text *tablename = PG_GETARG_TEXT_P(1);
1471 text *priv_type_text = PG_GETARG_TEXT_P(2);
1474 AclResult aclresult;
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_id_id
1486 * Check user privileges on a table given
1487 * roleid, table oid, and text priv name.
1490 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1492 Oid roleid = PG_GETARG_OID(0);
1493 Oid tableoid = PG_GETARG_OID(1);
1494 text *priv_type_text = PG_GETARG_TEXT_P(2);
1496 AclResult aclresult;
1498 mode = convert_table_priv_string(priv_type_text);
1500 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1502 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1506 * Support routines for has_table_privilege family.
1510 * Given a table name expressed as a string, look it up and return Oid
1513 convert_table_name(text *tablename)
1517 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1519 return RangeVarGetRelid(relrv, false);
1523 * convert_table_priv_string
1524 * Convert text string to AclMode value.
1527 convert_table_priv_string(text *priv_type_text)
1531 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1532 PointerGetDatum(priv_type_text)));
1535 * Return mode from priv_type string
1537 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1539 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1540 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1542 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1544 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1545 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1547 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1549 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1550 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1552 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1554 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1555 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1557 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1558 return ACL_REFERENCES;
1559 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1560 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1562 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1564 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1565 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1567 if (pg_strcasecmp(priv_type, "RULE") == 0)
1568 return 0; /* ignore old RULE privileges */
1569 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1573 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1574 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1575 return ACL_NO_RIGHTS; /* keep compiler quiet */
1580 * has_database_privilege variants
1581 * These are all named "has_database_privilege" at the SQL level.
1582 * They take various combinations of database name, database OID,
1583 * user name, user OID, or implicit user = current_user.
1585 * The result is a boolean value: true if user has the indicated
1586 * privilege, false if not.
1590 * has_database_privilege_name_name
1591 * Check user privileges on a database given
1592 * name username, text databasename, and text priv name.
1595 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1597 Name username = PG_GETARG_NAME(0);
1598 text *databasename = PG_GETARG_TEXT_P(1);
1599 text *priv_type_text = PG_GETARG_TEXT_P(2);
1603 AclResult aclresult;
1605 roleid = get_roleid_checked(NameStr(*username));
1606 databaseoid = convert_database_name(databasename);
1607 mode = convert_database_priv_string(priv_type_text);
1609 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1611 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1615 * has_database_privilege_name
1616 * Check user privileges on a database given
1617 * text databasename and text priv name.
1618 * current_user is assumed
1621 has_database_privilege_name(PG_FUNCTION_ARGS)
1623 text *databasename = PG_GETARG_TEXT_P(0);
1624 text *priv_type_text = PG_GETARG_TEXT_P(1);
1628 AclResult aclresult;
1630 roleid = GetUserId();
1631 databaseoid = convert_database_name(databasename);
1632 mode = convert_database_priv_string(priv_type_text);
1634 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1636 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1640 * has_database_privilege_name_id
1641 * Check user privileges on a database given
1642 * name usename, database oid, and text priv name.
1645 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1647 Name username = PG_GETARG_NAME(0);
1648 Oid databaseoid = PG_GETARG_OID(1);
1649 text *priv_type_text = PG_GETARG_TEXT_P(2);
1652 AclResult aclresult;
1654 roleid = get_roleid_checked(NameStr(*username));
1655 mode = convert_database_priv_string(priv_type_text);
1657 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1659 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1663 * has_database_privilege_id
1664 * Check user privileges on a database given
1665 * database oid, and text priv name.
1666 * current_user is assumed
1669 has_database_privilege_id(PG_FUNCTION_ARGS)
1671 Oid databaseoid = PG_GETARG_OID(0);
1672 text *priv_type_text = PG_GETARG_TEXT_P(1);
1675 AclResult aclresult;
1677 roleid = GetUserId();
1678 mode = convert_database_priv_string(priv_type_text);
1680 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1682 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1686 * has_database_privilege_id_name
1687 * Check user privileges on a database given
1688 * roleid, text databasename, and text priv name.
1691 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1693 Oid roleid = PG_GETARG_OID(0);
1694 text *databasename = PG_GETARG_TEXT_P(1);
1695 text *priv_type_text = PG_GETARG_TEXT_P(2);
1698 AclResult aclresult;
1700 databaseoid = convert_database_name(databasename);
1701 mode = convert_database_priv_string(priv_type_text);
1703 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1705 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1709 * has_database_privilege_id_id
1710 * Check user privileges on a database given
1711 * roleid, database oid, and text priv name.
1714 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1716 Oid roleid = PG_GETARG_OID(0);
1717 Oid databaseoid = PG_GETARG_OID(1);
1718 text *priv_type_text = PG_GETARG_TEXT_P(2);
1720 AclResult aclresult;
1722 mode = convert_database_priv_string(priv_type_text);
1724 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1726 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1730 * Support routines for has_database_privilege family.
1734 * Given a database name expressed as a string, look it up and return Oid
1737 convert_database_name(text *databasename)
1742 dbname = DatumGetCString(DirectFunctionCall1(textout,
1743 PointerGetDatum(databasename)));
1745 oid = get_database_oid(dbname);
1746 if (!OidIsValid(oid))
1748 (errcode(ERRCODE_UNDEFINED_DATABASE),
1749 errmsg("database \"%s\" does not exist", dbname)));
1755 * convert_database_priv_string
1756 * Convert text string to AclMode value.
1759 convert_database_priv_string(text *priv_type_text)
1763 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1764 PointerGetDatum(priv_type_text)));
1767 * Return mode from priv_type string
1769 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1771 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1772 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1774 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1775 return ACL_CREATE_TEMP;
1776 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1777 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1779 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1780 return ACL_CREATE_TEMP;
1781 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1782 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1784 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1786 if (pg_strcasecmp(priv_type, "CONNECT WITH GRANT OPTION") == 0)
1787 return ACL_GRANT_OPTION_FOR(ACL_CONNECT);
1790 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1791 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1792 return ACL_NO_RIGHTS; /* keep compiler quiet */
1797 * has_function_privilege variants
1798 * These are all named "has_function_privilege" at the SQL level.
1799 * They take various combinations of function name, function OID,
1800 * user name, user OID, or implicit user = current_user.
1802 * The result is a boolean value: true if user has the indicated
1803 * privilege, false if not.
1807 * has_function_privilege_name_name
1808 * Check user privileges on a function given
1809 * name username, text functionname, and text priv name.
1812 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1814 Name username = PG_GETARG_NAME(0);
1815 text *functionname = PG_GETARG_TEXT_P(1);
1816 text *priv_type_text = PG_GETARG_TEXT_P(2);
1820 AclResult aclresult;
1822 roleid = get_roleid_checked(NameStr(*username));
1823 functionoid = convert_function_name(functionname);
1824 mode = convert_function_priv_string(priv_type_text);
1826 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1828 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1832 * has_function_privilege_name
1833 * Check user privileges on a function given
1834 * text functionname and text priv name.
1835 * current_user is assumed
1838 has_function_privilege_name(PG_FUNCTION_ARGS)
1840 text *functionname = PG_GETARG_TEXT_P(0);
1841 text *priv_type_text = PG_GETARG_TEXT_P(1);
1845 AclResult aclresult;
1847 roleid = GetUserId();
1848 functionoid = convert_function_name(functionname);
1849 mode = convert_function_priv_string(priv_type_text);
1851 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1853 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1857 * has_function_privilege_name_id
1858 * Check user privileges on a function given
1859 * name usename, function oid, and text priv name.
1862 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1864 Name username = PG_GETARG_NAME(0);
1865 Oid functionoid = PG_GETARG_OID(1);
1866 text *priv_type_text = PG_GETARG_TEXT_P(2);
1869 AclResult aclresult;
1871 roleid = get_roleid_checked(NameStr(*username));
1872 mode = convert_function_priv_string(priv_type_text);
1874 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1876 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1880 * has_function_privilege_id
1881 * Check user privileges on a function given
1882 * function oid, and text priv name.
1883 * current_user is assumed
1886 has_function_privilege_id(PG_FUNCTION_ARGS)
1888 Oid functionoid = PG_GETARG_OID(0);
1889 text *priv_type_text = PG_GETARG_TEXT_P(1);
1892 AclResult aclresult;
1894 roleid = GetUserId();
1895 mode = convert_function_priv_string(priv_type_text);
1897 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1899 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1903 * has_function_privilege_id_name
1904 * Check user privileges on a function given
1905 * roleid, text functionname, and text priv name.
1908 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1910 Oid roleid = PG_GETARG_OID(0);
1911 text *functionname = PG_GETARG_TEXT_P(1);
1912 text *priv_type_text = PG_GETARG_TEXT_P(2);
1915 AclResult aclresult;
1917 functionoid = convert_function_name(functionname);
1918 mode = convert_function_priv_string(priv_type_text);
1920 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1922 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1926 * has_function_privilege_id_id
1927 * Check user privileges on a function given
1928 * roleid, function oid, and text priv name.
1931 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1933 Oid roleid = PG_GETARG_OID(0);
1934 Oid functionoid = PG_GETARG_OID(1);
1935 text *priv_type_text = PG_GETARG_TEXT_P(2);
1937 AclResult aclresult;
1939 mode = convert_function_priv_string(priv_type_text);
1941 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1943 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1947 * Support routines for has_function_privilege family.
1951 * Given a function name expressed as a string, look it up and return Oid
1954 convert_function_name(text *functionname)
1959 funcname = DatumGetCString(DirectFunctionCall1(textout,
1960 PointerGetDatum(functionname)));
1962 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1963 CStringGetDatum(funcname)));
1965 if (!OidIsValid(oid))
1967 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1968 errmsg("function \"%s\" does not exist", funcname)));
1974 * convert_function_priv_string
1975 * Convert text string to AclMode value.
1978 convert_function_priv_string(text *priv_type_text)
1982 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1983 PointerGetDatum(priv_type_text)));
1986 * Return mode from priv_type string
1988 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1990 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1991 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1994 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1995 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1996 return ACL_NO_RIGHTS; /* keep compiler quiet */
2001 * has_language_privilege variants
2002 * These are all named "has_language_privilege" at the SQL level.
2003 * They take various combinations of language name, language OID,
2004 * user name, user OID, or implicit user = current_user.
2006 * The result is a boolean value: true if user has the indicated
2007 * privilege, false if not.
2011 * has_language_privilege_name_name
2012 * Check user privileges on a language given
2013 * name username, text languagename, and text priv name.
2016 has_language_privilege_name_name(PG_FUNCTION_ARGS)
2018 Name username = PG_GETARG_NAME(0);
2019 text *languagename = PG_GETARG_TEXT_P(1);
2020 text *priv_type_text = PG_GETARG_TEXT_P(2);
2024 AclResult aclresult;
2026 roleid = get_roleid_checked(NameStr(*username));
2027 languageoid = convert_language_name(languagename);
2028 mode = convert_language_priv_string(priv_type_text);
2030 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2032 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2036 * has_language_privilege_name
2037 * Check user privileges on a language given
2038 * text languagename and text priv name.
2039 * current_user is assumed
2042 has_language_privilege_name(PG_FUNCTION_ARGS)
2044 text *languagename = PG_GETARG_TEXT_P(0);
2045 text *priv_type_text = PG_GETARG_TEXT_P(1);
2049 AclResult aclresult;
2051 roleid = GetUserId();
2052 languageoid = convert_language_name(languagename);
2053 mode = convert_language_priv_string(priv_type_text);
2055 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2057 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2061 * has_language_privilege_name_id
2062 * Check user privileges on a language given
2063 * name usename, language oid, and text priv name.
2066 has_language_privilege_name_id(PG_FUNCTION_ARGS)
2068 Name username = PG_GETARG_NAME(0);
2069 Oid languageoid = PG_GETARG_OID(1);
2070 text *priv_type_text = PG_GETARG_TEXT_P(2);
2073 AclResult aclresult;
2075 roleid = get_roleid_checked(NameStr(*username));
2076 mode = convert_language_priv_string(priv_type_text);
2078 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2080 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2084 * has_language_privilege_id
2085 * Check user privileges on a language given
2086 * language oid, and text priv name.
2087 * current_user is assumed
2090 has_language_privilege_id(PG_FUNCTION_ARGS)
2092 Oid languageoid = PG_GETARG_OID(0);
2093 text *priv_type_text = PG_GETARG_TEXT_P(1);
2096 AclResult aclresult;
2098 roleid = GetUserId();
2099 mode = convert_language_priv_string(priv_type_text);
2101 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2103 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2107 * has_language_privilege_id_name
2108 * Check user privileges on a language given
2109 * roleid, text languagename, and text priv name.
2112 has_language_privilege_id_name(PG_FUNCTION_ARGS)
2114 Oid roleid = PG_GETARG_OID(0);
2115 text *languagename = PG_GETARG_TEXT_P(1);
2116 text *priv_type_text = PG_GETARG_TEXT_P(2);
2119 AclResult aclresult;
2121 languageoid = convert_language_name(languagename);
2122 mode = convert_language_priv_string(priv_type_text);
2124 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2126 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2130 * has_language_privilege_id_id
2131 * Check user privileges on a language given
2132 * roleid, language oid, and text priv name.
2135 has_language_privilege_id_id(PG_FUNCTION_ARGS)
2137 Oid roleid = PG_GETARG_OID(0);
2138 Oid languageoid = PG_GETARG_OID(1);
2139 text *priv_type_text = PG_GETARG_TEXT_P(2);
2141 AclResult aclresult;
2143 mode = convert_language_priv_string(priv_type_text);
2145 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2147 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2151 * Support routines for has_language_privilege family.
2155 * Given a language name expressed as a string, look it up and return Oid
2158 convert_language_name(text *languagename)
2163 langname = DatumGetCString(DirectFunctionCall1(textout,
2164 PointerGetDatum(languagename)));
2166 oid = GetSysCacheOid(LANGNAME,
2167 CStringGetDatum(langname),
2169 if (!OidIsValid(oid))
2171 (errcode(ERRCODE_UNDEFINED_OBJECT),
2172 errmsg("language \"%s\" does not exist", langname)));
2178 * convert_language_priv_string
2179 * Convert text string to AclMode value.
2182 convert_language_priv_string(text *priv_type_text)
2186 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2187 PointerGetDatum(priv_type_text)));
2190 * Return mode from priv_type string
2192 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2194 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2195 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2198 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2199 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2200 return ACL_NO_RIGHTS; /* keep compiler quiet */
2205 * has_schema_privilege variants
2206 * These are all named "has_schema_privilege" at the SQL level.
2207 * They take various combinations of schema name, schema OID,
2208 * user name, user OID, or implicit user = current_user.
2210 * The result is a boolean value: true if user has the indicated
2211 * privilege, false if not.
2215 * has_schema_privilege_name_name
2216 * Check user privileges on a schema given
2217 * name username, text schemaname, and text priv name.
2220 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2222 Name username = PG_GETARG_NAME(0);
2223 text *schemaname = PG_GETARG_TEXT_P(1);
2224 text *priv_type_text = PG_GETARG_TEXT_P(2);
2228 AclResult aclresult;
2230 roleid = get_roleid_checked(NameStr(*username));
2231 schemaoid = convert_schema_name(schemaname);
2232 mode = convert_schema_priv_string(priv_type_text);
2234 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2236 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2240 * has_schema_privilege_name
2241 * Check user privileges on a schema given
2242 * text schemaname and text priv name.
2243 * current_user is assumed
2246 has_schema_privilege_name(PG_FUNCTION_ARGS)
2248 text *schemaname = PG_GETARG_TEXT_P(0);
2249 text *priv_type_text = PG_GETARG_TEXT_P(1);
2253 AclResult aclresult;
2255 roleid = GetUserId();
2256 schemaoid = convert_schema_name(schemaname);
2257 mode = convert_schema_priv_string(priv_type_text);
2259 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2261 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2265 * has_schema_privilege_name_id
2266 * Check user privileges on a schema given
2267 * name usename, schema oid, and text priv name.
2270 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2272 Name username = PG_GETARG_NAME(0);
2273 Oid schemaoid = PG_GETARG_OID(1);
2274 text *priv_type_text = PG_GETARG_TEXT_P(2);
2277 AclResult aclresult;
2279 roleid = get_roleid_checked(NameStr(*username));
2280 mode = convert_schema_priv_string(priv_type_text);
2282 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2284 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2288 * has_schema_privilege_id
2289 * Check user privileges on a schema given
2290 * schema oid, and text priv name.
2291 * current_user is assumed
2294 has_schema_privilege_id(PG_FUNCTION_ARGS)
2296 Oid schemaoid = PG_GETARG_OID(0);
2297 text *priv_type_text = PG_GETARG_TEXT_P(1);
2300 AclResult aclresult;
2302 roleid = GetUserId();
2303 mode = convert_schema_priv_string(priv_type_text);
2305 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2307 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2311 * has_schema_privilege_id_name
2312 * Check user privileges on a schema given
2313 * roleid, text schemaname, and text priv name.
2316 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2318 Oid roleid = PG_GETARG_OID(0);
2319 text *schemaname = PG_GETARG_TEXT_P(1);
2320 text *priv_type_text = PG_GETARG_TEXT_P(2);
2323 AclResult aclresult;
2325 schemaoid = convert_schema_name(schemaname);
2326 mode = convert_schema_priv_string(priv_type_text);
2328 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2330 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2334 * has_schema_privilege_id_id
2335 * Check user privileges on a schema given
2336 * roleid, schema oid, and text priv name.
2339 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2341 Oid roleid = PG_GETARG_OID(0);
2342 Oid schemaoid = PG_GETARG_OID(1);
2343 text *priv_type_text = PG_GETARG_TEXT_P(2);
2345 AclResult aclresult;
2347 mode = convert_schema_priv_string(priv_type_text);
2349 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2351 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2355 * Support routines for has_schema_privilege family.
2359 * Given a schema name expressed as a string, look it up and return Oid
2362 convert_schema_name(text *schemaname)
2367 nspname = DatumGetCString(DirectFunctionCall1(textout,
2368 PointerGetDatum(schemaname)));
2370 oid = GetSysCacheOid(NAMESPACENAME,
2371 CStringGetDatum(nspname),
2373 if (!OidIsValid(oid))
2375 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2376 errmsg("schema \"%s\" does not exist", nspname)));
2382 * convert_schema_priv_string
2383 * Convert text string to AclMode value.
2386 convert_schema_priv_string(text *priv_type_text)
2390 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2391 PointerGetDatum(priv_type_text)));
2394 * Return mode from priv_type string
2396 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2398 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2399 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2401 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2403 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2404 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2407 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2408 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2409 return ACL_NO_RIGHTS; /* keep compiler quiet */
2413 * has_tablespace_privilege variants
2414 * These are all named "has_tablespace_privilege" at the SQL level.
2415 * They take various combinations of tablespace name, tablespace OID,
2416 * user name, user OID, or implicit user = current_user.
2418 * The result is a boolean value: true if user has the indicated
2419 * privilege, false if not.
2423 * has_tablespace_privilege_name_name
2424 * Check user privileges on a tablespace given
2425 * name username, text tablespacename, and text priv name.
2428 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2430 Name username = PG_GETARG_NAME(0);
2431 text *tablespacename = PG_GETARG_TEXT_P(1);
2432 text *priv_type_text = PG_GETARG_TEXT_P(2);
2436 AclResult aclresult;
2438 roleid = get_roleid_checked(NameStr(*username));
2439 tablespaceoid = convert_tablespace_name(tablespacename);
2440 mode = convert_tablespace_priv_string(priv_type_text);
2442 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2444 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2448 * has_tablespace_privilege_name
2449 * Check user privileges on a tablespace given
2450 * text tablespacename and text priv name.
2451 * current_user is assumed
2454 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2456 text *tablespacename = PG_GETARG_TEXT_P(0);
2457 text *priv_type_text = PG_GETARG_TEXT_P(1);
2461 AclResult aclresult;
2463 roleid = GetUserId();
2464 tablespaceoid = convert_tablespace_name(tablespacename);
2465 mode = convert_tablespace_priv_string(priv_type_text);
2467 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2469 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2473 * has_tablespace_privilege_name_id
2474 * Check user privileges on a tablespace given
2475 * name usename, tablespace oid, and text priv name.
2478 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2480 Name username = PG_GETARG_NAME(0);
2481 Oid tablespaceoid = PG_GETARG_OID(1);
2482 text *priv_type_text = PG_GETARG_TEXT_P(2);
2485 AclResult aclresult;
2487 roleid = get_roleid_checked(NameStr(*username));
2488 mode = convert_tablespace_priv_string(priv_type_text);
2490 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2492 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2496 * has_tablespace_privilege_id
2497 * Check user privileges on a tablespace given
2498 * tablespace oid, and text priv name.
2499 * current_user is assumed
2502 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2504 Oid tablespaceoid = PG_GETARG_OID(0);
2505 text *priv_type_text = PG_GETARG_TEXT_P(1);
2508 AclResult aclresult;
2510 roleid = GetUserId();
2511 mode = convert_tablespace_priv_string(priv_type_text);
2513 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2515 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2519 * has_tablespace_privilege_id_name
2520 * Check user privileges on a tablespace given
2521 * roleid, text tablespacename, and text priv name.
2524 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2526 Oid roleid = PG_GETARG_OID(0);
2527 text *tablespacename = PG_GETARG_TEXT_P(1);
2528 text *priv_type_text = PG_GETARG_TEXT_P(2);
2531 AclResult aclresult;
2533 tablespaceoid = convert_tablespace_name(tablespacename);
2534 mode = convert_tablespace_priv_string(priv_type_text);
2536 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2538 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2542 * has_tablespace_privilege_id_id
2543 * Check user privileges on a tablespace given
2544 * roleid, tablespace oid, and text priv name.
2547 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2549 Oid roleid = PG_GETARG_OID(0);
2550 Oid tablespaceoid = PG_GETARG_OID(1);
2551 text *priv_type_text = PG_GETARG_TEXT_P(2);
2553 AclResult aclresult;
2555 mode = convert_tablespace_priv_string(priv_type_text);
2557 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2559 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2563 * Support routines for has_tablespace_privilege family.
2567 * Given a tablespace name expressed as a string, look it up and return Oid
2570 convert_tablespace_name(text *tablespacename)
2575 spcname = DatumGetCString(DirectFunctionCall1(textout,
2576 PointerGetDatum(tablespacename)));
2577 oid = get_tablespace_oid(spcname);
2579 if (!OidIsValid(oid))
2581 (errcode(ERRCODE_UNDEFINED_OBJECT),
2582 errmsg("tablespace \"%s\" does not exist", spcname)));
2588 * convert_tablespace_priv_string
2589 * Convert text string to AclMode value.
2592 convert_tablespace_priv_string(text *priv_type_text)
2596 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2597 PointerGetDatum(priv_type_text)));
2600 * Return mode from priv_type string
2602 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2604 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2605 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2608 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2609 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2610 return ACL_NO_RIGHTS; /* keep compiler quiet */
2614 * pg_has_role variants
2615 * These are all named "pg_has_role" at the SQL level.
2616 * They take various combinations of role name, role OID,
2617 * user name, user OID, or implicit user = current_user.
2619 * The result is a boolean value: true if user has the indicated
2620 * privilege, false if not.
2624 * pg_has_role_name_name
2625 * Check user privileges on a role given
2626 * name username, name rolename, and text priv name.
2629 pg_has_role_name_name(PG_FUNCTION_ARGS)
2631 Name username = PG_GETARG_NAME(0);
2632 Name rolename = PG_GETARG_NAME(1);
2633 text *priv_type_text = PG_GETARG_TEXT_P(2);
2637 AclResult aclresult;
2639 roleid = get_roleid_checked(NameStr(*username));
2640 roleoid = get_roleid_checked(NameStr(*rolename));
2641 mode = convert_role_priv_string(priv_type_text);
2643 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2645 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2650 * Check user privileges on a role given
2651 * name rolename and text priv name.
2652 * current_user is assumed
2655 pg_has_role_name(PG_FUNCTION_ARGS)
2657 Name rolename = PG_GETARG_NAME(0);
2658 text *priv_type_text = PG_GETARG_TEXT_P(1);
2662 AclResult aclresult;
2664 roleid = GetUserId();
2665 roleoid = get_roleid_checked(NameStr(*rolename));
2666 mode = convert_role_priv_string(priv_type_text);
2668 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2670 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2674 * pg_has_role_name_id
2675 * Check user privileges on a role given
2676 * name usename, role oid, and text priv name.
2679 pg_has_role_name_id(PG_FUNCTION_ARGS)
2681 Name username = PG_GETARG_NAME(0);
2682 Oid roleoid = PG_GETARG_OID(1);
2683 text *priv_type_text = PG_GETARG_TEXT_P(2);
2686 AclResult aclresult;
2688 roleid = get_roleid_checked(NameStr(*username));
2689 mode = convert_role_priv_string(priv_type_text);
2691 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2693 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2698 * Check user privileges on a role given
2699 * role oid, and text priv name.
2700 * current_user is assumed
2703 pg_has_role_id(PG_FUNCTION_ARGS)
2705 Oid roleoid = PG_GETARG_OID(0);
2706 text *priv_type_text = PG_GETARG_TEXT_P(1);
2709 AclResult aclresult;
2711 roleid = GetUserId();
2712 mode = convert_role_priv_string(priv_type_text);
2714 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2716 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2720 * pg_has_role_id_name
2721 * Check user privileges on a role given
2722 * roleid, name rolename, and text priv name.
2725 pg_has_role_id_name(PG_FUNCTION_ARGS)
2727 Oid roleid = PG_GETARG_OID(0);
2728 Name rolename = PG_GETARG_NAME(1);
2729 text *priv_type_text = PG_GETARG_TEXT_P(2);
2732 AclResult aclresult;
2734 roleoid = get_roleid_checked(NameStr(*rolename));
2735 mode = convert_role_priv_string(priv_type_text);
2737 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2739 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2744 * Check user privileges on a role given
2745 * roleid, role oid, and text priv name.
2748 pg_has_role_id_id(PG_FUNCTION_ARGS)
2750 Oid roleid = PG_GETARG_OID(0);
2751 Oid roleoid = PG_GETARG_OID(1);
2752 text *priv_type_text = PG_GETARG_TEXT_P(2);
2754 AclResult aclresult;
2756 mode = convert_role_priv_string(priv_type_text);
2758 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2760 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2764 * Support routines for pg_has_role family.
2768 * convert_role_priv_string
2769 * Convert text string to AclMode value.
2771 * We use USAGE to denote whether the privileges of the role are accessible
2772 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
2773 * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
2774 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
2775 * is shared only with pg_role_aclcheck, below.
2778 convert_role_priv_string(text *priv_type_text)
2782 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2783 PointerGetDatum(priv_type_text)));
2786 * Return mode from priv_type string
2788 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2790 if (pg_strcasecmp(priv_type, "MEMBER") == 0)
2792 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0 ||
2793 pg_strcasecmp(priv_type, "USAGE WITH ADMIN OPTION") == 0 ||
2794 pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0 ||
2795 pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
2796 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2799 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2800 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2801 return ACL_NO_RIGHTS; /* keep compiler quiet */
2806 * Quick-and-dirty support for pg_has_role
2809 pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
2811 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
2813 if (is_admin_of_role(roleid, role_oid))
2816 if (mode & ACL_CREATE)
2818 if (is_member_of_role(roleid, role_oid))
2821 if (mode & ACL_USAGE)
2823 if (has_privs_of_role(roleid, role_oid))
2826 return ACLCHECK_NO_PRIV;
2831 * initialization function (called by InitPostgres)
2834 initialize_acl(void)
2836 if (!IsBootstrapProcessingMode())
2839 * In normal mode, set a callback on any syscache invalidation of
2840 * pg_auth_members rows
2842 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
2843 RoleMembershipCacheCallback,
2849 * RoleMembershipCacheCallback
2850 * Syscache inval callback function
2853 RoleMembershipCacheCallback(Datum arg, Oid relid)
2855 /* Force membership caches to be recomputed on next use */
2856 cached_privs_role = InvalidOid;
2857 cached_member_role = InvalidOid;
2861 /* Check if specified role has rolinherit set */
2863 has_rolinherit(Oid roleid)
2865 bool result = false;
2868 utup = SearchSysCache(AUTHOID,
2869 ObjectIdGetDatum(roleid),
2871 if (HeapTupleIsValid(utup))
2873 result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
2874 ReleaseSysCache(utup);
2881 * Get a list of roles that the specified roleid has the privileges of
2883 * This is defined not to recurse through roles that don't have rolinherit
2884 * set; for such roles, membership implies the ability to do SET ROLE, but
2885 * the privileges are not available until you've done so.
2887 * Since indirect membership testing is relatively expensive, we cache
2888 * a list of memberships. Hence, the result is only guaranteed good until
2889 * the next call of roles_has_privs_of()!
2891 * For the benefit of select_best_grantor, the result is defined to be
2892 * in breadth-first order, ie, closer relationships earlier.
2895 roles_has_privs_of(Oid roleid)
2899 List *new_cached_privs_roles;
2900 MemoryContext oldctx;
2902 /* If cache is already valid, just return the list */
2903 if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
2904 return cached_privs_roles;
2907 * Find all the roles that roleid is a member of, including multi-level
2908 * recursion. The role itself will always be the first element of the
2911 * Each element of the list is scanned to see if it adds any indirect
2912 * memberships. We can use a single list as both the record of
2913 * already-found memberships and the agenda of roles yet to be scanned.
2914 * This is a bit tricky but works because the foreach() macro doesn't
2915 * fetch the next list element until the bottom of the loop.
2917 roles_list = list_make1_oid(roleid);
2919 foreach(l, roles_list)
2921 Oid memberid = lfirst_oid(l);
2925 /* Ignore non-inheriting roles */
2926 if (!has_rolinherit(memberid))
2929 /* Find roles that memberid is directly a member of */
2930 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
2931 ObjectIdGetDatum(memberid),
2933 for (i = 0; i < memlist->n_members; i++)
2935 HeapTuple tup = &memlist->members[i]->tuple;
2936 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
2939 * Even though there shouldn't be any loops in the membership
2940 * graph, we must test for having already seen this role. It is
2941 * legal for instance to have both A->B and A->C->B.
2943 roles_list = list_append_unique_oid(roles_list, otherid);
2945 ReleaseSysCacheList(memlist);
2949 * Copy the completed list into TopMemoryContext so it will persist.
2951 oldctx = MemoryContextSwitchTo(TopMemoryContext);
2952 new_cached_privs_roles = list_copy(roles_list);
2953 MemoryContextSwitchTo(oldctx);
2954 list_free(roles_list);
2957 * Now safe to assign to state variable
2959 cached_privs_role = InvalidOid; /* just paranoia */
2960 list_free(cached_privs_roles);
2961 cached_privs_roles = new_cached_privs_roles;
2962 cached_privs_role = roleid;
2964 /* And now we can return the answer */
2965 return cached_privs_roles;
2970 * Get a list of roles that the specified roleid is a member of
2972 * This is defined to recurse through roles regardless of rolinherit.
2974 * Since indirect membership testing is relatively expensive, we cache
2975 * a list of memberships. Hence, the result is only guaranteed good until
2976 * the next call of roles_is_member_of()!
2979 roles_is_member_of(Oid roleid)
2983 List *new_cached_membership_roles;
2984 MemoryContext oldctx;
2986 /* If cache is already valid, just return the list */
2987 if (OidIsValid(cached_member_role) && cached_member_role == roleid)
2988 return cached_membership_roles;
2991 * Find all the roles that roleid is a member of, including multi-level
2992 * recursion. The role itself will always be the first element of the
2995 * Each element of the list is scanned to see if it adds any indirect
2996 * memberships. We can use a single list as both the record of
2997 * already-found memberships and the agenda of roles yet to be scanned.
2998 * This is a bit tricky but works because the foreach() macro doesn't
2999 * fetch the next list element until the bottom of the loop.
3001 roles_list = list_make1_oid(roleid);
3003 foreach(l, roles_list)
3005 Oid memberid = lfirst_oid(l);
3009 /* Find roles that memberid is directly a member of */
3010 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3011 ObjectIdGetDatum(memberid),
3013 for (i = 0; i < memlist->n_members; i++)
3015 HeapTuple tup = &memlist->members[i]->tuple;
3016 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3019 * Even though there shouldn't be any loops in the membership
3020 * graph, we must test for having already seen this role. It is
3021 * legal for instance to have both A->B and A->C->B.
3023 roles_list = list_append_unique_oid(roles_list, otherid);
3025 ReleaseSysCacheList(memlist);
3029 * Copy the completed list into TopMemoryContext so it will persist.
3031 oldctx = MemoryContextSwitchTo(TopMemoryContext);
3032 new_cached_membership_roles = list_copy(roles_list);
3033 MemoryContextSwitchTo(oldctx);
3034 list_free(roles_list);
3037 * Now safe to assign to state variable
3039 cached_member_role = InvalidOid; /* just paranoia */
3040 list_free(cached_membership_roles);
3041 cached_membership_roles = new_cached_membership_roles;
3042 cached_member_role = roleid;
3044 /* And now we can return the answer */
3045 return cached_membership_roles;
3050 * Does member have the privileges of role (directly or indirectly)?
3052 * This is defined not to recurse through roles that don't have rolinherit
3053 * set; for such roles, membership implies the ability to do SET ROLE, but
3054 * the privileges are not available until you've done so.
3057 has_privs_of_role(Oid member, Oid role)
3059 /* Fast path for simple case */
3063 /* Superusers have every privilege, so are part of every role */
3064 if (superuser_arg(member))
3068 * Find all the roles that member has the privileges of, including
3069 * multi-level recursion, then see if target role is any one of them.
3071 return list_member_oid(roles_has_privs_of(member), role);
3076 * Is member a member of role (directly or indirectly)?
3078 * This is defined to recurse through roles regardless of rolinherit.
3081 is_member_of_role(Oid member, Oid role)
3083 /* Fast path for simple case */
3087 /* Superusers have every privilege, so are part of every role */
3088 if (superuser_arg(member))
3092 * Find all the roles that member is a member of, including multi-level
3093 * recursion, then see if target role is any one of them.
3095 return list_member_oid(roles_is_member_of(member), role);
3099 * check_is_member_of_role
3100 * is_member_of_role with a standard permission-violation error if not
3103 check_is_member_of_role(Oid member, Oid role)
3105 if (!is_member_of_role(member, role))
3107 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3108 errmsg("must be member of role \"%s\"",
3109 GetUserNameFromId(role))));
3113 * Is member a member of role, not considering superuserness?
3115 * This is identical to is_member_of_role except we ignore superuser
3119 is_member_of_role_nosuper(Oid member, Oid role)
3121 /* Fast path for simple case */
3126 * Find all the roles that member is a member of, including multi-level
3127 * recursion, then see if target role is any one of them.
3129 return list_member_oid(roles_is_member_of(member), role);
3134 * Is member an admin of role (directly or indirectly)? That is, is it
3135 * a member WITH ADMIN OPTION?
3137 * We could cache the result as for is_member_of_role, but currently this
3138 * is not used in any performance-critical paths, so we don't.
3141 is_admin_of_role(Oid member, Oid role)
3143 bool result = false;
3147 /* Fast path for simple case */
3151 /* Superusers have every privilege, so are part of every role */
3152 if (superuser_arg(member))
3156 * Find all the roles that member is a member of, including multi-level
3157 * recursion. We build a list in the same way that is_member_of_role does
3158 * to track visited and unvisited roles.
3160 roles_list = list_make1_oid(member);
3162 foreach(l, roles_list)
3164 Oid memberid = lfirst_oid(l);
3168 /* Find roles that memberid is directly a member of */
3169 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3170 ObjectIdGetDatum(memberid),
3172 for (i = 0; i < memlist->n_members; i++)
3174 HeapTuple tup = &memlist->members[i]->tuple;
3175 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3177 if (otherid == role &&
3178 ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
3180 /* Found what we came for, so can stop searching */
3185 roles_list = list_append_unique_oid(roles_list, otherid);
3187 ReleaseSysCacheList(memlist);
3192 list_free(roles_list);
3198 /* does what it says ... */
3200 count_one_bits(AclMode mask)
3204 /* this code relies on AclMode being an unsigned type */
3216 * Select the effective grantor ID for a GRANT or REVOKE operation.
3218 * The grantor must always be either the object owner or some role that has
3219 * been explicitly granted grant options. This ensures that all granted
3220 * privileges appear to flow from the object owner, and there are never
3221 * multiple "original sources" of a privilege. Therefore, if the would-be
3222 * grantor is a member of a role that has the needed grant options, we have
3223 * to do the grant as that role instead.
3225 * It is possible that the would-be grantor is a member of several roles
3226 * that have different subsets of the desired grant options, but no one
3227 * role has 'em all. In this case we pick a role with the largest number
3228 * of desired options. Ties are broken in favor of closer ancestors.
3230 * roleId: the role attempting to do the GRANT/REVOKE
3231 * privileges: the privileges to be granted/revoked
3232 * acl: the ACL of the object in question
3233 * ownerId: the role owning the object in question
3234 * *grantorId: receives the OID of the role to do the grant as
3235 * *grantOptions: receives the grant options actually held by grantorId
3237 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
3240 select_best_grantor(Oid roleId, AclMode privileges,
3241 const Acl *acl, Oid ownerId,
3242 Oid *grantorId, AclMode *grantOptions)
3244 AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
3250 * The object owner is always treated as having all grant options, so if
3251 * roleId is the owner it's easy. Also, if roleId is a superuser it's
3252 * easy: superusers are implicitly members of every role, so they act as
3255 if (roleId == ownerId || superuser_arg(roleId))
3257 *grantorId = ownerId;
3258 *grantOptions = needed_goptions;
3263 * Otherwise we have to do a careful search to see if roleId has the
3264 * privileges of any suitable role. Note: we can hang onto the result of
3265 * roles_has_privs_of() throughout this loop, because aclmask_direct()
3266 * doesn't query any role memberships.
3268 roles_list = roles_has_privs_of(roleId);
3270 /* initialize candidate result as default */
3271 *grantorId = roleId;
3272 *grantOptions = ACL_NO_RIGHTS;
3275 foreach(l, roles_list)
3277 Oid otherrole = lfirst_oid(l);
3280 otherprivs = aclmask_direct(acl, otherrole, ownerId,
3281 needed_goptions, ACLMASK_ALL);
3282 if (otherprivs == needed_goptions)
3284 /* Found a suitable grantor */
3285 *grantorId = otherrole;
3286 *grantOptions = otherprivs;
3291 * If it has just some of the needed privileges, remember best
3294 if (otherprivs != ACL_NO_RIGHTS)
3296 int nnewrights = count_one_bits(otherprivs);
3298 if (nnewrights > nrights)
3300 *grantorId = otherrole;
3301 *grantOptions = otherprivs;
3302 nrights = nnewrights;