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.143 2008/12/15 18:09:41 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, int cacheid, ItemPointer tuplePtr);
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_TRUNCATE_CHR:
271 case ACL_REFERENCES_CHR:
272 read = ACL_REFERENCES;
274 case ACL_TRIGGER_CHR:
277 case ACL_EXECUTE_CHR:
286 case ACL_CREATE_TEMP_CHR:
287 read = ACL_CREATE_TEMP;
289 case ACL_CONNECT_CHR:
292 case 'R': /* ignore old RULE privileges */
297 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
298 errmsg("invalid mode character: must be one of \"%s\"",
299 ACL_ALL_RIGHTS_STR)));
306 aip->ai_grantee = ACL_ID_PUBLIC;
308 aip->ai_grantee = get_roleid_checked(name);
311 * XXX Allow a degree of backward compatibility by defaulting the grantor
316 s = getid(s + 1, name2);
317 if (name2[0] == '\0')
319 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
320 errmsg("a name must follow the \"/\" sign")));
321 aip->ai_grantor = get_roleid_checked(name2);
325 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
327 (errcode(ERRCODE_INVALID_GRANTOR),
328 errmsg("defaulting grantor to user ID %u",
329 BOOTSTRAP_SUPERUSERID)));
332 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
335 elog(LOG, "aclparse: correctly read [%u %x %x]",
336 aip->ai_grantee, privs, goption);
344 * Allocates storage for a new Acl with 'n' entries.
356 elog(ERROR, "invalid size: %d", n);
357 size = ACL_N_SIZE(n);
358 new_acl = (Acl *) palloc0(size);
359 SET_VARSIZE(new_acl, size);
361 new_acl->dataoffset = 0; /* we never put in any nulls */
362 new_acl->elemtype = ACLITEMOID;
363 ARR_LBOUND(new_acl)[0] = 1;
364 ARR_DIMS(new_acl)[0] = n;
369 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
372 check_acl(const Acl *acl)
374 if (ARR_ELEMTYPE(acl) != ACLITEMOID)
376 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
377 errmsg("ACL array contains wrong data type")));
378 if (ARR_NDIM(acl) != 1)
380 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
381 errmsg("ACL arrays must be one-dimensional")));
382 if (ARR_HASNULL(acl))
384 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
385 errmsg("ACL arrays must not contain null values")));
390 * Allocates storage for, and fills in, a new AclItem given a string
391 * 's' that contains an ACL specification. See aclparse for details.
397 aclitemin(PG_FUNCTION_ARGS)
399 const char *s = PG_GETARG_CSTRING(0);
402 aip = (AclItem *) palloc(sizeof(AclItem));
403 s = aclparse(s, aip);
404 while (isspace((unsigned char) *s))
408 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
409 errmsg("extra garbage at the end of the ACL specification")));
411 PG_RETURN_ACLITEM_P(aip);
416 * Allocates storage for, and fills in, a new null-delimited string
417 * containing a formatted ACL specification. See aclparse for details.
423 aclitemout(PG_FUNCTION_ARGS)
425 AclItem *aip = PG_GETARG_ACLITEM_P(0);
431 out = palloc(strlen("=/") +
433 2 * (2 * NAMEDATALEN + 2) +
439 if (aip->ai_grantee != ACL_ID_PUBLIC)
441 htup = SearchSysCache(AUTHOID,
442 ObjectIdGetDatum(aip->ai_grantee),
444 if (HeapTupleIsValid(htup))
446 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
447 ReleaseSysCache(htup);
451 /* Generate numeric OID if we don't find an entry */
452 sprintf(p, "%u", aip->ai_grantee);
460 for (i = 0; i < N_ACL_RIGHTS; ++i)
462 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
463 *p++ = ACL_ALL_RIGHTS_STR[i];
464 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
471 htup = SearchSysCache(AUTHOID,
472 ObjectIdGetDatum(aip->ai_grantor),
474 if (HeapTupleIsValid(htup))
476 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
477 ReleaseSysCache(htup);
481 /* Generate numeric OID if we don't find an entry */
482 sprintf(p, "%u", aip->ai_grantor);
485 PG_RETURN_CSTRING(out);
490 * Two AclItems are considered to match iff they have the same
491 * grantee and grantor; the privileges are ignored.
494 aclitem_match(const AclItem *a1, const AclItem *a2)
496 return a1->ai_grantee == a2->ai_grantee &&
497 a1->ai_grantor == a2->ai_grantor;
501 * aclitem equality operator
504 aclitem_eq(PG_FUNCTION_ARGS)
506 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
507 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
510 result = a1->ai_privs == a2->ai_privs &&
511 a1->ai_grantee == a2->ai_grantee &&
512 a1->ai_grantor == a2->ai_grantor;
513 PG_RETURN_BOOL(result);
517 * aclitem hash function
519 * We make aclitems hashable not so much because anyone is likely to hash
520 * them, as because we want array equality to work on aclitem arrays, and
521 * with the typcache mechanism we must have a hash or btree opclass.
524 hash_aclitem(PG_FUNCTION_ARGS)
526 AclItem *a = PG_GETARG_ACLITEM_P(0);
528 /* not very bright, but avoids any issue of padding in struct */
529 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
534 * acldefault() --- create an ACL describing default access permissions
536 * Change this routine if you want to alter the default access policy for
537 * newly-created objects (or any object with a NULL acl entry).
540 acldefault(GrantObjectType objtype, Oid ownerId)
542 AclMode world_default;
543 AclMode owner_default;
549 case ACL_OBJECT_RELATION:
550 world_default = ACL_NO_RIGHTS;
551 owner_default = ACL_ALL_RIGHTS_RELATION;
553 case ACL_OBJECT_SEQUENCE:
554 world_default = ACL_NO_RIGHTS;
555 owner_default = ACL_ALL_RIGHTS_SEQUENCE;
557 case ACL_OBJECT_DATABASE:
558 /* for backwards compatibility, grant some rights by default */
559 world_default = ACL_CREATE_TEMP | ACL_CONNECT;
560 owner_default = ACL_ALL_RIGHTS_DATABASE;
562 case ACL_OBJECT_FUNCTION:
563 /* Grant EXECUTE by default, for now */
564 world_default = ACL_EXECUTE;
565 owner_default = ACL_ALL_RIGHTS_FUNCTION;
567 case ACL_OBJECT_LANGUAGE:
568 /* Grant USAGE by default, for now */
569 world_default = ACL_USAGE;
570 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
572 case ACL_OBJECT_NAMESPACE:
573 world_default = ACL_NO_RIGHTS;
574 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
576 case ACL_OBJECT_TABLESPACE:
577 world_default = ACL_NO_RIGHTS;
578 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
581 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
582 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
583 owner_default = ACL_NO_RIGHTS;
587 acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);
590 if (world_default != ACL_NO_RIGHTS)
592 aip->ai_grantee = ACL_ID_PUBLIC;
593 aip->ai_grantor = ownerId;
594 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
599 * Note that the owner's entry shows all ordinary privileges but no grant
600 * options. This is because his grant options come "from the system" and
601 * not from his own efforts. (The SQL spec says that the owner's rights
602 * come from a "_SYSTEM" authid.) However, we do consider that the
603 * owner's ordinary privileges are self-granted; this lets him revoke
604 * them. We implement the owner's grant options without any explicit
605 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
606 * whereever we are testing grant options.
608 aip->ai_grantee = ownerId;
609 aip->ai_grantor = ownerId;
610 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
617 * Update an ACL array to add or remove specified privileges.
619 * old_acl: the input ACL array
620 * mod_aip: defines the privileges to be added, removed, or substituted
621 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
622 * ownerId: Oid of object owner
623 * behavior: RESTRICT or CASCADE behavior for recursive removal
625 * ownerid and behavior are only relevant when the update operation specifies
626 * deletion of grant options.
628 * The result is a modified copy; the input object is not changed.
630 * NB: caller is responsible for having detoasted the input ACL, if needed.
633 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
634 int modechg, Oid ownerId, DropBehavior behavior)
646 /* Caller probably already checked old_acl, but be safe */
649 /* If granting grant options, check for circularity */
650 if (modechg != ACL_MODECHG_DEL &&
651 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
652 check_circularity(old_acl, mod_aip, ownerId);
654 num = ACL_NUM(old_acl);
655 old_aip = ACL_DAT(old_acl);
658 * Search the ACL for an existing entry for this grantee and grantor. If
659 * one exists, just modify the entry in-place (well, in the same position,
660 * since we actually return a copy); otherwise, insert the new entry at
664 for (dst = 0; dst < num; ++dst)
666 if (aclitem_match(mod_aip, old_aip + dst))
668 /* found a match, so modify existing item */
669 new_acl = allocacl(num);
670 new_aip = ACL_DAT(new_acl);
671 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
678 /* need to append a new item */
679 new_acl = allocacl(num + 1);
680 new_aip = ACL_DAT(new_acl);
681 memcpy(new_aip, old_aip, num * sizeof(AclItem));
683 /* initialize the new entry with no permissions */
684 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
685 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
686 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
687 ACL_NO_RIGHTS, ACL_NO_RIGHTS);
688 num++; /* set num to the size of new_acl */
691 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
692 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
694 /* apply the specified permissions change */
697 case ACL_MODECHG_ADD:
698 ACLITEM_SET_RIGHTS(new_aip[dst],
699 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
701 case ACL_MODECHG_DEL:
702 ACLITEM_SET_RIGHTS(new_aip[dst],
703 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
705 case ACL_MODECHG_EQL:
706 ACLITEM_SET_RIGHTS(new_aip[dst],
707 ACLITEM_GET_RIGHTS(*mod_aip));
711 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
712 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
715 * If the adjusted entry has no permissions, delete it from the list.
717 if (new_rights == ACL_NO_RIGHTS)
719 memmove(new_aip + dst,
721 (num - dst - 1) * sizeof(AclItem));
722 /* Adjust array size to be 'num - 1' items */
723 ARR_DIMS(new_acl)[0] = num - 1;
724 SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
728 * Remove abandoned privileges (cascading revoke). Currently we can only
729 * handle this when the grantee is not PUBLIC.
731 if ((old_goptions & ~new_goptions) != 0)
733 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
734 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
735 (old_goptions & ~new_goptions),
743 * Update an ACL array to reflect a change of owner to the parent object
745 * old_acl: the input ACL array (must not be NULL)
746 * oldOwnerId: Oid of the old object owner
747 * newOwnerId: Oid of the new object owner
749 * The result is a modified copy; the input object is not changed.
751 * NB: caller is responsible for having detoasted the input ACL, if needed.
754 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
762 bool newpresent = false;
771 * Make a copy of the given ACL, substituting new owner ID for old
772 * wherever it appears as either grantor or grantee. Also note if the new
773 * owner ID is already present.
775 num = ACL_NUM(old_acl);
776 old_aip = ACL_DAT(old_acl);
777 new_acl = allocacl(num);
778 new_aip = ACL_DAT(new_acl);
779 memcpy(new_aip, old_aip, num * sizeof(AclItem));
780 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
782 if (dst_aip->ai_grantor == oldOwnerId)
783 dst_aip->ai_grantor = newOwnerId;
784 else if (dst_aip->ai_grantor == newOwnerId)
786 if (dst_aip->ai_grantee == oldOwnerId)
787 dst_aip->ai_grantee = newOwnerId;
788 else if (dst_aip->ai_grantee == newOwnerId)
793 * If the old ACL contained any references to the new owner, then we may
794 * now have generated an ACL containing duplicate entries. Find them and
795 * merge them so that there are not duplicates. (This is relatively
796 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
797 * be the normal case.)
799 * To simplify deletion of duplicate entries, we temporarily leave them in
800 * the array but set their privilege masks to zero; when we reach such an
801 * entry it's just skipped. (Thus, a side effect of this code will be to
802 * remove privilege-free entries, should there be any in the input.) dst
803 * is the next output slot, targ is the currently considered input slot
804 * (always >= dst), and src scans entries to the right of targ looking for
805 * duplicates. Once an entry has been emitted to dst it is known
806 * duplicate-free and need not be considered anymore.
811 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
813 /* ignore if deleted in an earlier pass */
814 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
816 /* find and merge any duplicates */
817 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
820 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
822 if (aclitem_match(targ_aip, src_aip))
824 ACLITEM_SET_RIGHTS(*targ_aip,
825 ACLITEM_GET_RIGHTS(*targ_aip) |
826 ACLITEM_GET_RIGHTS(*src_aip));
827 /* mark the duplicate deleted */
828 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
831 /* and emit to output */
832 new_aip[dst] = *targ_aip;
835 /* Adjust array size to be 'dst' items */
836 ARR_DIMS(new_acl)[0] = dst;
837 SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
845 * When granting grant options, we must disallow attempts to set up circular
846 * chains of grant options. Suppose A (the object owner) grants B some
847 * privileges with grant option, and B re-grants them to C. If C could
848 * grant the privileges to B as well, then A would be unable to effectively
849 * revoke the privileges from B, since recursive_revoke would consider that
850 * B still has 'em from C.
852 * We check for this by recursively deleting all grant options belonging to
853 * the target grantee, and then seeing if the would-be grantor still has the
854 * grant option or not.
857 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
869 * For now, grant options can only be granted to roles, not PUBLIC.
870 * Otherwise we'd have to work a bit harder here.
872 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
874 /* The owner always has grant options, no need to check */
875 if (mod_aip->ai_grantor == ownerId)
878 /* Make a working copy */
879 acl = allocacl(ACL_NUM(old_acl));
880 memcpy(acl, old_acl, ACL_SIZE(old_acl));
882 /* Zap all grant options of target grantee, plus what depends on 'em */
886 for (i = 0; i < num; i++)
888 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
889 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
893 /* We'll actually zap ordinary privs too, but no matter */
894 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
895 ownerId, DROP_CASCADE);
904 /* Now we can compute grantor's independently-derived privileges */
905 own_privs = aclmask(acl,
908 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
910 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
912 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
914 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
915 errmsg("grant options cannot be granted back to your own grantor")));
922 * Ensure that no privilege is "abandoned". A privilege is abandoned
923 * if the user that granted the privilege loses the grant option. (So
924 * the chain through which it was granted is broken.) Either the
925 * abandoned privileges are revoked as well, or an error message is
926 * printed, depending on the drop behavior option.
928 * acl: the input ACL list
929 * grantee: the user from whom some grant options have been revoked
930 * revoke_privs: the grant options being revoked
931 * ownerId: Oid of object owner
932 * behavior: RESTRICT or CASCADE behavior for recursive removal
934 * The input Acl object is pfree'd if replaced.
937 recursive_revoke(Acl *acl,
939 AclMode revoke_privs,
941 DropBehavior behavior)
950 /* The owner can never truly lose grant options, so short-circuit */
951 if (grantee == ownerId)
954 /* The grantee might still have the privileges via another grantor */
955 still_has = aclmask(acl, grantee, ownerId,
956 ACL_GRANT_OPTION_FOR(revoke_privs),
958 revoke_privs &= ~still_has;
959 if (revoke_privs == ACL_NO_RIGHTS)
965 for (i = 0; i < num; i++)
967 if (aip[i].ai_grantor == grantee
968 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
973 if (behavior == DROP_RESTRICT)
975 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
976 errmsg("dependent privileges exist"),
977 errhint("Use CASCADE to revoke them too.")));
979 mod_acl.ai_grantor = grantee;
980 mod_acl.ai_grantee = aip[i].ai_grantee;
981 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
985 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1000 * aclmask --- compute bitmask of all privileges held by roleid.
1002 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1003 * held by the given roleid according to the given ACL list, ANDed
1004 * with 'mask'. (The point of passing 'mask' is to let the routine
1005 * exit early if all privileges of interest have been found.)
1007 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1008 * is known true. (This lets us exit soonest in cases where the
1009 * caller is only going to test for zero or nonzero result.)
1013 * To see if any of a set of privileges are held:
1014 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1016 * To see if all of a set of privileges are held:
1017 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1019 * To determine exactly which of a set of privileges are held:
1020 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1023 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1024 AclMode mask, AclMaskHow how)
1033 * Null ACL should not happen, since caller should have inserted
1034 * appropriate default
1037 elog(ERROR, "null ACL");
1041 /* Quick exit for mask == 0 */
1047 /* Owner always implicitly has all grant options */
1048 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1049 has_privs_of_role(roleid, ownerId))
1051 result = mask & ACLITEM_ALL_GOPTION_BITS;
1052 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1057 aidat = ACL_DAT(acl);
1060 * Check privileges granted directly to roleid or to public
1062 for (i = 0; i < num; i++)
1064 AclItem *aidata = &aidat[i];
1066 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1067 aidata->ai_grantee == roleid)
1069 result |= aidata->ai_privs & mask;
1070 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1076 * Check privileges granted indirectly via role memberships. We do this in
1077 * a separate pass to minimize expensive indirect membership tests. In
1078 * particular, it's worth testing whether a given ACL entry grants any
1079 * privileges still of interest before we perform the has_privs_of_role
1082 remaining = mask & ~result;
1083 for (i = 0; i < num; i++)
1085 AclItem *aidata = &aidat[i];
1087 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1088 aidata->ai_grantee == roleid)
1089 continue; /* already checked it */
1091 if ((aidata->ai_privs & remaining) &&
1092 has_privs_of_role(roleid, aidata->ai_grantee))
1094 result |= aidata->ai_privs & mask;
1095 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1097 remaining = mask & ~result;
1106 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1108 * This is exactly like aclmask() except that we consider only privileges
1109 * held *directly* by roleid, not those inherited via role membership.
1112 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1113 AclMode mask, AclMaskHow how)
1121 * Null ACL should not happen, since caller should have inserted
1122 * appropriate default
1125 elog(ERROR, "null ACL");
1129 /* Quick exit for mask == 0 */
1135 /* Owner always implicitly has all grant options */
1136 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1139 result = mask & ACLITEM_ALL_GOPTION_BITS;
1140 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1145 aidat = ACL_DAT(acl);
1148 * Check privileges granted directly to roleid (and not to public)
1150 for (i = 0; i < num; i++)
1152 AclItem *aidata = &aidat[i];
1154 if (aidata->ai_grantee == roleid)
1156 result |= aidata->ai_privs & mask;
1157 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1168 * Find out all the roleids mentioned in an Acl.
1169 * Note that we do not distinguish grantors from grantees.
1171 * *roleids is set to point to a palloc'd array containing distinct OIDs
1172 * in sorted order. The length of the array is the function result.
1175 aclmembers(const Acl *acl, Oid **roleids)
1178 const AclItem *acldat;
1183 if (acl == NULL || ACL_NUM(acl) == 0)
1191 /* Allocate the worst-case space requirement */
1192 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1193 acldat = ACL_DAT(acl);
1196 * Walk the ACL collecting mentioned RoleIds.
1199 for (i = 0; i < ACL_NUM(acl); i++)
1201 const AclItem *ai = &acldat[i];
1203 if (ai->ai_grantee != ACL_ID_PUBLIC)
1204 list[j++] = ai->ai_grantee;
1205 /* grantor is currently never PUBLIC, but let's check anyway */
1206 if (ai->ai_grantor != ACL_ID_PUBLIC)
1207 list[j++] = ai->ai_grantor;
1210 /* Sort the array */
1211 qsort(list, j, sizeof(Oid), oidComparator);
1213 /* Remove duplicates from the array */
1215 for (i = 1; i < j; i++)
1217 if (list[k] != list[i])
1218 list[++k] = list[i];
1222 * We could repalloc the array down to minimum size, but it's hardly worth
1223 * it since it's only transient memory.
1232 * qsort comparison function for Oids
1235 oidComparator(const void *arg1, const void *arg2)
1237 Oid oid1 = *(const Oid *) arg1;
1238 Oid oid2 = *(const Oid *) arg2;
1249 * aclinsert (exported function)
1252 aclinsert(PG_FUNCTION_ARGS)
1255 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1256 errmsg("aclinsert is no longer supported")));
1258 PG_RETURN_NULL(); /* keep compiler quiet */
1262 aclremove(PG_FUNCTION_ARGS)
1265 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1266 errmsg("aclremove is no longer supported")));
1268 PG_RETURN_NULL(); /* keep compiler quiet */
1272 aclcontains(PG_FUNCTION_ARGS)
1274 Acl *acl = PG_GETARG_ACL_P(0);
1275 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1282 aidat = ACL_DAT(acl);
1283 for (i = 0; i < num; ++i)
1285 if (aip->ai_grantee == aidat[i].ai_grantee &&
1286 aip->ai_grantor == aidat[i].ai_grantor &&
1287 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1288 PG_RETURN_BOOL(true);
1290 PG_RETURN_BOOL(false);
1294 makeaclitem(PG_FUNCTION_ARGS)
1296 Oid grantee = PG_GETARG_OID(0);
1297 Oid grantor = PG_GETARG_OID(1);
1298 text *privtext = PG_GETARG_TEXT_P(2);
1299 bool goption = PG_GETARG_BOOL(3);
1303 priv = convert_priv_string(privtext);
1305 result = (AclItem *) palloc(sizeof(AclItem));
1307 result->ai_grantee = grantee;
1308 result->ai_grantor = grantor;
1310 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1311 (goption ? priv : ACL_NO_RIGHTS));
1313 PG_RETURN_ACLITEM_P(result);
1317 convert_priv_string(text *priv_type_text)
1319 char *priv_type = text_to_cstring(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, "TRUNCATE") == 0)
1330 return ACL_TRUNCATE;
1331 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1332 return ACL_REFERENCES;
1333 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1335 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1337 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1339 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1341 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1342 return ACL_CREATE_TEMP;
1343 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1344 return ACL_CREATE_TEMP;
1345 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1347 if (pg_strcasecmp(priv_type, "RULE") == 0)
1348 return 0; /* ignore old RULE privileges */
1351 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1352 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1353 return ACL_NO_RIGHTS; /* keep compiler quiet */
1358 * has_table_privilege variants
1359 * These are all named "has_table_privilege" at the SQL level.
1360 * They take various combinations of relation name, relation OID,
1361 * user name, user OID, or implicit user = current_user.
1363 * The result is a boolean value: true if user has the indicated
1364 * privilege, false if not. The variants that take a relation OID
1365 * return NULL if the OID doesn't exist (rather than failing, as
1366 * they did before Postgres 8.4).
1370 * has_table_privilege_name_name
1371 * Check user privileges on a table given
1372 * name username, text tablename, and text priv name.
1375 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1377 Name rolename = PG_GETARG_NAME(0);
1378 text *tablename = PG_GETARG_TEXT_P(1);
1379 text *priv_type_text = PG_GETARG_TEXT_P(2);
1383 AclResult aclresult;
1385 roleid = get_roleid_checked(NameStr(*rolename));
1386 tableoid = convert_table_name(tablename);
1387 mode = convert_table_priv_string(priv_type_text);
1389 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1391 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1395 * has_table_privilege_name
1396 * Check user privileges on a table given
1397 * text tablename and text priv name.
1398 * current_user is assumed
1401 has_table_privilege_name(PG_FUNCTION_ARGS)
1403 text *tablename = PG_GETARG_TEXT_P(0);
1404 text *priv_type_text = PG_GETARG_TEXT_P(1);
1408 AclResult aclresult;
1410 roleid = GetUserId();
1411 tableoid = convert_table_name(tablename);
1412 mode = convert_table_priv_string(priv_type_text);
1414 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1416 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1420 * has_table_privilege_name_id
1421 * Check user privileges on a table given
1422 * name usename, table oid, and text priv name.
1425 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1427 Name username = PG_GETARG_NAME(0);
1428 Oid tableoid = PG_GETARG_OID(1);
1429 text *priv_type_text = PG_GETARG_TEXT_P(2);
1432 AclResult aclresult;
1434 roleid = get_roleid_checked(NameStr(*username));
1435 mode = convert_table_priv_string(priv_type_text);
1437 if (!SearchSysCacheExists(RELOID,
1438 ObjectIdGetDatum(tableoid),
1442 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1444 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1448 * has_table_privilege_id
1449 * Check user privileges on a table given
1450 * table oid, and text priv name.
1451 * current_user is assumed
1454 has_table_privilege_id(PG_FUNCTION_ARGS)
1456 Oid tableoid = PG_GETARG_OID(0);
1457 text *priv_type_text = PG_GETARG_TEXT_P(1);
1460 AclResult aclresult;
1462 roleid = GetUserId();
1463 mode = convert_table_priv_string(priv_type_text);
1465 if (!SearchSysCacheExists(RELOID,
1466 ObjectIdGetDatum(tableoid),
1470 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1472 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1476 * has_table_privilege_id_name
1477 * Check user privileges on a table given
1478 * roleid, text tablename, and text priv name.
1481 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1483 Oid roleid = PG_GETARG_OID(0);
1484 text *tablename = PG_GETARG_TEXT_P(1);
1485 text *priv_type_text = PG_GETARG_TEXT_P(2);
1488 AclResult aclresult;
1490 tableoid = convert_table_name(tablename);
1491 mode = convert_table_priv_string(priv_type_text);
1493 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1495 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1499 * has_table_privilege_id_id
1500 * Check user privileges on a table given
1501 * roleid, table oid, and text priv name.
1504 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1506 Oid roleid = PG_GETARG_OID(0);
1507 Oid tableoid = PG_GETARG_OID(1);
1508 text *priv_type_text = PG_GETARG_TEXT_P(2);
1510 AclResult aclresult;
1512 mode = convert_table_priv_string(priv_type_text);
1514 if (!SearchSysCacheExists(RELOID,
1515 ObjectIdGetDatum(tableoid),
1519 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1521 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1525 * Support routines for has_table_privilege family.
1529 * Given a table name expressed as a string, look it up and return Oid
1532 convert_table_name(text *tablename)
1536 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1538 return RangeVarGetRelid(relrv, false);
1542 * convert_table_priv_string
1543 * Convert text string to AclMode value.
1546 convert_table_priv_string(text *priv_type_text)
1548 char *priv_type = text_to_cstring(priv_type_text);
1551 * Return mode from priv_type string
1553 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1555 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1556 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1558 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1560 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1561 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1563 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1565 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1566 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1568 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1570 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1571 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1573 if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
1574 return ACL_TRUNCATE;
1575 if (pg_strcasecmp(priv_type, "TRUNCATE WITH GRANT OPTION") == 0)
1576 return ACL_GRANT_OPTION_FOR(ACL_TRUNCATE);
1578 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1579 return ACL_REFERENCES;
1580 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1581 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1583 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1585 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1586 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1588 if (pg_strcasecmp(priv_type, "RULE") == 0)
1589 return 0; /* ignore old RULE privileges */
1590 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1594 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1595 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1596 return ACL_NO_RIGHTS; /* keep compiler quiet */
1601 * has_database_privilege variants
1602 * These are all named "has_database_privilege" at the SQL level.
1603 * They take various combinations of database name, database OID,
1604 * user name, user OID, or implicit user = current_user.
1606 * The result is a boolean value: true if user has the indicated
1607 * privilege, false if not, or NULL if object doesn't exist.
1611 * has_database_privilege_name_name
1612 * Check user privileges on a database given
1613 * name username, text databasename, and text priv name.
1616 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1618 Name username = PG_GETARG_NAME(0);
1619 text *databasename = PG_GETARG_TEXT_P(1);
1620 text *priv_type_text = PG_GETARG_TEXT_P(2);
1624 AclResult aclresult;
1626 roleid = get_roleid_checked(NameStr(*username));
1627 databaseoid = convert_database_name(databasename);
1628 mode = convert_database_priv_string(priv_type_text);
1630 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1632 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1636 * has_database_privilege_name
1637 * Check user privileges on a database given
1638 * text databasename and text priv name.
1639 * current_user is assumed
1642 has_database_privilege_name(PG_FUNCTION_ARGS)
1644 text *databasename = PG_GETARG_TEXT_P(0);
1645 text *priv_type_text = PG_GETARG_TEXT_P(1);
1649 AclResult aclresult;
1651 roleid = GetUserId();
1652 databaseoid = convert_database_name(databasename);
1653 mode = convert_database_priv_string(priv_type_text);
1655 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1657 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1661 * has_database_privilege_name_id
1662 * Check user privileges on a database given
1663 * name usename, database oid, and text priv name.
1666 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1668 Name username = PG_GETARG_NAME(0);
1669 Oid databaseoid = PG_GETARG_OID(1);
1670 text *priv_type_text = PG_GETARG_TEXT_P(2);
1673 AclResult aclresult;
1675 roleid = get_roleid_checked(NameStr(*username));
1676 mode = convert_database_priv_string(priv_type_text);
1678 if (!SearchSysCacheExists(DATABASEOID,
1679 ObjectIdGetDatum(databaseoid),
1683 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1685 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1689 * has_database_privilege_id
1690 * Check user privileges on a database given
1691 * database oid, and text priv name.
1692 * current_user is assumed
1695 has_database_privilege_id(PG_FUNCTION_ARGS)
1697 Oid databaseoid = PG_GETARG_OID(0);
1698 text *priv_type_text = PG_GETARG_TEXT_P(1);
1701 AclResult aclresult;
1703 roleid = GetUserId();
1704 mode = convert_database_priv_string(priv_type_text);
1706 if (!SearchSysCacheExists(DATABASEOID,
1707 ObjectIdGetDatum(databaseoid),
1711 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1713 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1717 * has_database_privilege_id_name
1718 * Check user privileges on a database given
1719 * roleid, text databasename, and text priv name.
1722 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1724 Oid roleid = PG_GETARG_OID(0);
1725 text *databasename = PG_GETARG_TEXT_P(1);
1726 text *priv_type_text = PG_GETARG_TEXT_P(2);
1729 AclResult aclresult;
1731 databaseoid = convert_database_name(databasename);
1732 mode = convert_database_priv_string(priv_type_text);
1734 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1736 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1740 * has_database_privilege_id_id
1741 * Check user privileges on a database given
1742 * roleid, database oid, and text priv name.
1745 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1747 Oid roleid = PG_GETARG_OID(0);
1748 Oid databaseoid = PG_GETARG_OID(1);
1749 text *priv_type_text = PG_GETARG_TEXT_P(2);
1751 AclResult aclresult;
1753 mode = convert_database_priv_string(priv_type_text);
1755 if (!SearchSysCacheExists(DATABASEOID,
1756 ObjectIdGetDatum(databaseoid),
1760 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1762 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1766 * Support routines for has_database_privilege family.
1770 * Given a database name expressed as a string, look it up and return Oid
1773 convert_database_name(text *databasename)
1775 char *dbname = text_to_cstring(databasename);
1778 oid = get_database_oid(dbname);
1779 if (!OidIsValid(oid))
1781 (errcode(ERRCODE_UNDEFINED_DATABASE),
1782 errmsg("database \"%s\" does not exist", dbname)));
1788 * convert_database_priv_string
1789 * Convert text string to AclMode value.
1792 convert_database_priv_string(text *priv_type_text)
1794 char *priv_type = text_to_cstring(priv_type_text);
1797 * Return mode from priv_type string
1799 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1801 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1802 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1804 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1805 return ACL_CREATE_TEMP;
1806 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1807 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1809 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1810 return ACL_CREATE_TEMP;
1811 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1812 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1814 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1816 if (pg_strcasecmp(priv_type, "CONNECT WITH GRANT OPTION") == 0)
1817 return ACL_GRANT_OPTION_FOR(ACL_CONNECT);
1820 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1821 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1822 return ACL_NO_RIGHTS; /* keep compiler quiet */
1827 * has_function_privilege variants
1828 * These are all named "has_function_privilege" at the SQL level.
1829 * They take various combinations of function name, function OID,
1830 * user name, user OID, or implicit user = current_user.
1832 * The result is a boolean value: true if user has the indicated
1833 * privilege, false if not, or NULL if object doesn't exist.
1837 * has_function_privilege_name_name
1838 * Check user privileges on a function given
1839 * name username, text functionname, and text priv name.
1842 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1844 Name username = PG_GETARG_NAME(0);
1845 text *functionname = PG_GETARG_TEXT_P(1);
1846 text *priv_type_text = PG_GETARG_TEXT_P(2);
1850 AclResult aclresult;
1852 roleid = get_roleid_checked(NameStr(*username));
1853 functionoid = convert_function_name(functionname);
1854 mode = convert_function_priv_string(priv_type_text);
1856 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1858 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1862 * has_function_privilege_name
1863 * Check user privileges on a function given
1864 * text functionname and text priv name.
1865 * current_user is assumed
1868 has_function_privilege_name(PG_FUNCTION_ARGS)
1870 text *functionname = PG_GETARG_TEXT_P(0);
1871 text *priv_type_text = PG_GETARG_TEXT_P(1);
1875 AclResult aclresult;
1877 roleid = GetUserId();
1878 functionoid = convert_function_name(functionname);
1879 mode = convert_function_priv_string(priv_type_text);
1881 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1883 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1887 * has_function_privilege_name_id
1888 * Check user privileges on a function given
1889 * name usename, function oid, and text priv name.
1892 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1894 Name username = PG_GETARG_NAME(0);
1895 Oid functionoid = PG_GETARG_OID(1);
1896 text *priv_type_text = PG_GETARG_TEXT_P(2);
1899 AclResult aclresult;
1901 roleid = get_roleid_checked(NameStr(*username));
1902 mode = convert_function_priv_string(priv_type_text);
1904 if (!SearchSysCacheExists(PROCOID,
1905 ObjectIdGetDatum(functionoid),
1909 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1911 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1915 * has_function_privilege_id
1916 * Check user privileges on a function given
1917 * function oid, and text priv name.
1918 * current_user is assumed
1921 has_function_privilege_id(PG_FUNCTION_ARGS)
1923 Oid functionoid = PG_GETARG_OID(0);
1924 text *priv_type_text = PG_GETARG_TEXT_P(1);
1927 AclResult aclresult;
1929 roleid = GetUserId();
1930 mode = convert_function_priv_string(priv_type_text);
1932 if (!SearchSysCacheExists(PROCOID,
1933 ObjectIdGetDatum(functionoid),
1937 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1939 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1943 * has_function_privilege_id_name
1944 * Check user privileges on a function given
1945 * roleid, text functionname, and text priv name.
1948 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1950 Oid roleid = PG_GETARG_OID(0);
1951 text *functionname = PG_GETARG_TEXT_P(1);
1952 text *priv_type_text = PG_GETARG_TEXT_P(2);
1955 AclResult aclresult;
1957 functionoid = convert_function_name(functionname);
1958 mode = convert_function_priv_string(priv_type_text);
1960 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1962 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1966 * has_function_privilege_id_id
1967 * Check user privileges on a function given
1968 * roleid, function oid, and text priv name.
1971 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1973 Oid roleid = PG_GETARG_OID(0);
1974 Oid functionoid = PG_GETARG_OID(1);
1975 text *priv_type_text = PG_GETARG_TEXT_P(2);
1977 AclResult aclresult;
1979 mode = convert_function_priv_string(priv_type_text);
1981 if (!SearchSysCacheExists(PROCOID,
1982 ObjectIdGetDatum(functionoid),
1986 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1988 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1992 * Support routines for has_function_privilege family.
1996 * Given a function name expressed as a string, look it up and return Oid
1999 convert_function_name(text *functionname)
2001 char *funcname = text_to_cstring(functionname);
2004 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
2005 CStringGetDatum(funcname)));
2007 if (!OidIsValid(oid))
2009 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2010 errmsg("function \"%s\" does not exist", funcname)));
2016 * convert_function_priv_string
2017 * Convert text string to AclMode value.
2020 convert_function_priv_string(text *priv_type_text)
2022 char *priv_type = text_to_cstring(priv_type_text);
2025 * Return mode from priv_type string
2027 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
2029 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
2030 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
2033 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2034 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2035 return ACL_NO_RIGHTS; /* keep compiler quiet */
2040 * has_language_privilege variants
2041 * These are all named "has_language_privilege" at the SQL level.
2042 * They take various combinations of language name, language OID,
2043 * user name, user OID, or implicit user = current_user.
2045 * The result is a boolean value: true if user has the indicated
2046 * privilege, false if not, or NULL if object doesn't exist.
2050 * has_language_privilege_name_name
2051 * Check user privileges on a language given
2052 * name username, text languagename, and text priv name.
2055 has_language_privilege_name_name(PG_FUNCTION_ARGS)
2057 Name username = PG_GETARG_NAME(0);
2058 text *languagename = PG_GETARG_TEXT_P(1);
2059 text *priv_type_text = PG_GETARG_TEXT_P(2);
2063 AclResult aclresult;
2065 roleid = get_roleid_checked(NameStr(*username));
2066 languageoid = convert_language_name(languagename);
2067 mode = convert_language_priv_string(priv_type_text);
2069 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2071 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2075 * has_language_privilege_name
2076 * Check user privileges on a language given
2077 * text languagename and text priv name.
2078 * current_user is assumed
2081 has_language_privilege_name(PG_FUNCTION_ARGS)
2083 text *languagename = PG_GETARG_TEXT_P(0);
2084 text *priv_type_text = PG_GETARG_TEXT_P(1);
2088 AclResult aclresult;
2090 roleid = GetUserId();
2091 languageoid = convert_language_name(languagename);
2092 mode = convert_language_priv_string(priv_type_text);
2094 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2096 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2100 * has_language_privilege_name_id
2101 * Check user privileges on a language given
2102 * name usename, language oid, and text priv name.
2105 has_language_privilege_name_id(PG_FUNCTION_ARGS)
2107 Name username = PG_GETARG_NAME(0);
2108 Oid languageoid = PG_GETARG_OID(1);
2109 text *priv_type_text = PG_GETARG_TEXT_P(2);
2112 AclResult aclresult;
2114 roleid = get_roleid_checked(NameStr(*username));
2115 mode = convert_language_priv_string(priv_type_text);
2117 if (!SearchSysCacheExists(LANGOID,
2118 ObjectIdGetDatum(languageoid),
2122 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2124 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2128 * has_language_privilege_id
2129 * Check user privileges on a language given
2130 * language oid, and text priv name.
2131 * current_user is assumed
2134 has_language_privilege_id(PG_FUNCTION_ARGS)
2136 Oid languageoid = PG_GETARG_OID(0);
2137 text *priv_type_text = PG_GETARG_TEXT_P(1);
2140 AclResult aclresult;
2142 roleid = GetUserId();
2143 mode = convert_language_priv_string(priv_type_text);
2145 if (!SearchSysCacheExists(LANGOID,
2146 ObjectIdGetDatum(languageoid),
2150 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2152 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2156 * has_language_privilege_id_name
2157 * Check user privileges on a language given
2158 * roleid, text languagename, and text priv name.
2161 has_language_privilege_id_name(PG_FUNCTION_ARGS)
2163 Oid roleid = PG_GETARG_OID(0);
2164 text *languagename = PG_GETARG_TEXT_P(1);
2165 text *priv_type_text = PG_GETARG_TEXT_P(2);
2168 AclResult aclresult;
2170 languageoid = convert_language_name(languagename);
2171 mode = convert_language_priv_string(priv_type_text);
2173 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2175 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2179 * has_language_privilege_id_id
2180 * Check user privileges on a language given
2181 * roleid, language oid, and text priv name.
2184 has_language_privilege_id_id(PG_FUNCTION_ARGS)
2186 Oid roleid = PG_GETARG_OID(0);
2187 Oid languageoid = PG_GETARG_OID(1);
2188 text *priv_type_text = PG_GETARG_TEXT_P(2);
2190 AclResult aclresult;
2192 mode = convert_language_priv_string(priv_type_text);
2194 if (!SearchSysCacheExists(LANGOID,
2195 ObjectIdGetDatum(languageoid),
2199 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2201 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2205 * Support routines for has_language_privilege family.
2209 * Given a language name expressed as a string, look it up and return Oid
2212 convert_language_name(text *languagename)
2214 char *langname = text_to_cstring(languagename);
2217 oid = GetSysCacheOid(LANGNAME,
2218 CStringGetDatum(langname),
2220 if (!OidIsValid(oid))
2222 (errcode(ERRCODE_UNDEFINED_OBJECT),
2223 errmsg("language \"%s\" does not exist", langname)));
2229 * convert_language_priv_string
2230 * Convert text string to AclMode value.
2233 convert_language_priv_string(text *priv_type_text)
2235 char *priv_type = text_to_cstring(priv_type_text);
2238 * Return mode from priv_type string
2240 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2242 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2243 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2246 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2247 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2248 return ACL_NO_RIGHTS; /* keep compiler quiet */
2253 * has_schema_privilege variants
2254 * These are all named "has_schema_privilege" at the SQL level.
2255 * They take various combinations of schema name, schema OID,
2256 * user name, user OID, or implicit user = current_user.
2258 * The result is a boolean value: true if user has the indicated
2259 * privilege, false if not, or NULL if object doesn't exist.
2263 * has_schema_privilege_name_name
2264 * Check user privileges on a schema given
2265 * name username, text schemaname, and text priv name.
2268 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2270 Name username = PG_GETARG_NAME(0);
2271 text *schemaname = PG_GETARG_TEXT_P(1);
2272 text *priv_type_text = PG_GETARG_TEXT_P(2);
2276 AclResult aclresult;
2278 roleid = get_roleid_checked(NameStr(*username));
2279 schemaoid = convert_schema_name(schemaname);
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_name
2289 * Check user privileges on a schema given
2290 * text schemaname and text priv name.
2291 * current_user is assumed
2294 has_schema_privilege_name(PG_FUNCTION_ARGS)
2296 text *schemaname = PG_GETARG_TEXT_P(0);
2297 text *priv_type_text = PG_GETARG_TEXT_P(1);
2301 AclResult aclresult;
2303 roleid = GetUserId();
2304 schemaoid = convert_schema_name(schemaname);
2305 mode = convert_schema_priv_string(priv_type_text);
2307 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2309 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2313 * has_schema_privilege_name_id
2314 * Check user privileges on a schema given
2315 * name usename, schema oid, and text priv name.
2318 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2320 Name username = PG_GETARG_NAME(0);
2321 Oid schemaoid = PG_GETARG_OID(1);
2322 text *priv_type_text = PG_GETARG_TEXT_P(2);
2325 AclResult aclresult;
2327 roleid = get_roleid_checked(NameStr(*username));
2328 mode = convert_schema_priv_string(priv_type_text);
2330 if (!SearchSysCacheExists(NAMESPACEOID,
2331 ObjectIdGetDatum(schemaoid),
2335 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2337 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2341 * has_schema_privilege_id
2342 * Check user privileges on a schema given
2343 * schema oid, and text priv name.
2344 * current_user is assumed
2347 has_schema_privilege_id(PG_FUNCTION_ARGS)
2349 Oid schemaoid = PG_GETARG_OID(0);
2350 text *priv_type_text = PG_GETARG_TEXT_P(1);
2353 AclResult aclresult;
2355 roleid = GetUserId();
2356 mode = convert_schema_priv_string(priv_type_text);
2358 if (!SearchSysCacheExists(NAMESPACEOID,
2359 ObjectIdGetDatum(schemaoid),
2363 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2365 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2369 * has_schema_privilege_id_name
2370 * Check user privileges on a schema given
2371 * roleid, text schemaname, and text priv name.
2374 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2376 Oid roleid = PG_GETARG_OID(0);
2377 text *schemaname = PG_GETARG_TEXT_P(1);
2378 text *priv_type_text = PG_GETARG_TEXT_P(2);
2381 AclResult aclresult;
2383 schemaoid = convert_schema_name(schemaname);
2384 mode = convert_schema_priv_string(priv_type_text);
2386 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2388 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2392 * has_schema_privilege_id_id
2393 * Check user privileges on a schema given
2394 * roleid, schema oid, and text priv name.
2397 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2399 Oid roleid = PG_GETARG_OID(0);
2400 Oid schemaoid = PG_GETARG_OID(1);
2401 text *priv_type_text = PG_GETARG_TEXT_P(2);
2403 AclResult aclresult;
2405 mode = convert_schema_priv_string(priv_type_text);
2407 if (!SearchSysCacheExists(NAMESPACEOID,
2408 ObjectIdGetDatum(schemaoid),
2412 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2414 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2418 * Support routines for has_schema_privilege family.
2422 * Given a schema name expressed as a string, look it up and return Oid
2425 convert_schema_name(text *schemaname)
2427 char *nspname = text_to_cstring(schemaname);
2430 oid = GetSysCacheOid(NAMESPACENAME,
2431 CStringGetDatum(nspname),
2433 if (!OidIsValid(oid))
2435 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2436 errmsg("schema \"%s\" does not exist", nspname)));
2442 * convert_schema_priv_string
2443 * Convert text string to AclMode value.
2446 convert_schema_priv_string(text *priv_type_text)
2448 char *priv_type = text_to_cstring(priv_type_text);
2451 * Return mode from priv_type string
2453 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2455 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2456 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2458 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2460 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2461 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2464 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2465 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2466 return ACL_NO_RIGHTS; /* keep compiler quiet */
2470 * has_tablespace_privilege variants
2471 * These are all named "has_tablespace_privilege" at the SQL level.
2472 * They take various combinations of tablespace name, tablespace OID,
2473 * user name, user OID, or implicit user = current_user.
2475 * The result is a boolean value: true if user has the indicated
2476 * privilege, false if not.
2480 * has_tablespace_privilege_name_name
2481 * Check user privileges on a tablespace given
2482 * name username, text tablespacename, and text priv name.
2485 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2487 Name username = PG_GETARG_NAME(0);
2488 text *tablespacename = PG_GETARG_TEXT_P(1);
2489 text *priv_type_text = PG_GETARG_TEXT_P(2);
2493 AclResult aclresult;
2495 roleid = get_roleid_checked(NameStr(*username));
2496 tablespaceoid = convert_tablespace_name(tablespacename);
2497 mode = convert_tablespace_priv_string(priv_type_text);
2499 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2501 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2505 * has_tablespace_privilege_name
2506 * Check user privileges on a tablespace given
2507 * text tablespacename and text priv name.
2508 * current_user is assumed
2511 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2513 text *tablespacename = PG_GETARG_TEXT_P(0);
2514 text *priv_type_text = PG_GETARG_TEXT_P(1);
2518 AclResult aclresult;
2520 roleid = GetUserId();
2521 tablespaceoid = convert_tablespace_name(tablespacename);
2522 mode = convert_tablespace_priv_string(priv_type_text);
2524 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2526 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2530 * has_tablespace_privilege_name_id
2531 * Check user privileges on a tablespace given
2532 * name usename, tablespace oid, and text priv name.
2535 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2537 Name username = PG_GETARG_NAME(0);
2538 Oid tablespaceoid = PG_GETARG_OID(1);
2539 text *priv_type_text = PG_GETARG_TEXT_P(2);
2542 AclResult aclresult;
2544 roleid = get_roleid_checked(NameStr(*username));
2545 mode = convert_tablespace_priv_string(priv_type_text);
2547 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2549 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2553 * has_tablespace_privilege_id
2554 * Check user privileges on a tablespace given
2555 * tablespace oid, and text priv name.
2556 * current_user is assumed
2559 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2561 Oid tablespaceoid = PG_GETARG_OID(0);
2562 text *priv_type_text = PG_GETARG_TEXT_P(1);
2565 AclResult aclresult;
2567 roleid = GetUserId();
2568 mode = convert_tablespace_priv_string(priv_type_text);
2570 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2572 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2576 * has_tablespace_privilege_id_name
2577 * Check user privileges on a tablespace given
2578 * roleid, text tablespacename, and text priv name.
2581 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2583 Oid roleid = PG_GETARG_OID(0);
2584 text *tablespacename = PG_GETARG_TEXT_P(1);
2585 text *priv_type_text = PG_GETARG_TEXT_P(2);
2588 AclResult aclresult;
2590 tablespaceoid = convert_tablespace_name(tablespacename);
2591 mode = convert_tablespace_priv_string(priv_type_text);
2593 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2595 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2599 * has_tablespace_privilege_id_id
2600 * Check user privileges on a tablespace given
2601 * roleid, tablespace oid, and text priv name.
2604 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2606 Oid roleid = PG_GETARG_OID(0);
2607 Oid tablespaceoid = PG_GETARG_OID(1);
2608 text *priv_type_text = PG_GETARG_TEXT_P(2);
2610 AclResult aclresult;
2612 mode = convert_tablespace_priv_string(priv_type_text);
2614 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2616 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2620 * Support routines for has_tablespace_privilege family.
2624 * Given a tablespace name expressed as a string, look it up and return Oid
2627 convert_tablespace_name(text *tablespacename)
2629 char *spcname = text_to_cstring(tablespacename);
2632 oid = get_tablespace_oid(spcname);
2634 if (!OidIsValid(oid))
2636 (errcode(ERRCODE_UNDEFINED_OBJECT),
2637 errmsg("tablespace \"%s\" does not exist", spcname)));
2643 * convert_tablespace_priv_string
2644 * Convert text string to AclMode value.
2647 convert_tablespace_priv_string(text *priv_type_text)
2649 char *priv_type = text_to_cstring(priv_type_text);
2652 * Return mode from priv_type string
2654 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2656 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2657 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2660 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2661 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2662 return ACL_NO_RIGHTS; /* keep compiler quiet */
2666 * pg_has_role variants
2667 * These are all named "pg_has_role" at the SQL level.
2668 * They take various combinations of role name, role OID,
2669 * user name, user OID, or implicit user = current_user.
2671 * The result is a boolean value: true if user has the indicated
2672 * privilege, false if not.
2676 * pg_has_role_name_name
2677 * Check user privileges on a role given
2678 * name username, name rolename, and text priv name.
2681 pg_has_role_name_name(PG_FUNCTION_ARGS)
2683 Name username = PG_GETARG_NAME(0);
2684 Name rolename = PG_GETARG_NAME(1);
2685 text *priv_type_text = PG_GETARG_TEXT_P(2);
2689 AclResult aclresult;
2691 roleid = get_roleid_checked(NameStr(*username));
2692 roleoid = get_roleid_checked(NameStr(*rolename));
2693 mode = convert_role_priv_string(priv_type_text);
2695 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2697 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2702 * Check user privileges on a role given
2703 * name rolename and text priv name.
2704 * current_user is assumed
2707 pg_has_role_name(PG_FUNCTION_ARGS)
2709 Name rolename = PG_GETARG_NAME(0);
2710 text *priv_type_text = PG_GETARG_TEXT_P(1);
2714 AclResult aclresult;
2716 roleid = GetUserId();
2717 roleoid = get_roleid_checked(NameStr(*rolename));
2718 mode = convert_role_priv_string(priv_type_text);
2720 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2722 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2726 * pg_has_role_name_id
2727 * Check user privileges on a role given
2728 * name usename, role oid, and text priv name.
2731 pg_has_role_name_id(PG_FUNCTION_ARGS)
2733 Name username = PG_GETARG_NAME(0);
2734 Oid roleoid = PG_GETARG_OID(1);
2735 text *priv_type_text = PG_GETARG_TEXT_P(2);
2738 AclResult aclresult;
2740 roleid = get_roleid_checked(NameStr(*username));
2741 mode = convert_role_priv_string(priv_type_text);
2743 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2745 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2750 * Check user privileges on a role given
2751 * role oid, and text priv name.
2752 * current_user is assumed
2755 pg_has_role_id(PG_FUNCTION_ARGS)
2757 Oid roleoid = PG_GETARG_OID(0);
2758 text *priv_type_text = PG_GETARG_TEXT_P(1);
2761 AclResult aclresult;
2763 roleid = GetUserId();
2764 mode = convert_role_priv_string(priv_type_text);
2766 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2768 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2772 * pg_has_role_id_name
2773 * Check user privileges on a role given
2774 * roleid, name rolename, and text priv name.
2777 pg_has_role_id_name(PG_FUNCTION_ARGS)
2779 Oid roleid = PG_GETARG_OID(0);
2780 Name rolename = PG_GETARG_NAME(1);
2781 text *priv_type_text = PG_GETARG_TEXT_P(2);
2784 AclResult aclresult;
2786 roleoid = get_roleid_checked(NameStr(*rolename));
2787 mode = convert_role_priv_string(priv_type_text);
2789 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2791 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2796 * Check user privileges on a role given
2797 * roleid, role oid, and text priv name.
2800 pg_has_role_id_id(PG_FUNCTION_ARGS)
2802 Oid roleid = PG_GETARG_OID(0);
2803 Oid roleoid = PG_GETARG_OID(1);
2804 text *priv_type_text = PG_GETARG_TEXT_P(2);
2806 AclResult aclresult;
2808 mode = convert_role_priv_string(priv_type_text);
2810 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2812 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2816 * Support routines for pg_has_role family.
2820 * convert_role_priv_string
2821 * Convert text string to AclMode value.
2823 * We use USAGE to denote whether the privileges of the role are accessible
2824 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
2825 * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
2826 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
2827 * is shared only with pg_role_aclcheck, below.
2830 convert_role_priv_string(text *priv_type_text)
2832 char *priv_type = text_to_cstring(priv_type_text);
2835 * Return mode from priv_type string
2837 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2839 if (pg_strcasecmp(priv_type, "MEMBER") == 0)
2841 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0 ||
2842 pg_strcasecmp(priv_type, "USAGE WITH ADMIN OPTION") == 0 ||
2843 pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0 ||
2844 pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
2845 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2848 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2849 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2850 return ACL_NO_RIGHTS; /* keep compiler quiet */
2855 * Quick-and-dirty support for pg_has_role
2858 pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
2860 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
2862 if (is_admin_of_role(roleid, role_oid))
2865 if (mode & ACL_CREATE)
2867 if (is_member_of_role(roleid, role_oid))
2870 if (mode & ACL_USAGE)
2872 if (has_privs_of_role(roleid, role_oid))
2875 return ACLCHECK_NO_PRIV;
2880 * initialization function (called by InitPostgres)
2883 initialize_acl(void)
2885 if (!IsBootstrapProcessingMode())
2888 * In normal mode, set a callback on any syscache invalidation of
2889 * pg_auth_members rows
2891 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
2892 RoleMembershipCacheCallback,
2898 * RoleMembershipCacheCallback
2899 * Syscache inval callback function
2902 RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
2904 /* Force membership caches to be recomputed on next use */
2905 cached_privs_role = InvalidOid;
2906 cached_member_role = InvalidOid;
2910 /* Check if specified role has rolinherit set */
2912 has_rolinherit(Oid roleid)
2914 bool result = false;
2917 utup = SearchSysCache(AUTHOID,
2918 ObjectIdGetDatum(roleid),
2920 if (HeapTupleIsValid(utup))
2922 result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
2923 ReleaseSysCache(utup);
2930 * Get a list of roles that the specified roleid has the privileges of
2932 * This is defined not to recurse through roles that don't have rolinherit
2933 * set; for such roles, membership implies the ability to do SET ROLE, but
2934 * the privileges are not available until you've done so.
2936 * Since indirect membership testing is relatively expensive, we cache
2937 * a list of memberships. Hence, the result is only guaranteed good until
2938 * the next call of roles_has_privs_of()!
2940 * For the benefit of select_best_grantor, the result is defined to be
2941 * in breadth-first order, ie, closer relationships earlier.
2944 roles_has_privs_of(Oid roleid)
2948 List *new_cached_privs_roles;
2949 MemoryContext oldctx;
2951 /* If cache is already valid, just return the list */
2952 if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
2953 return cached_privs_roles;
2956 * Find all the roles that roleid is a member of, including multi-level
2957 * recursion. The role itself will always be the first element of the
2960 * Each element of the list is scanned to see if it adds any indirect
2961 * memberships. We can use a single list as both the record of
2962 * already-found memberships and the agenda of roles yet to be scanned.
2963 * This is a bit tricky but works because the foreach() macro doesn't
2964 * fetch the next list element until the bottom of the loop.
2966 roles_list = list_make1_oid(roleid);
2968 foreach(l, roles_list)
2970 Oid memberid = lfirst_oid(l);
2974 /* Ignore non-inheriting roles */
2975 if (!has_rolinherit(memberid))
2978 /* Find roles that memberid is directly a member of */
2979 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
2980 ObjectIdGetDatum(memberid),
2982 for (i = 0; i < memlist->n_members; i++)
2984 HeapTuple tup = &memlist->members[i]->tuple;
2985 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
2988 * Even though there shouldn't be any loops in the membership
2989 * graph, we must test for having already seen this role. It is
2990 * legal for instance to have both A->B and A->C->B.
2992 roles_list = list_append_unique_oid(roles_list, otherid);
2994 ReleaseSysCacheList(memlist);
2998 * Copy the completed list into TopMemoryContext so it will persist.
3000 oldctx = MemoryContextSwitchTo(TopMemoryContext);
3001 new_cached_privs_roles = list_copy(roles_list);
3002 MemoryContextSwitchTo(oldctx);
3003 list_free(roles_list);
3006 * Now safe to assign to state variable
3008 cached_privs_role = InvalidOid; /* just paranoia */
3009 list_free(cached_privs_roles);
3010 cached_privs_roles = new_cached_privs_roles;
3011 cached_privs_role = roleid;
3013 /* And now we can return the answer */
3014 return cached_privs_roles;
3019 * Get a list of roles that the specified roleid is a member of
3021 * This is defined to recurse through roles regardless of rolinherit.
3023 * Since indirect membership testing is relatively expensive, we cache
3024 * a list of memberships. Hence, the result is only guaranteed good until
3025 * the next call of roles_is_member_of()!
3028 roles_is_member_of(Oid roleid)
3032 List *new_cached_membership_roles;
3033 MemoryContext oldctx;
3035 /* If cache is already valid, just return the list */
3036 if (OidIsValid(cached_member_role) && cached_member_role == roleid)
3037 return cached_membership_roles;
3040 * Find all the roles that roleid is a member of, including multi-level
3041 * recursion. The role itself will always be the first element of the
3044 * Each element of the list is scanned to see if it adds any indirect
3045 * memberships. We can use a single list as both the record of
3046 * already-found memberships and the agenda of roles yet to be scanned.
3047 * This is a bit tricky but works because the foreach() macro doesn't
3048 * fetch the next list element until the bottom of the loop.
3050 roles_list = list_make1_oid(roleid);
3052 foreach(l, roles_list)
3054 Oid memberid = lfirst_oid(l);
3058 /* Find roles that memberid is directly a member of */
3059 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3060 ObjectIdGetDatum(memberid),
3062 for (i = 0; i < memlist->n_members; i++)
3064 HeapTuple tup = &memlist->members[i]->tuple;
3065 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3068 * Even though there shouldn't be any loops in the membership
3069 * graph, we must test for having already seen this role. It is
3070 * legal for instance to have both A->B and A->C->B.
3072 roles_list = list_append_unique_oid(roles_list, otherid);
3074 ReleaseSysCacheList(memlist);
3078 * Copy the completed list into TopMemoryContext so it will persist.
3080 oldctx = MemoryContextSwitchTo(TopMemoryContext);
3081 new_cached_membership_roles = list_copy(roles_list);
3082 MemoryContextSwitchTo(oldctx);
3083 list_free(roles_list);
3086 * Now safe to assign to state variable
3088 cached_member_role = InvalidOid; /* just paranoia */
3089 list_free(cached_membership_roles);
3090 cached_membership_roles = new_cached_membership_roles;
3091 cached_member_role = roleid;
3093 /* And now we can return the answer */
3094 return cached_membership_roles;
3099 * Does member have the privileges of role (directly or indirectly)?
3101 * This is defined not to recurse through roles that don't have rolinherit
3102 * set; for such roles, membership implies the ability to do SET ROLE, but
3103 * the privileges are not available until you've done so.
3106 has_privs_of_role(Oid member, Oid role)
3108 /* Fast path for simple case */
3112 /* Superusers have every privilege, so are part of every role */
3113 if (superuser_arg(member))
3117 * Find all the roles that member has the privileges of, including
3118 * multi-level recursion, then see if target role is any one of them.
3120 return list_member_oid(roles_has_privs_of(member), role);
3125 * Is member a member of role (directly or indirectly)?
3127 * This is defined to recurse through roles regardless of rolinherit.
3130 is_member_of_role(Oid member, Oid role)
3132 /* Fast path for simple case */
3136 /* Superusers have every privilege, so are part of every role */
3137 if (superuser_arg(member))
3141 * Find all the roles that member is a member of, including multi-level
3142 * recursion, then see if target role is any one of them.
3144 return list_member_oid(roles_is_member_of(member), role);
3148 * check_is_member_of_role
3149 * is_member_of_role with a standard permission-violation error if not
3152 check_is_member_of_role(Oid member, Oid role)
3154 if (!is_member_of_role(member, role))
3156 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3157 errmsg("must be member of role \"%s\"",
3158 GetUserNameFromId(role))));
3162 * Is member a member of role, not considering superuserness?
3164 * This is identical to is_member_of_role except we ignore superuser
3168 is_member_of_role_nosuper(Oid member, Oid role)
3170 /* Fast path for simple case */
3175 * Find all the roles that member is a member of, including multi-level
3176 * recursion, then see if target role is any one of them.
3178 return list_member_oid(roles_is_member_of(member), role);
3183 * Is member an admin of role (directly or indirectly)? That is, is it
3184 * a member WITH ADMIN OPTION?
3186 * We could cache the result as for is_member_of_role, but currently this
3187 * is not used in any performance-critical paths, so we don't.
3190 is_admin_of_role(Oid member, Oid role)
3192 bool result = false;
3196 /* Fast path for simple case */
3200 /* Superusers have every privilege, so are part of every role */
3201 if (superuser_arg(member))
3205 * Find all the roles that member is a member of, including multi-level
3206 * recursion. We build a list in the same way that is_member_of_role does
3207 * to track visited and unvisited roles.
3209 roles_list = list_make1_oid(member);
3211 foreach(l, roles_list)
3213 Oid memberid = lfirst_oid(l);
3217 /* Find roles that memberid is directly a member of */
3218 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3219 ObjectIdGetDatum(memberid),
3221 for (i = 0; i < memlist->n_members; i++)
3223 HeapTuple tup = &memlist->members[i]->tuple;
3224 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3226 if (otherid == role &&
3227 ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
3229 /* Found what we came for, so can stop searching */
3234 roles_list = list_append_unique_oid(roles_list, otherid);
3236 ReleaseSysCacheList(memlist);
3241 list_free(roles_list);
3247 /* does what it says ... */
3249 count_one_bits(AclMode mask)
3253 /* this code relies on AclMode being an unsigned type */
3265 * Select the effective grantor ID for a GRANT or REVOKE operation.
3267 * The grantor must always be either the object owner or some role that has
3268 * been explicitly granted grant options. This ensures that all granted
3269 * privileges appear to flow from the object owner, and there are never
3270 * multiple "original sources" of a privilege. Therefore, if the would-be
3271 * grantor is a member of a role that has the needed grant options, we have
3272 * to do the grant as that role instead.
3274 * It is possible that the would-be grantor is a member of several roles
3275 * that have different subsets of the desired grant options, but no one
3276 * role has 'em all. In this case we pick a role with the largest number
3277 * of desired options. Ties are broken in favor of closer ancestors.
3279 * roleId: the role attempting to do the GRANT/REVOKE
3280 * privileges: the privileges to be granted/revoked
3281 * acl: the ACL of the object in question
3282 * ownerId: the role owning the object in question
3283 * *grantorId: receives the OID of the role to do the grant as
3284 * *grantOptions: receives the grant options actually held by grantorId
3286 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
3289 select_best_grantor(Oid roleId, AclMode privileges,
3290 const Acl *acl, Oid ownerId,
3291 Oid *grantorId, AclMode *grantOptions)
3293 AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
3299 * The object owner is always treated as having all grant options, so if
3300 * roleId is the owner it's easy. Also, if roleId is a superuser it's
3301 * easy: superusers are implicitly members of every role, so they act as
3304 if (roleId == ownerId || superuser_arg(roleId))
3306 *grantorId = ownerId;
3307 *grantOptions = needed_goptions;
3312 * Otherwise we have to do a careful search to see if roleId has the
3313 * privileges of any suitable role. Note: we can hang onto the result of
3314 * roles_has_privs_of() throughout this loop, because aclmask_direct()
3315 * doesn't query any role memberships.
3317 roles_list = roles_has_privs_of(roleId);
3319 /* initialize candidate result as default */
3320 *grantorId = roleId;
3321 *grantOptions = ACL_NO_RIGHTS;
3324 foreach(l, roles_list)
3326 Oid otherrole = lfirst_oid(l);
3329 otherprivs = aclmask_direct(acl, otherrole, ownerId,
3330 needed_goptions, ACLMASK_ALL);
3331 if (otherprivs == needed_goptions)
3333 /* Found a suitable grantor */
3334 *grantorId = otherrole;
3335 *grantOptions = otherprivs;
3340 * If it has just some of the needed privileges, remember best
3343 if (otherprivs != ACL_NO_RIGHTS)
3345 int nnewrights = count_one_bits(otherprivs);
3347 if (nnewrights > nrights)
3349 *grantorId = otherrole;
3350 *grantOptions = otherprivs;
3351 nrights = nnewrights;