1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2005, 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.128 2005/11/17 22:14:52 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/catcache.h"
29 #include "utils/inval.h"
30 #include "utils/lsyscache.h"
31 #include "utils/memutils.h"
32 #include "utils/syscache.h"
36 * We frequently need to test whether a given role is a member of some other
37 * role. In most of these tests the "given role" is the same, namely the
38 * active current user. So we can optimize it by keeping a cached list of
39 * all the roles the "given role" is a member of, directly or indirectly.
40 * The cache is flushed whenever we detect a change in pg_auth_members.
42 * There are actually two caches, one computed under "has_privs" rules
43 * (do not recurse where rolinherit isn't true) and one computed under
44 * "is_member" rules (recurse regardless of rolinherit).
46 * Possibly this mechanism should be generalized to allow caching membership
47 * info for multiple roles?
49 * The has_privs cache is:
50 * cached_privs_role is the role OID the cache is for.
51 * cached_privs_roles is an OID list of roles that cached_privs_role
52 * has the privileges of (always including itself).
53 * The cache is valid if cached_privs_role is not InvalidOid.
55 * The is_member cache is similarly:
56 * cached_member_role is the role OID the cache is for.
57 * cached_membership_roles is an OID list of roles that cached_member_role
58 * is a member of (always including itself).
59 * The cache is valid if cached_member_role is not InvalidOid.
61 static Oid cached_privs_role = InvalidOid;
62 static List *cached_privs_roles = NIL;
63 static Oid cached_member_role = InvalidOid;
64 static List *cached_membership_roles = NIL;
67 static const char *getid(const char *s, char *n);
68 static void putid(char *p, const char *s);
69 static Acl *allocacl(int n);
70 static 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++)
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;
291 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
292 errmsg("invalid mode character: must be one of \"%s\"",
293 ACL_ALL_RIGHTS_STR)));
300 aip->ai_grantee = ACL_ID_PUBLIC;
302 aip->ai_grantee = get_roleid_checked(name);
305 * XXX Allow a degree of backward compatibility by defaulting the grantor
310 s = getid(s + 1, name2);
311 if (name2[0] == '\0')
313 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
314 errmsg("a name must follow the \"/\" sign")));
315 aip->ai_grantor = get_roleid_checked(name2);
319 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
321 (errcode(ERRCODE_INVALID_GRANTOR),
322 errmsg("defaulting grantor to user ID %u",
323 BOOTSTRAP_SUPERUSERID)));
326 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
329 elog(LOG, "aclparse: correctly read [%u %x %x]",
330 aip->ai_grantee, privs, goption);
338 * Allocates storage for a new Acl with 'n' entries.
350 elog(ERROR, "invalid size: %d", n);
351 size = ACL_N_SIZE(n);
352 new_acl = (Acl *) palloc0(size);
353 new_acl->size = size;
355 new_acl->dataoffset = 0; /* we never put in any nulls */
356 new_acl->elemtype = ACLITEMOID;
357 ARR_LBOUND(new_acl)[0] = 1;
358 ARR_DIMS(new_acl)[0] = n;
364 * Allocates storage for, and fills in, a new AclItem given a string
365 * 's' that contains an ACL specification. See aclparse for details.
371 aclitemin(PG_FUNCTION_ARGS)
373 const char *s = PG_GETARG_CSTRING(0);
376 aip = (AclItem *) palloc(sizeof(AclItem));
377 s = aclparse(s, aip);
378 while (isspace((unsigned char) *s))
382 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
383 errmsg("extra garbage at the end of the ACL specification")));
385 PG_RETURN_ACLITEM_P(aip);
390 * Allocates storage for, and fills in, a new null-delimited string
391 * containing a formatted ACL specification. See aclparse for details.
397 aclitemout(PG_FUNCTION_ARGS)
399 AclItem *aip = PG_GETARG_ACLITEM_P(0);
405 out = palloc(strlen("=/") +
407 2 * (2 * NAMEDATALEN + 2) +
413 if (aip->ai_grantee != ACL_ID_PUBLIC)
415 htup = SearchSysCache(AUTHOID,
416 ObjectIdGetDatum(aip->ai_grantee),
418 if (HeapTupleIsValid(htup))
420 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
421 ReleaseSysCache(htup);
425 /* Generate numeric OID if we don't find an entry */
426 sprintf(p, "%u", aip->ai_grantee);
434 for (i = 0; i < N_ACL_RIGHTS; ++i)
436 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
437 *p++ = ACL_ALL_RIGHTS_STR[i];
438 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
445 htup = SearchSysCache(AUTHOID,
446 ObjectIdGetDatum(aip->ai_grantor),
448 if (HeapTupleIsValid(htup))
450 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
451 ReleaseSysCache(htup);
455 /* Generate numeric OID if we don't find an entry */
456 sprintf(p, "%u", aip->ai_grantor);
459 PG_RETURN_CSTRING(out);
464 * Two AclItems are considered to match iff they have the same
465 * grantee and grantor; the privileges are ignored.
468 aclitem_match(const AclItem *a1, const AclItem *a2)
470 return a1->ai_grantee == a2->ai_grantee &&
471 a1->ai_grantor == a2->ai_grantor;
475 * aclitem equality operator
478 aclitem_eq(PG_FUNCTION_ARGS)
480 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
481 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
484 result = a1->ai_privs == a2->ai_privs &&
485 a1->ai_grantee == a2->ai_grantee &&
486 a1->ai_grantor == a2->ai_grantor;
487 PG_RETURN_BOOL(result);
491 * aclitem hash function
493 * We make aclitems hashable not so much because anyone is likely to hash
494 * them, as because we want array equality to work on aclitem arrays, and
495 * with the typcache mechanism we must have a hash or btree opclass.
498 hash_aclitem(PG_FUNCTION_ARGS)
500 AclItem *a = PG_GETARG_ACLITEM_P(0);
502 /* not very bright, but avoids any issue of padding in struct */
503 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
508 * acldefault() --- create an ACL describing default access permissions
510 * Change this routine if you want to alter the default access policy for
511 * newly-created objects (or any object with a NULL acl entry).
514 acldefault(GrantObjectType objtype, Oid ownerId)
516 AclMode world_default;
517 AclMode owner_default;
523 case ACL_OBJECT_RELATION:
524 world_default = ACL_NO_RIGHTS;
525 owner_default = ACL_ALL_RIGHTS_RELATION;
527 case ACL_OBJECT_DATABASE:
528 world_default = ACL_CREATE_TEMP; /* not NO_RIGHTS! */
529 owner_default = ACL_ALL_RIGHTS_DATABASE;
531 case ACL_OBJECT_FUNCTION:
532 /* Grant EXECUTE by default, for now */
533 world_default = ACL_EXECUTE;
534 owner_default = ACL_ALL_RIGHTS_FUNCTION;
536 case ACL_OBJECT_LANGUAGE:
537 /* Grant USAGE by default, for now */
538 world_default = ACL_USAGE;
539 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
541 case ACL_OBJECT_NAMESPACE:
542 world_default = ACL_NO_RIGHTS;
543 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
545 case ACL_OBJECT_TABLESPACE:
546 world_default = ACL_NO_RIGHTS;
547 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
550 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
551 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
552 owner_default = ACL_NO_RIGHTS;
556 acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);
559 if (world_default != ACL_NO_RIGHTS)
561 aip->ai_grantee = ACL_ID_PUBLIC;
562 aip->ai_grantor = ownerId;
563 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
568 * Note that the owner's entry shows all ordinary privileges but no grant
569 * options. This is because his grant options come "from the system" and
570 * not from his own efforts. (The SQL spec says that the owner's rights
571 * come from a "_SYSTEM" authid.) However, we do consider that the
572 * owner's ordinary privileges are self-granted; this lets him revoke
573 * them. We implement the owner's grant options without any explicit
574 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
575 * whereever we are testing grant options.
577 aip->ai_grantee = ownerId;
578 aip->ai_grantor = ownerId;
579 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
586 * Update an ACL array to add or remove specified privileges.
588 * old_acl: the input ACL array
589 * mod_aip: defines the privileges to be added, removed, or substituted
590 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
591 * ownerId: Oid of object owner
592 * behavior: RESTRICT or CASCADE behavior for recursive removal
594 * ownerid and behavior are only relevant when the update operation specifies
595 * deletion of grant options.
597 * The result is a modified copy; the input object is not changed.
599 * NB: caller is responsible for having detoasted the input ACL, if needed.
602 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
603 int modechg, Oid ownerId, DropBehavior behavior)
615 /* These checks for null input are probably dead code, but... */
616 if (!old_acl || ACL_NUM(old_acl) < 0)
617 old_acl = allocacl(0);
620 new_acl = allocacl(ACL_NUM(old_acl));
621 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
625 /* If granting grant options, check for circularity */
626 if (modechg != ACL_MODECHG_DEL &&
627 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
628 check_circularity(old_acl, mod_aip, ownerId);
630 num = ACL_NUM(old_acl);
631 old_aip = ACL_DAT(old_acl);
634 * Search the ACL for an existing entry for this grantee and grantor. If
635 * one exists, just modify the entry in-place (well, in the same position,
636 * since we actually return a copy); otherwise, insert the new entry at
640 for (dst = 0; dst < num; ++dst)
642 if (aclitem_match(mod_aip, old_aip + dst))
644 /* found a match, so modify existing item */
645 new_acl = allocacl(num);
646 new_aip = ACL_DAT(new_acl);
647 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
654 /* need to append a new item */
655 new_acl = allocacl(num + 1);
656 new_aip = ACL_DAT(new_acl);
657 memcpy(new_aip, old_aip, num * sizeof(AclItem));
659 /* initialize the new entry with no permissions */
660 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
661 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
662 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
663 ACL_NO_RIGHTS, ACL_NO_RIGHTS);
664 num++; /* set num to the size of new_acl */
667 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
668 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
670 /* apply the specified permissions change */
673 case ACL_MODECHG_ADD:
674 ACLITEM_SET_RIGHTS(new_aip[dst],
675 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
677 case ACL_MODECHG_DEL:
678 ACLITEM_SET_RIGHTS(new_aip[dst],
679 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
681 case ACL_MODECHG_EQL:
682 ACLITEM_SET_RIGHTS(new_aip[dst],
683 ACLITEM_GET_RIGHTS(*mod_aip));
687 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
688 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
691 * If the adjusted entry has no permissions, delete it from the list.
693 if (new_rights == ACL_NO_RIGHTS)
695 memmove(new_aip + dst,
697 (num - dst - 1) * sizeof(AclItem));
698 ARR_DIMS(new_acl)[0] = num - 1;
699 ARR_SIZE(new_acl) -= sizeof(AclItem);
703 * Remove abandoned privileges (cascading revoke). Currently we can only
704 * handle this when the grantee is not PUBLIC.
706 if ((old_goptions & ~new_goptions) != 0)
708 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
709 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
710 (old_goptions & ~new_goptions),
718 * Update an ACL array to reflect a change of owner to the parent object
720 * old_acl: the input ACL array (must not be NULL)
721 * oldOwnerId: Oid of the old object owner
722 * newOwnerId: Oid of the new object owner
724 * The result is a modified copy; the input object is not changed.
726 * NB: caller is responsible for having detoasted the input ACL, if needed.
729 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
737 bool newpresent = false;
744 * Make a copy of the given ACL, substituting new owner ID for old
745 * wherever it appears as either grantor or grantee. Also note if the new
746 * owner ID is already present.
748 num = ACL_NUM(old_acl);
749 old_aip = ACL_DAT(old_acl);
750 new_acl = allocacl(num);
751 new_aip = ACL_DAT(new_acl);
752 memcpy(new_aip, old_aip, num * sizeof(AclItem));
753 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
755 if (dst_aip->ai_grantor == oldOwnerId)
756 dst_aip->ai_grantor = newOwnerId;
757 else if (dst_aip->ai_grantor == newOwnerId)
759 if (dst_aip->ai_grantee == oldOwnerId)
760 dst_aip->ai_grantee = newOwnerId;
761 else if (dst_aip->ai_grantee == newOwnerId)
766 * If the old ACL contained any references to the new owner, then we may
767 * now have generated an ACL containing duplicate entries. Find them and
768 * merge them so that there are not duplicates. (This is relatively
769 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
770 * be the normal case.)
772 * To simplify deletion of duplicate entries, we temporarily leave them in
773 * the array but set their privilege masks to zero; when we reach such an
774 * entry it's just skipped. (Thus, a side effect of this code will be to
775 * remove privilege-free entries, should there be any in the input.) dst
776 * is the next output slot, targ is the currently considered input slot
777 * (always >= dst), and src scans entries to the right of targ looking for
778 * duplicates. Once an entry has been emitted to dst it is known
779 * duplicate-free and need not be considered anymore.
784 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
786 /* ignore if deleted in an earlier pass */
787 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
789 /* find and merge any duplicates */
790 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
793 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
795 if (aclitem_match(targ_aip, src_aip))
797 ACLITEM_SET_RIGHTS(*targ_aip,
798 ACLITEM_GET_RIGHTS(*targ_aip) |
799 ACLITEM_GET_RIGHTS(*src_aip));
800 /* mark the duplicate deleted */
801 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
804 /* and emit to output */
805 new_aip[dst] = *targ_aip;
808 /* Adjust array size to be 'dst' items */
809 ARR_DIMS(new_acl)[0] = dst;
810 ARR_SIZE(new_acl) = ACL_N_SIZE(dst);
818 * When granting grant options, we must disallow attempts to set up circular
819 * chains of grant options. Suppose A (the object owner) grants B some
820 * privileges with grant option, and B re-grants them to C. If C could
821 * grant the privileges to B as well, then A would be unable to effectively
822 * revoke the privileges from B, since recursive_revoke would consider that
823 * B still has 'em from C.
825 * We check for this by recursively deleting all grant options belonging to
826 * the target grantee, and then seeing if the would-be grantor still has the
827 * grant option or not.
830 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
840 * For now, grant options can only be granted to roles, not PUBLIC.
841 * Otherwise we'd have to work a bit harder here.
843 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
845 /* The owner always has grant options, no need to check */
846 if (mod_aip->ai_grantor == ownerId)
849 /* Make a working copy */
850 acl = allocacl(ACL_NUM(old_acl));
851 memcpy(acl, old_acl, ACL_SIZE(old_acl));
853 /* Zap all grant options of target grantee, plus what depends on 'em */
857 for (i = 0; i < num; i++)
859 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
860 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
864 /* We'll actually zap ordinary privs too, but no matter */
865 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
866 ownerId, DROP_CASCADE);
875 /* Now we can compute grantor's independently-derived privileges */
876 own_privs = aclmask(acl,
879 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
881 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
883 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
885 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
886 errmsg("grant options cannot be granted back to your own grantor")));
893 * Ensure that no privilege is "abandoned". A privilege is abandoned
894 * if the user that granted the privilege loses the grant option. (So
895 * the chain through which it was granted is broken.) Either the
896 * abandoned privileges are revoked as well, or an error message is
897 * printed, depending on the drop behavior option.
899 * acl: the input ACL list
900 * grantee: the user from whom some grant options have been revoked
901 * revoke_privs: the grant options being revoked
902 * ownerId: Oid of object owner
903 * behavior: RESTRICT or CASCADE behavior for recursive removal
905 * The input Acl object is pfree'd if replaced.
908 recursive_revoke(Acl *acl,
910 AclMode revoke_privs,
912 DropBehavior behavior)
919 /* The owner can never truly lose grant options, so short-circuit */
920 if (grantee == ownerId)
923 /* The grantee might still have the privileges via another grantor */
924 still_has = aclmask(acl, grantee, ownerId,
925 ACL_GRANT_OPTION_FOR(revoke_privs),
927 revoke_privs &= ~still_has;
928 if (revoke_privs == ACL_NO_RIGHTS)
934 for (i = 0; i < num; i++)
936 if (aip[i].ai_grantor == grantee
937 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
942 if (behavior == DROP_RESTRICT)
944 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
945 errmsg("dependent privileges exist"),
946 errhint("Use CASCADE to revoke them too.")));
948 mod_acl.ai_grantor = grantee;
949 mod_acl.ai_grantee = aip[i].ai_grantee;
950 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
954 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
969 * aclmask --- compute bitmask of all privileges held by roleid.
971 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
972 * held by the given roleid according to the given ACL list, ANDed
973 * with 'mask'. (The point of passing 'mask' is to let the routine
974 * exit early if all privileges of interest have been found.)
976 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
977 * is known true. (This lets us exit soonest in cases where the
978 * caller is only going to test for zero or nonzero result.)
982 * To see if any of a set of privileges are held:
983 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
985 * To see if all of a set of privileges are held:
986 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
988 * To determine exactly which of a set of privileges are held:
989 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
992 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
993 AclMode mask, AclMaskHow how)
1002 * Null ACL should not happen, since caller should have inserted
1003 * appropriate default
1006 elog(ERROR, "null ACL");
1008 /* Quick exit for mask == 0 */
1014 /* Owner always implicitly has all grant options */
1015 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1016 has_privs_of_role(roleid, ownerId))
1018 result = mask & ACLITEM_ALL_GOPTION_BITS;
1019 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1024 aidat = ACL_DAT(acl);
1027 * Check privileges granted directly to roleid or to public
1029 for (i = 0; i < num; i++)
1031 AclItem *aidata = &aidat[i];
1033 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1034 aidata->ai_grantee == roleid)
1036 result |= aidata->ai_privs & mask;
1037 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1043 * Check privileges granted indirectly via role memberships. We do this in
1044 * a separate pass to minimize expensive indirect membership tests. In
1045 * particular, it's worth testing whether a given ACL entry grants any
1046 * privileges still of interest before we perform the has_privs_of_role
1049 remaining = mask & ~result;
1050 for (i = 0; i < num; i++)
1052 AclItem *aidata = &aidat[i];
1054 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1055 aidata->ai_grantee == roleid)
1056 continue; /* already checked it */
1058 if ((aidata->ai_privs & remaining) &&
1059 has_privs_of_role(roleid, aidata->ai_grantee))
1061 result |= aidata->ai_privs & mask;
1062 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1064 remaining = mask & ~result;
1073 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1075 * This is exactly like aclmask() except that we consider only privileges
1076 * held *directly* by roleid, not those inherited via role membership.
1079 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1080 AclMode mask, AclMaskHow how)
1088 * Null ACL should not happen, since caller should have inserted
1089 * appropriate default
1092 elog(ERROR, "null ACL");
1094 /* Quick exit for mask == 0 */
1100 /* Owner always implicitly has all grant options */
1101 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1104 result = mask & ACLITEM_ALL_GOPTION_BITS;
1105 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1110 aidat = ACL_DAT(acl);
1113 * Check privileges granted directly to roleid (and not to public)
1115 for (i = 0; i < num; i++)
1117 AclItem *aidata = &aidat[i];
1119 if (aidata->ai_grantee == roleid)
1121 result |= aidata->ai_privs & mask;
1122 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1133 * Find out all the roleids mentioned in an Acl.
1134 * Note that we do not distinguish grantors from grantees.
1136 * *roleids is set to point to a palloc'd array containing distinct OIDs
1137 * in sorted order. The length of the array is the function result.
1140 aclmembers(const Acl *acl, Oid **roleids)
1143 const AclItem *acldat;
1148 if (acl == NULL || ACL_NUM(acl) == 0)
1154 /* Allocate the worst-case space requirement */
1155 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1156 acldat = ACL_DAT(acl);
1159 * Walk the ACL collecting mentioned RoleIds.
1162 for (i = 0; i < ACL_NUM(acl); i++)
1164 const AclItem *ai = &acldat[i];
1166 if (ai->ai_grantee != ACL_ID_PUBLIC)
1167 list[j++] = ai->ai_grantee;
1168 /* grantor is currently never PUBLIC, but let's check anyway */
1169 if (ai->ai_grantor != ACL_ID_PUBLIC)
1170 list[j++] = ai->ai_grantor;
1173 /* Sort the array */
1174 qsort(list, j, sizeof(Oid), oidComparator);
1176 /* Remove duplicates from the array */
1178 for (i = 1; i < j; i++)
1180 if (list[k] != list[i])
1181 list[++k] = list[i];
1185 * We could repalloc the array down to minimum size, but it's hardly worth
1186 * it since it's only transient memory.
1195 * qsort comparison function for Oids
1198 oidComparator(const void *arg1, const void *arg2)
1200 Oid oid1 = *(const Oid *) arg1;
1201 Oid oid2 = *(const Oid *) arg2;
1212 * aclinsert (exported function)
1215 aclinsert(PG_FUNCTION_ARGS)
1218 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1219 errmsg("aclinsert is no longer supported")));
1221 PG_RETURN_NULL(); /* keep compiler quiet */
1225 aclremove(PG_FUNCTION_ARGS)
1228 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1229 errmsg("aclremove is no longer supported")));
1231 PG_RETURN_NULL(); /* keep compiler quiet */
1235 aclcontains(PG_FUNCTION_ARGS)
1237 Acl *acl = PG_GETARG_ACL_P(0);
1238 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1244 aidat = ACL_DAT(acl);
1245 for (i = 0; i < num; ++i)
1247 if (aip->ai_grantee == aidat[i].ai_grantee &&
1248 aip->ai_grantor == aidat[i].ai_grantor &&
1249 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1250 PG_RETURN_BOOL(true);
1252 PG_RETURN_BOOL(false);
1256 makeaclitem(PG_FUNCTION_ARGS)
1258 Oid grantee = PG_GETARG_OID(0);
1259 Oid grantor = PG_GETARG_OID(1);
1260 text *privtext = PG_GETARG_TEXT_P(2);
1261 bool goption = PG_GETARG_BOOL(3);
1265 priv = convert_priv_string(privtext);
1267 result = (AclItem *) palloc(sizeof(AclItem));
1269 result->ai_grantee = grantee;
1270 result->ai_grantor = grantor;
1272 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1273 (goption ? priv : ACL_NO_RIGHTS));
1275 PG_RETURN_ACLITEM_P(result);
1279 convert_priv_string(text *priv_type_text)
1283 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1284 PointerGetDatum(priv_type_text)));
1286 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1288 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1290 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1292 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1294 if (pg_strcasecmp(priv_type, "RULE") == 0)
1296 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1297 return ACL_REFERENCES;
1298 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1300 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1302 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1304 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1306 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1307 return ACL_CREATE_TEMP;
1308 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1309 return ACL_CREATE_TEMP;
1312 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1313 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1314 return ACL_NO_RIGHTS; /* keep compiler quiet */
1319 * has_table_privilege variants
1320 * These are all named "has_table_privilege" at the SQL level.
1321 * They take various combinations of relation name, relation OID,
1322 * user name, user OID, or implicit user = current_user.
1324 * The result is a boolean value: true if user has the indicated
1325 * privilege, false if not.
1329 * has_table_privilege_name_name
1330 * Check user privileges on a table given
1331 * name username, text tablename, and text priv name.
1334 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1336 Name rolename = PG_GETARG_NAME(0);
1337 text *tablename = PG_GETARG_TEXT_P(1);
1338 text *priv_type_text = PG_GETARG_TEXT_P(2);
1342 AclResult aclresult;
1344 roleid = get_roleid_checked(NameStr(*rolename));
1345 tableoid = convert_table_name(tablename);
1346 mode = convert_table_priv_string(priv_type_text);
1348 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1350 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1354 * has_table_privilege_name
1355 * Check user privileges on a table given
1356 * text tablename and text priv name.
1357 * current_user is assumed
1360 has_table_privilege_name(PG_FUNCTION_ARGS)
1362 text *tablename = PG_GETARG_TEXT_P(0);
1363 text *priv_type_text = PG_GETARG_TEXT_P(1);
1367 AclResult aclresult;
1369 roleid = GetUserId();
1370 tableoid = convert_table_name(tablename);
1371 mode = convert_table_priv_string(priv_type_text);
1373 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1375 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1379 * has_table_privilege_name_id
1380 * Check user privileges on a table given
1381 * name usename, table oid, and text priv name.
1384 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1386 Name username = PG_GETARG_NAME(0);
1387 Oid tableoid = PG_GETARG_OID(1);
1388 text *priv_type_text = PG_GETARG_TEXT_P(2);
1391 AclResult aclresult;
1393 roleid = get_roleid_checked(NameStr(*username));
1394 mode = convert_table_priv_string(priv_type_text);
1396 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1398 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1402 * has_table_privilege_id
1403 * Check user privileges on a table given
1404 * table oid, and text priv name.
1405 * current_user is assumed
1408 has_table_privilege_id(PG_FUNCTION_ARGS)
1410 Oid tableoid = PG_GETARG_OID(0);
1411 text *priv_type_text = PG_GETARG_TEXT_P(1);
1414 AclResult aclresult;
1416 roleid = GetUserId();
1417 mode = convert_table_priv_string(priv_type_text);
1419 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1421 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1425 * has_table_privilege_id_name
1426 * Check user privileges on a table given
1427 * roleid, text tablename, and text priv name.
1430 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1432 Oid roleid = PG_GETARG_OID(0);
1433 text *tablename = PG_GETARG_TEXT_P(1);
1434 text *priv_type_text = PG_GETARG_TEXT_P(2);
1437 AclResult aclresult;
1439 tableoid = convert_table_name(tablename);
1440 mode = convert_table_priv_string(priv_type_text);
1442 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1444 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1448 * has_table_privilege_id_id
1449 * Check user privileges on a table given
1450 * roleid, table oid, and text priv name.
1453 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1455 Oid roleid = PG_GETARG_OID(0);
1456 Oid tableoid = PG_GETARG_OID(1);
1457 text *priv_type_text = PG_GETARG_TEXT_P(2);
1459 AclResult aclresult;
1461 mode = convert_table_priv_string(priv_type_text);
1463 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1465 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1469 * Support routines for has_table_privilege family.
1473 * Given a table name expressed as a string, look it up and return Oid
1476 convert_table_name(text *tablename)
1480 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1482 return RangeVarGetRelid(relrv, false);
1486 * convert_table_priv_string
1487 * Convert text string to AclMode value.
1490 convert_table_priv_string(text *priv_type_text)
1494 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1495 PointerGetDatum(priv_type_text)));
1498 * Return mode from priv_type string
1500 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1502 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1503 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1505 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1507 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1508 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1510 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1512 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1513 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1515 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1517 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1518 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1520 if (pg_strcasecmp(priv_type, "RULE") == 0)
1522 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1523 return ACL_GRANT_OPTION_FOR(ACL_RULE);
1525 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1526 return ACL_REFERENCES;
1527 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1528 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1530 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1532 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1533 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1536 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1537 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1538 return ACL_NO_RIGHTS; /* keep compiler quiet */
1543 * has_database_privilege variants
1544 * These are all named "has_database_privilege" at the SQL level.
1545 * They take various combinations of database name, database OID,
1546 * user name, user OID, or implicit user = current_user.
1548 * The result is a boolean value: true if user has the indicated
1549 * privilege, false if not.
1553 * has_database_privilege_name_name
1554 * Check user privileges on a database given
1555 * name username, text databasename, and text priv name.
1558 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1560 Name username = PG_GETARG_NAME(0);
1561 text *databasename = PG_GETARG_TEXT_P(1);
1562 text *priv_type_text = PG_GETARG_TEXT_P(2);
1566 AclResult aclresult;
1568 roleid = get_roleid_checked(NameStr(*username));
1569 databaseoid = convert_database_name(databasename);
1570 mode = convert_database_priv_string(priv_type_text);
1572 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1574 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1578 * has_database_privilege_name
1579 * Check user privileges on a database given
1580 * text databasename and text priv name.
1581 * current_user is assumed
1584 has_database_privilege_name(PG_FUNCTION_ARGS)
1586 text *databasename = PG_GETARG_TEXT_P(0);
1587 text *priv_type_text = PG_GETARG_TEXT_P(1);
1591 AclResult aclresult;
1593 roleid = GetUserId();
1594 databaseoid = convert_database_name(databasename);
1595 mode = convert_database_priv_string(priv_type_text);
1597 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1599 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1603 * has_database_privilege_name_id
1604 * Check user privileges on a database given
1605 * name usename, database oid, and text priv name.
1608 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1610 Name username = PG_GETARG_NAME(0);
1611 Oid databaseoid = PG_GETARG_OID(1);
1612 text *priv_type_text = PG_GETARG_TEXT_P(2);
1615 AclResult aclresult;
1617 roleid = get_roleid_checked(NameStr(*username));
1618 mode = convert_database_priv_string(priv_type_text);
1620 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1622 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1626 * has_database_privilege_id
1627 * Check user privileges on a database given
1628 * database oid, and text priv name.
1629 * current_user is assumed
1632 has_database_privilege_id(PG_FUNCTION_ARGS)
1634 Oid databaseoid = PG_GETARG_OID(0);
1635 text *priv_type_text = PG_GETARG_TEXT_P(1);
1638 AclResult aclresult;
1640 roleid = GetUserId();
1641 mode = convert_database_priv_string(priv_type_text);
1643 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1645 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1649 * has_database_privilege_id_name
1650 * Check user privileges on a database given
1651 * roleid, text databasename, and text priv name.
1654 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1656 Oid roleid = PG_GETARG_OID(0);
1657 text *databasename = PG_GETARG_TEXT_P(1);
1658 text *priv_type_text = PG_GETARG_TEXT_P(2);
1661 AclResult aclresult;
1663 databaseoid = convert_database_name(databasename);
1664 mode = convert_database_priv_string(priv_type_text);
1666 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1668 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1672 * has_database_privilege_id_id
1673 * Check user privileges on a database given
1674 * roleid, database oid, and text priv name.
1677 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1679 Oid roleid = PG_GETARG_OID(0);
1680 Oid databaseoid = PG_GETARG_OID(1);
1681 text *priv_type_text = PG_GETARG_TEXT_P(2);
1683 AclResult aclresult;
1685 mode = convert_database_priv_string(priv_type_text);
1687 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1689 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1693 * Support routines for has_database_privilege family.
1697 * Given a database name expressed as a string, look it up and return Oid
1700 convert_database_name(text *databasename)
1705 dbname = DatumGetCString(DirectFunctionCall1(textout,
1706 PointerGetDatum(databasename)));
1708 oid = get_database_oid(dbname);
1709 if (!OidIsValid(oid))
1711 (errcode(ERRCODE_UNDEFINED_DATABASE),
1712 errmsg("database \"%s\" does not exist", dbname)));
1718 * convert_database_priv_string
1719 * Convert text string to AclMode value.
1722 convert_database_priv_string(text *priv_type_text)
1726 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1727 PointerGetDatum(priv_type_text)));
1730 * Return mode from priv_type string
1732 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1734 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1735 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1737 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1738 return ACL_CREATE_TEMP;
1739 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1740 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1742 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1743 return ACL_CREATE_TEMP;
1744 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1745 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1748 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1749 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1750 return ACL_NO_RIGHTS; /* keep compiler quiet */
1755 * has_function_privilege variants
1756 * These are all named "has_function_privilege" at the SQL level.
1757 * They take various combinations of function name, function OID,
1758 * user name, user OID, or implicit user = current_user.
1760 * The result is a boolean value: true if user has the indicated
1761 * privilege, false if not.
1765 * has_function_privilege_name_name
1766 * Check user privileges on a function given
1767 * name username, text functionname, and text priv name.
1770 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1772 Name username = PG_GETARG_NAME(0);
1773 text *functionname = PG_GETARG_TEXT_P(1);
1774 text *priv_type_text = PG_GETARG_TEXT_P(2);
1778 AclResult aclresult;
1780 roleid = get_roleid_checked(NameStr(*username));
1781 functionoid = convert_function_name(functionname);
1782 mode = convert_function_priv_string(priv_type_text);
1784 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1786 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1790 * has_function_privilege_name
1791 * Check user privileges on a function given
1792 * text functionname and text priv name.
1793 * current_user is assumed
1796 has_function_privilege_name(PG_FUNCTION_ARGS)
1798 text *functionname = PG_GETARG_TEXT_P(0);
1799 text *priv_type_text = PG_GETARG_TEXT_P(1);
1803 AclResult aclresult;
1805 roleid = GetUserId();
1806 functionoid = convert_function_name(functionname);
1807 mode = convert_function_priv_string(priv_type_text);
1809 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1811 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1815 * has_function_privilege_name_id
1816 * Check user privileges on a function given
1817 * name usename, function oid, and text priv name.
1820 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1822 Name username = PG_GETARG_NAME(0);
1823 Oid functionoid = PG_GETARG_OID(1);
1824 text *priv_type_text = PG_GETARG_TEXT_P(2);
1827 AclResult aclresult;
1829 roleid = get_roleid_checked(NameStr(*username));
1830 mode = convert_function_priv_string(priv_type_text);
1832 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1834 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1838 * has_function_privilege_id
1839 * Check user privileges on a function given
1840 * function oid, and text priv name.
1841 * current_user is assumed
1844 has_function_privilege_id(PG_FUNCTION_ARGS)
1846 Oid functionoid = PG_GETARG_OID(0);
1847 text *priv_type_text = PG_GETARG_TEXT_P(1);
1850 AclResult aclresult;
1852 roleid = GetUserId();
1853 mode = convert_function_priv_string(priv_type_text);
1855 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1857 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1861 * has_function_privilege_id_name
1862 * Check user privileges on a function given
1863 * roleid, text functionname, and text priv name.
1866 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1868 Oid roleid = PG_GETARG_OID(0);
1869 text *functionname = PG_GETARG_TEXT_P(1);
1870 text *priv_type_text = PG_GETARG_TEXT_P(2);
1873 AclResult aclresult;
1875 functionoid = convert_function_name(functionname);
1876 mode = convert_function_priv_string(priv_type_text);
1878 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1880 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1884 * has_function_privilege_id_id
1885 * Check user privileges on a function given
1886 * roleid, function oid, and text priv name.
1889 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1891 Oid roleid = PG_GETARG_OID(0);
1892 Oid functionoid = PG_GETARG_OID(1);
1893 text *priv_type_text = PG_GETARG_TEXT_P(2);
1895 AclResult aclresult;
1897 mode = convert_function_priv_string(priv_type_text);
1899 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1901 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1905 * Support routines for has_function_privilege family.
1909 * Given a function name expressed as a string, look it up and return Oid
1912 convert_function_name(text *functionname)
1917 funcname = DatumGetCString(DirectFunctionCall1(textout,
1918 PointerGetDatum(functionname)));
1920 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1921 CStringGetDatum(funcname)));
1923 if (!OidIsValid(oid))
1925 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1926 errmsg("function \"%s\" does not exist", funcname)));
1932 * convert_function_priv_string
1933 * Convert text string to AclMode value.
1936 convert_function_priv_string(text *priv_type_text)
1940 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1941 PointerGetDatum(priv_type_text)));
1944 * Return mode from priv_type string
1946 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1948 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1949 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1952 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1953 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1954 return ACL_NO_RIGHTS; /* keep compiler quiet */
1959 * has_language_privilege variants
1960 * These are all named "has_language_privilege" at the SQL level.
1961 * They take various combinations of language name, language OID,
1962 * user name, user OID, or implicit user = current_user.
1964 * The result is a boolean value: true if user has the indicated
1965 * privilege, false if not.
1969 * has_language_privilege_name_name
1970 * Check user privileges on a language given
1971 * name username, text languagename, and text priv name.
1974 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1976 Name username = PG_GETARG_NAME(0);
1977 text *languagename = PG_GETARG_TEXT_P(1);
1978 text *priv_type_text = PG_GETARG_TEXT_P(2);
1982 AclResult aclresult;
1984 roleid = get_roleid_checked(NameStr(*username));
1985 languageoid = convert_language_name(languagename);
1986 mode = convert_language_priv_string(priv_type_text);
1988 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1990 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1994 * has_language_privilege_name
1995 * Check user privileges on a language given
1996 * text languagename and text priv name.
1997 * current_user is assumed
2000 has_language_privilege_name(PG_FUNCTION_ARGS)
2002 text *languagename = PG_GETARG_TEXT_P(0);
2003 text *priv_type_text = PG_GETARG_TEXT_P(1);
2007 AclResult aclresult;
2009 roleid = GetUserId();
2010 languageoid = convert_language_name(languagename);
2011 mode = convert_language_priv_string(priv_type_text);
2013 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2015 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2019 * has_language_privilege_name_id
2020 * Check user privileges on a language given
2021 * name usename, language oid, and text priv name.
2024 has_language_privilege_name_id(PG_FUNCTION_ARGS)
2026 Name username = PG_GETARG_NAME(0);
2027 Oid languageoid = PG_GETARG_OID(1);
2028 text *priv_type_text = PG_GETARG_TEXT_P(2);
2031 AclResult aclresult;
2033 roleid = get_roleid_checked(NameStr(*username));
2034 mode = convert_language_priv_string(priv_type_text);
2036 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2038 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2042 * has_language_privilege_id
2043 * Check user privileges on a language given
2044 * language oid, and text priv name.
2045 * current_user is assumed
2048 has_language_privilege_id(PG_FUNCTION_ARGS)
2050 Oid languageoid = PG_GETARG_OID(0);
2051 text *priv_type_text = PG_GETARG_TEXT_P(1);
2054 AclResult aclresult;
2056 roleid = GetUserId();
2057 mode = convert_language_priv_string(priv_type_text);
2059 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2061 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2065 * has_language_privilege_id_name
2066 * Check user privileges on a language given
2067 * roleid, text languagename, and text priv name.
2070 has_language_privilege_id_name(PG_FUNCTION_ARGS)
2072 Oid roleid = PG_GETARG_OID(0);
2073 text *languagename = PG_GETARG_TEXT_P(1);
2074 text *priv_type_text = PG_GETARG_TEXT_P(2);
2077 AclResult aclresult;
2079 languageoid = convert_language_name(languagename);
2080 mode = convert_language_priv_string(priv_type_text);
2082 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2084 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2088 * has_language_privilege_id_id
2089 * Check user privileges on a language given
2090 * roleid, language oid, and text priv name.
2093 has_language_privilege_id_id(PG_FUNCTION_ARGS)
2095 Oid roleid = PG_GETARG_OID(0);
2096 Oid languageoid = PG_GETARG_OID(1);
2097 text *priv_type_text = PG_GETARG_TEXT_P(2);
2099 AclResult aclresult;
2101 mode = convert_language_priv_string(priv_type_text);
2103 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2105 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2109 * Support routines for has_language_privilege family.
2113 * Given a language name expressed as a string, look it up and return Oid
2116 convert_language_name(text *languagename)
2121 langname = DatumGetCString(DirectFunctionCall1(textout,
2122 PointerGetDatum(languagename)));
2124 oid = GetSysCacheOid(LANGNAME,
2125 CStringGetDatum(langname),
2127 if (!OidIsValid(oid))
2129 (errcode(ERRCODE_UNDEFINED_OBJECT),
2130 errmsg("language \"%s\" does not exist", langname)));
2136 * convert_language_priv_string
2137 * Convert text string to AclMode value.
2140 convert_language_priv_string(text *priv_type_text)
2144 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2145 PointerGetDatum(priv_type_text)));
2148 * Return mode from priv_type string
2150 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2152 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2153 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2156 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2157 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2158 return ACL_NO_RIGHTS; /* keep compiler quiet */
2163 * has_schema_privilege variants
2164 * These are all named "has_schema_privilege" at the SQL level.
2165 * They take various combinations of schema name, schema OID,
2166 * user name, user OID, or implicit user = current_user.
2168 * The result is a boolean value: true if user has the indicated
2169 * privilege, false if not.
2173 * has_schema_privilege_name_name
2174 * Check user privileges on a schema given
2175 * name username, text schemaname, and text priv name.
2178 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2180 Name username = PG_GETARG_NAME(0);
2181 text *schemaname = PG_GETARG_TEXT_P(1);
2182 text *priv_type_text = PG_GETARG_TEXT_P(2);
2186 AclResult aclresult;
2188 roleid = get_roleid_checked(NameStr(*username));
2189 schemaoid = convert_schema_name(schemaname);
2190 mode = convert_schema_priv_string(priv_type_text);
2192 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2194 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2198 * has_schema_privilege_name
2199 * Check user privileges on a schema given
2200 * text schemaname and text priv name.
2201 * current_user is assumed
2204 has_schema_privilege_name(PG_FUNCTION_ARGS)
2206 text *schemaname = PG_GETARG_TEXT_P(0);
2207 text *priv_type_text = PG_GETARG_TEXT_P(1);
2211 AclResult aclresult;
2213 roleid = GetUserId();
2214 schemaoid = convert_schema_name(schemaname);
2215 mode = convert_schema_priv_string(priv_type_text);
2217 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2219 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2223 * has_schema_privilege_name_id
2224 * Check user privileges on a schema given
2225 * name usename, schema oid, and text priv name.
2228 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2230 Name username = PG_GETARG_NAME(0);
2231 Oid schemaoid = PG_GETARG_OID(1);
2232 text *priv_type_text = PG_GETARG_TEXT_P(2);
2235 AclResult aclresult;
2237 roleid = get_roleid_checked(NameStr(*username));
2238 mode = convert_schema_priv_string(priv_type_text);
2240 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2242 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2246 * has_schema_privilege_id
2247 * Check user privileges on a schema given
2248 * schema oid, and text priv name.
2249 * current_user is assumed
2252 has_schema_privilege_id(PG_FUNCTION_ARGS)
2254 Oid schemaoid = PG_GETARG_OID(0);
2255 text *priv_type_text = PG_GETARG_TEXT_P(1);
2258 AclResult aclresult;
2260 roleid = GetUserId();
2261 mode = convert_schema_priv_string(priv_type_text);
2263 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2265 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2269 * has_schema_privilege_id_name
2270 * Check user privileges on a schema given
2271 * roleid, text schemaname, and text priv name.
2274 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2276 Oid roleid = PG_GETARG_OID(0);
2277 text *schemaname = PG_GETARG_TEXT_P(1);
2278 text *priv_type_text = PG_GETARG_TEXT_P(2);
2281 AclResult aclresult;
2283 schemaoid = convert_schema_name(schemaname);
2284 mode = convert_schema_priv_string(priv_type_text);
2286 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2288 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2292 * has_schema_privilege_id_id
2293 * Check user privileges on a schema given
2294 * roleid, schema oid, and text priv name.
2297 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2299 Oid roleid = PG_GETARG_OID(0);
2300 Oid schemaoid = PG_GETARG_OID(1);
2301 text *priv_type_text = PG_GETARG_TEXT_P(2);
2303 AclResult aclresult;
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 * Support routines for has_schema_privilege family.
2317 * Given a schema name expressed as a string, look it up and return Oid
2320 convert_schema_name(text *schemaname)
2325 nspname = DatumGetCString(DirectFunctionCall1(textout,
2326 PointerGetDatum(schemaname)));
2328 oid = GetSysCacheOid(NAMESPACENAME,
2329 CStringGetDatum(nspname),
2331 if (!OidIsValid(oid))
2333 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2334 errmsg("schema \"%s\" does not exist", nspname)));
2340 * convert_schema_priv_string
2341 * Convert text string to AclMode value.
2344 convert_schema_priv_string(text *priv_type_text)
2348 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2349 PointerGetDatum(priv_type_text)));
2352 * Return mode from priv_type string
2354 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2356 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2357 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2359 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2361 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2362 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2365 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2366 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2367 return ACL_NO_RIGHTS; /* keep compiler quiet */
2371 * has_tablespace_privilege variants
2372 * These are all named "has_tablespace_privilege" at the SQL level.
2373 * They take various combinations of tablespace name, tablespace OID,
2374 * user name, user OID, or implicit user = current_user.
2376 * The result is a boolean value: true if user has the indicated
2377 * privilege, false if not.
2381 * has_tablespace_privilege_name_name
2382 * Check user privileges on a tablespace given
2383 * name username, text tablespacename, and text priv name.
2386 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2388 Name username = PG_GETARG_NAME(0);
2389 text *tablespacename = PG_GETARG_TEXT_P(1);
2390 text *priv_type_text = PG_GETARG_TEXT_P(2);
2394 AclResult aclresult;
2396 roleid = get_roleid_checked(NameStr(*username));
2397 tablespaceoid = convert_tablespace_name(tablespacename);
2398 mode = convert_tablespace_priv_string(priv_type_text);
2400 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2402 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2406 * has_tablespace_privilege_name
2407 * Check user privileges on a tablespace given
2408 * text tablespacename and text priv name.
2409 * current_user is assumed
2412 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2414 text *tablespacename = PG_GETARG_TEXT_P(0);
2415 text *priv_type_text = PG_GETARG_TEXT_P(1);
2419 AclResult aclresult;
2421 roleid = GetUserId();
2422 tablespaceoid = convert_tablespace_name(tablespacename);
2423 mode = convert_tablespace_priv_string(priv_type_text);
2425 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2427 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2431 * has_tablespace_privilege_name_id
2432 * Check user privileges on a tablespace given
2433 * name usename, tablespace oid, and text priv name.
2436 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2438 Name username = PG_GETARG_NAME(0);
2439 Oid tablespaceoid = PG_GETARG_OID(1);
2440 text *priv_type_text = PG_GETARG_TEXT_P(2);
2443 AclResult aclresult;
2445 roleid = get_roleid_checked(NameStr(*username));
2446 mode = convert_tablespace_priv_string(priv_type_text);
2448 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2450 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2454 * has_tablespace_privilege_id
2455 * Check user privileges on a tablespace given
2456 * tablespace oid, and text priv name.
2457 * current_user is assumed
2460 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2462 Oid tablespaceoid = PG_GETARG_OID(0);
2463 text *priv_type_text = PG_GETARG_TEXT_P(1);
2466 AclResult aclresult;
2468 roleid = GetUserId();
2469 mode = convert_tablespace_priv_string(priv_type_text);
2471 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2473 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2477 * has_tablespace_privilege_id_name
2478 * Check user privileges on a tablespace given
2479 * roleid, text tablespacename, and text priv name.
2482 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2484 Oid roleid = PG_GETARG_OID(0);
2485 text *tablespacename = PG_GETARG_TEXT_P(1);
2486 text *priv_type_text = PG_GETARG_TEXT_P(2);
2489 AclResult aclresult;
2491 tablespaceoid = convert_tablespace_name(tablespacename);
2492 mode = convert_tablespace_priv_string(priv_type_text);
2494 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2496 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2500 * has_tablespace_privilege_id_id
2501 * Check user privileges on a tablespace given
2502 * roleid, tablespace oid, and text priv name.
2505 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2507 Oid roleid = PG_GETARG_OID(0);
2508 Oid tablespaceoid = PG_GETARG_OID(1);
2509 text *priv_type_text = PG_GETARG_TEXT_P(2);
2511 AclResult aclresult;
2513 mode = convert_tablespace_priv_string(priv_type_text);
2515 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2517 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2521 * Support routines for has_tablespace_privilege family.
2525 * Given a tablespace name expressed as a string, look it up and return Oid
2528 convert_tablespace_name(text *tablespacename)
2533 spcname = DatumGetCString(DirectFunctionCall1(textout,
2534 PointerGetDatum(tablespacename)));
2535 oid = get_tablespace_oid(spcname);
2537 if (!OidIsValid(oid))
2539 (errcode(ERRCODE_UNDEFINED_OBJECT),
2540 errmsg("tablespace \"%s\" does not exist", spcname)));
2546 * convert_tablespace_priv_string
2547 * Convert text string to AclMode value.
2550 convert_tablespace_priv_string(text *priv_type_text)
2554 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2555 PointerGetDatum(priv_type_text)));
2558 * Return mode from priv_type string
2560 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2562 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2563 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2566 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2567 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2568 return ACL_NO_RIGHTS; /* keep compiler quiet */
2572 * pg_has_role variants
2573 * These are all named "pg_has_role" at the SQL level.
2574 * They take various combinations of role name, role OID,
2575 * user name, user OID, or implicit user = current_user.
2577 * The result is a boolean value: true if user has the indicated
2578 * privilege, false if not.
2582 * pg_has_role_name_name
2583 * Check user privileges on a role given
2584 * name username, name rolename, and text priv name.
2587 pg_has_role_name_name(PG_FUNCTION_ARGS)
2589 Name username = PG_GETARG_NAME(0);
2590 Name rolename = PG_GETARG_NAME(1);
2591 text *priv_type_text = PG_GETARG_TEXT_P(2);
2595 AclResult aclresult;
2597 roleid = get_roleid_checked(NameStr(*username));
2598 roleoid = get_roleid_checked(NameStr(*rolename));
2599 mode = convert_role_priv_string(priv_type_text);
2601 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2603 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2608 * Check user privileges on a role given
2609 * name rolename and text priv name.
2610 * current_user is assumed
2613 pg_has_role_name(PG_FUNCTION_ARGS)
2615 Name rolename = PG_GETARG_NAME(0);
2616 text *priv_type_text = PG_GETARG_TEXT_P(1);
2620 AclResult aclresult;
2622 roleid = GetUserId();
2623 roleoid = get_roleid_checked(NameStr(*rolename));
2624 mode = convert_role_priv_string(priv_type_text);
2626 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2628 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2632 * pg_has_role_name_id
2633 * Check user privileges on a role given
2634 * name usename, role oid, and text priv name.
2637 pg_has_role_name_id(PG_FUNCTION_ARGS)
2639 Name username = PG_GETARG_NAME(0);
2640 Oid roleoid = PG_GETARG_OID(1);
2641 text *priv_type_text = PG_GETARG_TEXT_P(2);
2644 AclResult aclresult;
2646 roleid = get_roleid_checked(NameStr(*username));
2647 mode = convert_role_priv_string(priv_type_text);
2649 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2651 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2656 * Check user privileges on a role given
2657 * role oid, and text priv name.
2658 * current_user is assumed
2661 pg_has_role_id(PG_FUNCTION_ARGS)
2663 Oid roleoid = PG_GETARG_OID(0);
2664 text *priv_type_text = PG_GETARG_TEXT_P(1);
2667 AclResult aclresult;
2669 roleid = GetUserId();
2670 mode = convert_role_priv_string(priv_type_text);
2672 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2674 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2678 * pg_has_role_id_name
2679 * Check user privileges on a role given
2680 * roleid, name rolename, and text priv name.
2683 pg_has_role_id_name(PG_FUNCTION_ARGS)
2685 Oid roleid = PG_GETARG_OID(0);
2686 Name rolename = PG_GETARG_NAME(1);
2687 text *priv_type_text = PG_GETARG_TEXT_P(2);
2690 AclResult aclresult;
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 * roleid, role oid, and text priv name.
2706 pg_has_role_id_id(PG_FUNCTION_ARGS)
2708 Oid roleid = PG_GETARG_OID(0);
2709 Oid roleoid = PG_GETARG_OID(1);
2710 text *priv_type_text = PG_GETARG_TEXT_P(2);
2712 AclResult aclresult;
2714 mode = convert_role_priv_string(priv_type_text);
2716 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2718 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2722 * Support routines for pg_has_role family.
2726 * convert_role_priv_string
2727 * Convert text string to AclMode value.
2729 * We use USAGE to denote whether the privileges of the role are accessible
2730 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
2731 * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
2732 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
2733 * is shared only with pg_role_aclcheck, below.
2736 convert_role_priv_string(text *priv_type_text)
2740 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2741 PointerGetDatum(priv_type_text)));
2744 * Return mode from priv_type string
2746 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2748 if (pg_strcasecmp(priv_type, "MEMBER") == 0)
2750 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0 ||
2751 pg_strcasecmp(priv_type, "USAGE WITH ADMIN OPTION") == 0 ||
2752 pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0 ||
2753 pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
2754 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2757 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2758 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2759 return ACL_NO_RIGHTS; /* keep compiler quiet */
2764 * Quick-and-dirty support for pg_has_role
2767 pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
2769 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
2771 if (is_admin_of_role(roleid, role_oid))
2774 if (mode & ACL_CREATE)
2776 if (is_member_of_role(roleid, role_oid))
2779 if (mode & ACL_USAGE)
2781 if (has_privs_of_role(roleid, role_oid))
2784 return ACLCHECK_NO_PRIV;
2789 * initialization function (called by InitPostgres)
2792 initialize_acl(void)
2794 if (!IsBootstrapProcessingMode())
2797 * In normal mode, set a callback on any syscache invalidation of
2798 * pg_auth_members rows
2800 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
2801 RoleMembershipCacheCallback,
2807 * RoleMembershipCacheCallback
2808 * Syscache inval callback function
2811 RoleMembershipCacheCallback(Datum arg, Oid relid)
2813 /* Force membership caches to be recomputed on next use */
2814 cached_privs_role = InvalidOid;
2815 cached_member_role = InvalidOid;
2819 /* Check if specified role has rolinherit set */
2821 has_rolinherit(Oid roleid)
2823 bool result = false;
2826 utup = SearchSysCache(AUTHOID,
2827 ObjectIdGetDatum(roleid),
2829 if (HeapTupleIsValid(utup))
2831 result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
2832 ReleaseSysCache(utup);
2839 * Get a list of roles that the specified roleid has the privileges of
2841 * This is defined not to recurse through roles that don't have rolinherit
2842 * set; for such roles, membership implies the ability to do SET ROLE, but
2843 * the privileges are not available until you've done so.
2845 * Since indirect membership testing is relatively expensive, we cache
2846 * a list of memberships. Hence, the result is only guaranteed good until
2847 * the next call of roles_has_privs_of()!
2849 * For the benefit of select_best_grantor, the result is defined to be
2850 * in breadth-first order, ie, closer relationships earlier.
2853 roles_has_privs_of(Oid roleid)
2857 List *new_cached_privs_roles;
2858 MemoryContext oldctx;
2860 /* If cache is already valid, just return the list */
2861 if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
2862 return cached_privs_roles;
2865 * Find all the roles that roleid is a member of, including multi-level
2866 * recursion. The role itself will always be the first element of the
2869 * Each element of the list is scanned to see if it adds any indirect
2870 * memberships. We can use a single list as both the record of
2871 * already-found memberships and the agenda of roles yet to be scanned.
2872 * This is a bit tricky but works because the foreach() macro doesn't
2873 * fetch the next list element until the bottom of the loop.
2875 roles_list = list_make1_oid(roleid);
2877 foreach(l, roles_list)
2879 Oid memberid = lfirst_oid(l);
2883 /* Ignore non-inheriting roles */
2884 if (!has_rolinherit(memberid))
2887 /* Find roles that memberid is directly a member of */
2888 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
2889 ObjectIdGetDatum(memberid),
2891 for (i = 0; i < memlist->n_members; i++)
2893 HeapTuple tup = &memlist->members[i]->tuple;
2894 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
2897 * Even though there shouldn't be any loops in the membership
2898 * graph, we must test for having already seen this role. It is
2899 * legal for instance to have both A->B and A->C->B.
2901 roles_list = list_append_unique_oid(roles_list, otherid);
2903 ReleaseSysCacheList(memlist);
2907 * Copy the completed list into TopMemoryContext so it will persist.
2909 oldctx = MemoryContextSwitchTo(TopMemoryContext);
2910 new_cached_privs_roles = list_copy(roles_list);
2911 MemoryContextSwitchTo(oldctx);
2912 list_free(roles_list);
2915 * Now safe to assign to state variable
2917 cached_privs_role = InvalidOid; /* just paranoia */
2918 list_free(cached_privs_roles);
2919 cached_privs_roles = new_cached_privs_roles;
2920 cached_privs_role = roleid;
2922 /* And now we can return the answer */
2923 return cached_privs_roles;
2928 * Get a list of roles that the specified roleid is a member of
2930 * This is defined to recurse through roles regardless of rolinherit.
2932 * Since indirect membership testing is relatively expensive, we cache
2933 * a list of memberships. Hence, the result is only guaranteed good until
2934 * the next call of roles_is_member_of()!
2937 roles_is_member_of(Oid roleid)
2941 List *new_cached_membership_roles;
2942 MemoryContext oldctx;
2944 /* If cache is already valid, just return the list */
2945 if (OidIsValid(cached_member_role) && cached_member_role == roleid)
2946 return cached_membership_roles;
2949 * Find all the roles that roleid is a member of, including multi-level
2950 * recursion. The role itself will always be the first element of the
2953 * Each element of the list is scanned to see if it adds any indirect
2954 * memberships. We can use a single list as both the record of
2955 * already-found memberships and the agenda of roles yet to be scanned.
2956 * This is a bit tricky but works because the foreach() macro doesn't
2957 * fetch the next list element until the bottom of the loop.
2959 roles_list = list_make1_oid(roleid);
2961 foreach(l, roles_list)
2963 Oid memberid = lfirst_oid(l);
2967 /* Find roles that memberid is directly a member of */
2968 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
2969 ObjectIdGetDatum(memberid),
2971 for (i = 0; i < memlist->n_members; i++)
2973 HeapTuple tup = &memlist->members[i]->tuple;
2974 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
2977 * Even though there shouldn't be any loops in the membership
2978 * graph, we must test for having already seen this role. It is
2979 * legal for instance to have both A->B and A->C->B.
2981 roles_list = list_append_unique_oid(roles_list, otherid);
2983 ReleaseSysCacheList(memlist);
2987 * Copy the completed list into TopMemoryContext so it will persist.
2989 oldctx = MemoryContextSwitchTo(TopMemoryContext);
2990 new_cached_membership_roles = list_copy(roles_list);
2991 MemoryContextSwitchTo(oldctx);
2992 list_free(roles_list);
2995 * Now safe to assign to state variable
2997 cached_member_role = InvalidOid; /* just paranoia */
2998 list_free(cached_membership_roles);
2999 cached_membership_roles = new_cached_membership_roles;
3000 cached_member_role = roleid;
3002 /* And now we can return the answer */
3003 return cached_membership_roles;
3008 * Does member have the privileges of role (directly or indirectly)?
3010 * This is defined not to recurse through roles that don't have rolinherit
3011 * set; for such roles, membership implies the ability to do SET ROLE, but
3012 * the privileges are not available until you've done so.
3015 has_privs_of_role(Oid member, Oid role)
3017 /* Fast path for simple case */
3021 /* Superusers have every privilege, so are part of every role */
3022 if (superuser_arg(member))
3026 * Find all the roles that member has the privileges of, including
3027 * multi-level recursion, then see if target role is any one of them.
3029 return list_member_oid(roles_has_privs_of(member), role);
3034 * Is member a member of role (directly or indirectly)?
3036 * This is defined to recurse through roles regardless of rolinherit.
3039 is_member_of_role(Oid member, Oid role)
3041 /* Fast path for simple case */
3045 /* Superusers have every privilege, so are part of every role */
3046 if (superuser_arg(member))
3050 * Find all the roles that member is a member of, including multi-level
3051 * recursion, then see if target role is any one of them.
3053 return list_member_oid(roles_is_member_of(member), role);
3057 * check_is_member_of_role
3058 * is_member_of_role with a standard permission-violation error if not
3061 check_is_member_of_role(Oid member, Oid role)
3063 if (!is_member_of_role(member, role))
3065 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3066 errmsg("must be member of role \"%s\"",
3067 GetUserNameFromId(role))));
3071 * Is member a member of role, not considering superuserness?
3073 * This is identical to is_member_of_role except we ignore superuser
3077 is_member_of_role_nosuper(Oid member, Oid role)
3079 /* Fast path for simple case */
3084 * Find all the roles that member is a member of, including multi-level
3085 * recursion, then see if target role is any one of them.
3087 return list_member_oid(roles_is_member_of(member), role);
3092 * Is member an admin of role (directly or indirectly)? That is, is it
3093 * a member WITH ADMIN OPTION?
3095 * We could cache the result as for is_member_of_role, but currently this
3096 * is not used in any performance-critical paths, so we don't.
3099 is_admin_of_role(Oid member, Oid role)
3101 bool result = false;
3105 /* Fast path for simple case */
3109 /* Superusers have every privilege, so are part of every role */
3110 if (superuser_arg(member))
3114 * Find all the roles that member is a member of, including multi-level
3115 * recursion. We build a list in the same way that is_member_of_role does
3116 * to track visited and unvisited roles.
3118 roles_list = list_make1_oid(member);
3120 foreach(l, roles_list)
3122 Oid memberid = lfirst_oid(l);
3126 /* Find roles that memberid is directly a member of */
3127 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3128 ObjectIdGetDatum(memberid),
3130 for (i = 0; i < memlist->n_members; i++)
3132 HeapTuple tup = &memlist->members[i]->tuple;
3133 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3135 if (otherid == role &&
3136 ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
3138 /* Found what we came for, so can stop searching */
3143 roles_list = list_append_unique_oid(roles_list, otherid);
3145 ReleaseSysCacheList(memlist);
3150 list_free(roles_list);
3156 /* does what it says ... */
3158 count_one_bits(AclMode mask)
3162 /* this code relies on AclMode being an unsigned type */
3174 * Select the effective grantor ID for a GRANT or REVOKE operation.
3176 * The grantor must always be either the object owner or some role that has
3177 * been explicitly granted grant options. This ensures that all granted
3178 * privileges appear to flow from the object owner, and there are never
3179 * multiple "original sources" of a privilege. Therefore, if the would-be
3180 * grantor is a member of a role that has the needed grant options, we have
3181 * to do the grant as that role instead.
3183 * It is possible that the would-be grantor is a member of several roles
3184 * that have different subsets of the desired grant options, but no one
3185 * role has 'em all. In this case we pick a role with the largest number
3186 * of desired options. Ties are broken in favor of closer ancestors.
3188 * roleId: the role attempting to do the GRANT/REVOKE
3189 * privileges: the privileges to be granted/revoked
3190 * acl: the ACL of the object in question
3191 * ownerId: the role owning the object in question
3192 * *grantorId: receives the OID of the role to do the grant as
3193 * *grantOptions: receives the grant options actually held by grantorId
3195 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
3198 select_best_grantor(Oid roleId, AclMode privileges,
3199 const Acl *acl, Oid ownerId,
3200 Oid *grantorId, AclMode *grantOptions)
3202 AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
3208 * The object owner is always treated as having all grant options, so if
3209 * roleId is the owner it's easy. Also, if roleId is a superuser it's
3210 * easy: superusers are implicitly members of every role, so they act as
3213 if (roleId == ownerId || superuser_arg(roleId))
3215 *grantorId = ownerId;
3216 *grantOptions = needed_goptions;
3221 * Otherwise we have to do a careful search to see if roleId has the
3222 * privileges of any suitable role. Note: we can hang onto the result of
3223 * roles_has_privs_of() throughout this loop, because aclmask_direct()
3224 * doesn't query any role memberships.
3226 roles_list = roles_has_privs_of(roleId);
3228 /* initialize candidate result as default */
3229 *grantorId = roleId;
3230 *grantOptions = ACL_NO_RIGHTS;
3233 foreach(l, roles_list)
3235 Oid otherrole = lfirst_oid(l);
3238 otherprivs = aclmask_direct(acl, otherrole, ownerId,
3239 needed_goptions, ACLMASK_ALL);
3240 if (otherprivs == needed_goptions)
3242 /* Found a suitable grantor */
3243 *grantorId = otherrole;
3244 *grantOptions = otherprivs;
3249 * If it has just some of the needed privileges, remember best
3252 if (otherprivs != ACL_NO_RIGHTS)
3254 int nnewrights = count_one_bits(otherprivs);
3256 if (nnewrights > nrights)
3258 *grantorId = otherrole;
3259 *grantOptions = otherprivs;
3260 nrights = nnewrights;