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.122 2005/07/26 16:38:27 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
306 * grantor to the superuser.
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;
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
569 * grant options. This is because his grant options come "from the
570 * system" and not from his own efforts. (The SQL spec says that the
571 * owner's rights come from a "_SYSTEM" authid.) However, we do
572 * consider that the owner's ordinary privileges are self-granted;
573 * this lets him revoke them. We implement the owner's grant options
574 * without any explicit "_SYSTEM"-like ACL entry, by internally
575 * special-casing the owner 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.
635 * If one exists, just modify the entry in-place (well, in the same
636 * position, since we actually return a copy); otherwise, insert the
637 * new entry at the end.
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
704 * only 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
746 * new 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
767 * may now have generated an ACL containing duplicate entries. Find
768 * them and merge them so that there are not duplicates. (This is
769 * relatively expensive since we use a stupid O(N^2) algorithm, but
770 * it's unlikely to be the normal case.)
772 * To simplify deletion of duplicate entries, we temporarily leave them
773 * in the array but set their privilege masks to zero; when we reach
774 * such an entry it's just skipped. (Thus, a side effect of this code
775 * will be to remove privilege-free entries, should there be any in
776 * the input.) dst is the next output slot, targ is the currently
777 * considered input slot (always >= dst), and src scans entries to the
778 * right of targ looking for duplicates. Once an entry has been
779 * emitted to dst it is known duplicate-free and need not be
780 * considered anymore.
785 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
787 /* ignore if deleted in an earlier pass */
788 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
790 /* find and merge any duplicates */
791 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
794 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
796 if (aclitem_match(targ_aip, src_aip))
798 ACLITEM_SET_RIGHTS(*targ_aip,
799 ACLITEM_GET_RIGHTS(*targ_aip) |
800 ACLITEM_GET_RIGHTS(*src_aip));
801 /* mark the duplicate deleted */
802 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
805 /* and emit to output */
806 new_aip[dst] = *targ_aip;
809 /* Adjust array size to be 'dst' items */
810 ARR_DIMS(new_acl)[0] = dst;
811 ARR_SIZE(new_acl) = ACL_N_SIZE(dst);
819 * When granting grant options, we must disallow attempts to set up circular
820 * chains of grant options. Suppose A (the object owner) grants B some
821 * privileges with grant option, and B re-grants them to C. If C could
822 * grant the privileges to B as well, then A would be unable to effectively
823 * revoke the privileges from B, since recursive_revoke would consider that
824 * B still has 'em from C.
826 * We check for this by recursively deleting all grant options belonging to
827 * the target grantee, and then seeing if the would-be grantor still has the
828 * grant option or not.
831 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
841 * For now, grant options can only be granted to roles, not PUBLIC.
842 * Otherwise we'd have to work a bit harder here.
844 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
846 /* The owner always has grant options, no need to check */
847 if (mod_aip->ai_grantor == ownerId)
850 /* Make a working copy */
851 acl = allocacl(ACL_NUM(old_acl));
852 memcpy(acl, old_acl, ACL_SIZE(old_acl));
854 /* Zap all grant options of target grantee, plus what depends on 'em */
858 for (i = 0; i < num; i++)
860 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
861 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
865 /* We'll actually zap ordinary privs too, but no matter */
866 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
867 ownerId, DROP_CASCADE);
876 /* Now we can compute grantor's independently-derived privileges */
877 own_privs = aclmask(acl,
880 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
882 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
884 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
886 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
887 errmsg("grant options cannot be granted back to your own grantor")));
894 * Ensure that no privilege is "abandoned". A privilege is abandoned
895 * if the user that granted the privilege loses the grant option. (So
896 * the chain through which it was granted is broken.) Either the
897 * abandoned privileges are revoked as well, or an error message is
898 * printed, depending on the drop behavior option.
900 * acl: the input ACL list
901 * grantee: the user from whom some grant options have been revoked
902 * revoke_privs: the grant options being revoked
903 * ownerId: Oid of object owner
904 * behavior: RESTRICT or CASCADE behavior for recursive removal
906 * The input Acl object is pfree'd if replaced.
909 recursive_revoke(Acl *acl,
911 AclMode revoke_privs,
913 DropBehavior behavior)
920 /* The owner can never truly lose grant options, so short-circuit */
921 if (grantee == ownerId)
924 /* The grantee might still have the privileges via another grantor */
925 still_has = aclmask(acl, grantee, ownerId,
926 ACL_GRANT_OPTION_FOR(revoke_privs),
928 revoke_privs &= ~still_has;
929 if (revoke_privs == ACL_NO_RIGHTS)
935 for (i = 0; i < num; i++)
937 if (aip[i].ai_grantor == grantee
938 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
943 if (behavior == DROP_RESTRICT)
945 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
946 errmsg("dependent privileges exist"),
947 errhint("Use CASCADE to revoke them too.")));
949 mod_acl.ai_grantor = grantee;
950 mod_acl.ai_grantee = aip[i].ai_grantee;
951 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
955 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
970 * aclmask --- compute bitmask of all privileges held by roleid.
972 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
973 * held by the given roleid according to the given ACL list, ANDed
974 * with 'mask'. (The point of passing 'mask' is to let the routine
975 * exit early if all privileges of interest have been found.)
977 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
978 * is known true. (This lets us exit soonest in cases where the
979 * caller is only going to test for zero or nonzero result.)
983 * To see if any of a set of privileges are held:
984 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
986 * To see if all of a set of privileges are held:
987 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
989 * To determine exactly which of a set of privileges are held:
990 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
993 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
994 AclMode mask, AclMaskHow how)
1003 * Null ACL should not happen, since caller should have inserted
1004 * appropriate default
1007 elog(ERROR, "null ACL");
1009 /* Quick exit for mask == 0 */
1015 /* Owner always implicitly has all grant options */
1016 if (has_privs_of_role(roleid, ownerId))
1018 result = mask & ACLITEM_ALL_GOPTION_BITS;
1024 aidat = ACL_DAT(acl);
1027 * Check privileges granted directly to user 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 roles.
1044 * We do this in a separate pass to minimize expensive indirect
1045 * membership tests. In particular, it's worth testing whether
1046 * a given ACL entry grants any privileges still of interest before
1047 * we perform the is_member test.
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;
1074 * Find out all the roleids mentioned in an Acl.
1075 * Note that we do not distinguish grantors from grantees.
1077 * *roleids is set to point to a palloc'd array containing distinct OIDs
1078 * in sorted order. The length of the array is the function result.
1081 aclmembers(const Acl *acl, Oid **roleids)
1084 const AclItem *acldat;
1089 if (acl == NULL || ACL_NUM(acl) == 0)
1095 /* Allocate the worst-case space requirement */
1096 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1097 acldat = ACL_DAT(acl);
1100 * Walk the ACL collecting mentioned RoleIds.
1103 for (i = 0; i < ACL_NUM(acl); i++)
1105 const AclItem *ai = &acldat[i];
1107 if (ai->ai_grantee != ACL_ID_PUBLIC)
1108 list[j++] = ai->ai_grantee;
1109 /* grantor is currently never PUBLIC, but let's check anyway */
1110 if (ai->ai_grantor != ACL_ID_PUBLIC)
1111 list[j++] = ai->ai_grantor;
1114 /* Sort the array */
1115 qsort(list, j, sizeof(Oid), oidComparator);
1117 /* Remove duplicates from the array */
1119 for (i = 1; i < j; i++)
1121 if (list[k] != list[i])
1122 list[++k] = list[i];
1126 * We could repalloc the array down to minimum size, but it's hardly
1127 * worth it since it's only transient memory.
1136 * qsort comparison function for Oids
1139 oidComparator(const void *arg1, const void *arg2)
1141 Oid oid1 = * (const Oid *) arg1;
1142 Oid oid2 = * (const Oid *) arg2;
1153 * aclinsert (exported function)
1156 aclinsert(PG_FUNCTION_ARGS)
1159 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1160 errmsg("aclinsert is no longer supported")));
1162 PG_RETURN_NULL(); /* keep compiler quiet */
1166 aclremove(PG_FUNCTION_ARGS)
1169 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1170 errmsg("aclremove is no longer supported")));
1172 PG_RETURN_NULL(); /* keep compiler quiet */
1176 aclcontains(PG_FUNCTION_ARGS)
1178 Acl *acl = PG_GETARG_ACL_P(0);
1179 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1185 aidat = ACL_DAT(acl);
1186 for (i = 0; i < num; ++i)
1188 if (aip->ai_grantee == aidat[i].ai_grantee &&
1189 aip->ai_grantor == aidat[i].ai_grantor &&
1190 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1191 PG_RETURN_BOOL(true);
1193 PG_RETURN_BOOL(false);
1197 makeaclitem(PG_FUNCTION_ARGS)
1199 Oid grantee = PG_GETARG_OID(0);
1200 Oid grantor = PG_GETARG_OID(1);
1201 text *privtext = PG_GETARG_TEXT_P(2);
1202 bool goption = PG_GETARG_BOOL(3);
1206 priv = convert_priv_string(privtext);
1208 result = (AclItem *) palloc(sizeof(AclItem));
1210 result->ai_grantee = grantee;
1211 result->ai_grantor = grantor;
1213 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1214 (goption ? priv : ACL_NO_RIGHTS));
1216 PG_RETURN_ACLITEM_P(result);
1220 convert_priv_string(text *priv_type_text)
1224 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1225 PointerGetDatum(priv_type_text)));
1227 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1229 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1231 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1233 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1235 if (pg_strcasecmp(priv_type, "RULE") == 0)
1237 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1238 return ACL_REFERENCES;
1239 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1241 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1243 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1245 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1247 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1248 return ACL_CREATE_TEMP;
1249 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1250 return ACL_CREATE_TEMP;
1253 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1254 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1255 return ACL_NO_RIGHTS; /* keep compiler quiet */
1260 * has_table_privilege variants
1261 * These are all named "has_table_privilege" at the SQL level.
1262 * They take various combinations of relation name, relation OID,
1263 * user name, user OID, or implicit user = current_user.
1265 * The result is a boolean value: true if user has the indicated
1266 * privilege, false if not.
1270 * has_table_privilege_name_name
1271 * Check user privileges on a table given
1272 * name username, text tablename, and text priv name.
1275 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1277 Name rolename = PG_GETARG_NAME(0);
1278 text *tablename = PG_GETARG_TEXT_P(1);
1279 text *priv_type_text = PG_GETARG_TEXT_P(2);
1283 AclResult aclresult;
1285 roleid = get_roleid_checked(NameStr(*rolename));
1286 tableoid = convert_table_name(tablename);
1287 mode = convert_table_priv_string(priv_type_text);
1289 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1291 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1295 * has_table_privilege_name
1296 * Check user privileges on a table given
1297 * text tablename and text priv name.
1298 * current_user is assumed
1301 has_table_privilege_name(PG_FUNCTION_ARGS)
1303 text *tablename = PG_GETARG_TEXT_P(0);
1304 text *priv_type_text = PG_GETARG_TEXT_P(1);
1308 AclResult aclresult;
1310 roleid = GetUserId();
1311 tableoid = convert_table_name(tablename);
1312 mode = convert_table_priv_string(priv_type_text);
1314 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1316 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1320 * has_table_privilege_name_id
1321 * Check user privileges on a table given
1322 * name usename, table oid, and text priv name.
1325 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1327 Name username = PG_GETARG_NAME(0);
1328 Oid tableoid = PG_GETARG_OID(1);
1329 text *priv_type_text = PG_GETARG_TEXT_P(2);
1332 AclResult aclresult;
1334 roleid = get_roleid_checked(NameStr(*username));
1335 mode = convert_table_priv_string(priv_type_text);
1337 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1339 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1343 * has_table_privilege_id
1344 * Check user privileges on a table given
1345 * table oid, and text priv name.
1346 * current_user is assumed
1349 has_table_privilege_id(PG_FUNCTION_ARGS)
1351 Oid tableoid = PG_GETARG_OID(0);
1352 text *priv_type_text = PG_GETARG_TEXT_P(1);
1355 AclResult aclresult;
1357 roleid = GetUserId();
1358 mode = convert_table_priv_string(priv_type_text);
1360 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1362 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1366 * has_table_privilege_id_name
1367 * Check user privileges on a table given
1368 * roleid, text tablename, and text priv name.
1371 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1373 Oid roleid = PG_GETARG_OID(0);
1374 text *tablename = PG_GETARG_TEXT_P(1);
1375 text *priv_type_text = PG_GETARG_TEXT_P(2);
1378 AclResult aclresult;
1380 tableoid = convert_table_name(tablename);
1381 mode = convert_table_priv_string(priv_type_text);
1383 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1385 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1389 * has_table_privilege_id_id
1390 * Check user privileges on a table given
1391 * roleid, table oid, and text priv name.
1394 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1396 Oid roleid = PG_GETARG_OID(0);
1397 Oid tableoid = PG_GETARG_OID(1);
1398 text *priv_type_text = PG_GETARG_TEXT_P(2);
1400 AclResult aclresult;
1402 mode = convert_table_priv_string(priv_type_text);
1404 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1406 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1410 * Support routines for has_table_privilege family.
1414 * Given a table name expressed as a string, look it up and return Oid
1417 convert_table_name(text *tablename)
1421 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1423 return RangeVarGetRelid(relrv, false);
1427 * convert_table_priv_string
1428 * Convert text string to AclMode value.
1431 convert_table_priv_string(text *priv_type_text)
1435 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1436 PointerGetDatum(priv_type_text)));
1439 * Return mode from priv_type string
1441 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1443 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1444 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1446 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1448 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1449 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1451 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1453 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1454 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1456 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1458 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1459 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1461 if (pg_strcasecmp(priv_type, "RULE") == 0)
1463 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1464 return ACL_GRANT_OPTION_FOR(ACL_RULE);
1466 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1467 return ACL_REFERENCES;
1468 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1469 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1471 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1473 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1474 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1477 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1478 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1479 return ACL_NO_RIGHTS; /* keep compiler quiet */
1484 * has_database_privilege variants
1485 * These are all named "has_database_privilege" at the SQL level.
1486 * They take various combinations of database name, database OID,
1487 * user name, user OID, or implicit user = current_user.
1489 * The result is a boolean value: true if user has the indicated
1490 * privilege, false if not.
1494 * has_database_privilege_name_name
1495 * Check user privileges on a database given
1496 * name username, text databasename, and text priv name.
1499 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1501 Name username = PG_GETARG_NAME(0);
1502 text *databasename = PG_GETARG_TEXT_P(1);
1503 text *priv_type_text = PG_GETARG_TEXT_P(2);
1507 AclResult aclresult;
1509 roleid = get_roleid_checked(NameStr(*username));
1510 databaseoid = convert_database_name(databasename);
1511 mode = convert_database_priv_string(priv_type_text);
1513 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1515 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1519 * has_database_privilege_name
1520 * Check user privileges on a database given
1521 * text databasename and text priv name.
1522 * current_user is assumed
1525 has_database_privilege_name(PG_FUNCTION_ARGS)
1527 text *databasename = PG_GETARG_TEXT_P(0);
1528 text *priv_type_text = PG_GETARG_TEXT_P(1);
1532 AclResult aclresult;
1534 roleid = GetUserId();
1535 databaseoid = convert_database_name(databasename);
1536 mode = convert_database_priv_string(priv_type_text);
1538 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1540 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1544 * has_database_privilege_name_id
1545 * Check user privileges on a database given
1546 * name usename, database oid, and text priv name.
1549 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1551 Name username = PG_GETARG_NAME(0);
1552 Oid databaseoid = PG_GETARG_OID(1);
1553 text *priv_type_text = PG_GETARG_TEXT_P(2);
1556 AclResult aclresult;
1558 roleid = get_roleid_checked(NameStr(*username));
1559 mode = convert_database_priv_string(priv_type_text);
1561 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1563 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1567 * has_database_privilege_id
1568 * Check user privileges on a database given
1569 * database oid, and text priv name.
1570 * current_user is assumed
1573 has_database_privilege_id(PG_FUNCTION_ARGS)
1575 Oid databaseoid = PG_GETARG_OID(0);
1576 text *priv_type_text = PG_GETARG_TEXT_P(1);
1579 AclResult aclresult;
1581 roleid = GetUserId();
1582 mode = convert_database_priv_string(priv_type_text);
1584 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1586 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1590 * has_database_privilege_id_name
1591 * Check user privileges on a database given
1592 * roleid, text databasename, and text priv name.
1595 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1597 Oid roleid = PG_GETARG_OID(0);
1598 text *databasename = PG_GETARG_TEXT_P(1);
1599 text *priv_type_text = PG_GETARG_TEXT_P(2);
1602 AclResult aclresult;
1604 databaseoid = convert_database_name(databasename);
1605 mode = convert_database_priv_string(priv_type_text);
1607 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1609 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1613 * has_database_privilege_id_id
1614 * Check user privileges on a database given
1615 * roleid, database oid, and text priv name.
1618 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1620 Oid roleid = PG_GETARG_OID(0);
1621 Oid databaseoid = PG_GETARG_OID(1);
1622 text *priv_type_text = PG_GETARG_TEXT_P(2);
1624 AclResult aclresult;
1626 mode = convert_database_priv_string(priv_type_text);
1628 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1630 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1634 * Support routines for has_database_privilege family.
1638 * Given a database name expressed as a string, look it up and return Oid
1641 convert_database_name(text *databasename)
1646 dbname = DatumGetCString(DirectFunctionCall1(textout,
1647 PointerGetDatum(databasename)));
1649 oid = get_database_oid(dbname);
1650 if (!OidIsValid(oid))
1652 (errcode(ERRCODE_UNDEFINED_DATABASE),
1653 errmsg("database \"%s\" does not exist", dbname)));
1659 * convert_database_priv_string
1660 * Convert text string to AclMode value.
1663 convert_database_priv_string(text *priv_type_text)
1667 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1668 PointerGetDatum(priv_type_text)));
1671 * Return mode from priv_type string
1673 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1675 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1676 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1678 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1679 return ACL_CREATE_TEMP;
1680 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1681 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1683 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1684 return ACL_CREATE_TEMP;
1685 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1686 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1689 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1690 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1691 return ACL_NO_RIGHTS; /* keep compiler quiet */
1696 * has_function_privilege variants
1697 * These are all named "has_function_privilege" at the SQL level.
1698 * They take various combinations of function name, function OID,
1699 * user name, user OID, or implicit user = current_user.
1701 * The result is a boolean value: true if user has the indicated
1702 * privilege, false if not.
1706 * has_function_privilege_name_name
1707 * Check user privileges on a function given
1708 * name username, text functionname, and text priv name.
1711 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1713 Name username = PG_GETARG_NAME(0);
1714 text *functionname = PG_GETARG_TEXT_P(1);
1715 text *priv_type_text = PG_GETARG_TEXT_P(2);
1719 AclResult aclresult;
1721 roleid = get_roleid_checked(NameStr(*username));
1722 functionoid = convert_function_name(functionname);
1723 mode = convert_function_priv_string(priv_type_text);
1725 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1727 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1731 * has_function_privilege_name
1732 * Check user privileges on a function given
1733 * text functionname and text priv name.
1734 * current_user is assumed
1737 has_function_privilege_name(PG_FUNCTION_ARGS)
1739 text *functionname = PG_GETARG_TEXT_P(0);
1740 text *priv_type_text = PG_GETARG_TEXT_P(1);
1744 AclResult aclresult;
1746 roleid = GetUserId();
1747 functionoid = convert_function_name(functionname);
1748 mode = convert_function_priv_string(priv_type_text);
1750 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1752 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1756 * has_function_privilege_name_id
1757 * Check user privileges on a function given
1758 * name usename, function oid, and text priv name.
1761 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1763 Name username = PG_GETARG_NAME(0);
1764 Oid functionoid = PG_GETARG_OID(1);
1765 text *priv_type_text = PG_GETARG_TEXT_P(2);
1768 AclResult aclresult;
1770 roleid = get_roleid_checked(NameStr(*username));
1771 mode = convert_function_priv_string(priv_type_text);
1773 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1775 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1779 * has_function_privilege_id
1780 * Check user privileges on a function given
1781 * function oid, and text priv name.
1782 * current_user is assumed
1785 has_function_privilege_id(PG_FUNCTION_ARGS)
1787 Oid functionoid = PG_GETARG_OID(0);
1788 text *priv_type_text = PG_GETARG_TEXT_P(1);
1791 AclResult aclresult;
1793 roleid = GetUserId();
1794 mode = convert_function_priv_string(priv_type_text);
1796 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1798 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1802 * has_function_privilege_id_name
1803 * Check user privileges on a function given
1804 * roleid, text functionname, and text priv name.
1807 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1809 Oid roleid = PG_GETARG_OID(0);
1810 text *functionname = PG_GETARG_TEXT_P(1);
1811 text *priv_type_text = PG_GETARG_TEXT_P(2);
1814 AclResult aclresult;
1816 functionoid = convert_function_name(functionname);
1817 mode = convert_function_priv_string(priv_type_text);
1819 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1821 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1825 * has_function_privilege_id_id
1826 * Check user privileges on a function given
1827 * roleid, function oid, and text priv name.
1830 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1832 Oid roleid = PG_GETARG_OID(0);
1833 Oid functionoid = PG_GETARG_OID(1);
1834 text *priv_type_text = PG_GETARG_TEXT_P(2);
1836 AclResult aclresult;
1838 mode = convert_function_priv_string(priv_type_text);
1840 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1842 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1846 * Support routines for has_function_privilege family.
1850 * Given a function name expressed as a string, look it up and return Oid
1853 convert_function_name(text *functionname)
1858 funcname = DatumGetCString(DirectFunctionCall1(textout,
1859 PointerGetDatum(functionname)));
1861 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1862 CStringGetDatum(funcname)));
1864 if (!OidIsValid(oid))
1866 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1867 errmsg("function \"%s\" does not exist", funcname)));
1873 * convert_function_priv_string
1874 * Convert text string to AclMode value.
1877 convert_function_priv_string(text *priv_type_text)
1881 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1882 PointerGetDatum(priv_type_text)));
1885 * Return mode from priv_type string
1887 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1889 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1890 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1893 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1894 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1895 return ACL_NO_RIGHTS; /* keep compiler quiet */
1900 * has_language_privilege variants
1901 * These are all named "has_language_privilege" at the SQL level.
1902 * They take various combinations of language name, language OID,
1903 * user name, user OID, or implicit user = current_user.
1905 * The result is a boolean value: true if user has the indicated
1906 * privilege, false if not.
1910 * has_language_privilege_name_name
1911 * Check user privileges on a language given
1912 * name username, text languagename, and text priv name.
1915 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1917 Name username = PG_GETARG_NAME(0);
1918 text *languagename = PG_GETARG_TEXT_P(1);
1919 text *priv_type_text = PG_GETARG_TEXT_P(2);
1923 AclResult aclresult;
1925 roleid = get_roleid_checked(NameStr(*username));
1926 languageoid = convert_language_name(languagename);
1927 mode = convert_language_priv_string(priv_type_text);
1929 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1931 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1935 * has_language_privilege_name
1936 * Check user privileges on a language given
1937 * text languagename and text priv name.
1938 * current_user is assumed
1941 has_language_privilege_name(PG_FUNCTION_ARGS)
1943 text *languagename = PG_GETARG_TEXT_P(0);
1944 text *priv_type_text = PG_GETARG_TEXT_P(1);
1948 AclResult aclresult;
1950 roleid = GetUserId();
1951 languageoid = convert_language_name(languagename);
1952 mode = convert_language_priv_string(priv_type_text);
1954 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1956 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1960 * has_language_privilege_name_id
1961 * Check user privileges on a language given
1962 * name usename, language oid, and text priv name.
1965 has_language_privilege_name_id(PG_FUNCTION_ARGS)
1967 Name username = PG_GETARG_NAME(0);
1968 Oid languageoid = PG_GETARG_OID(1);
1969 text *priv_type_text = PG_GETARG_TEXT_P(2);
1972 AclResult aclresult;
1974 roleid = get_roleid_checked(NameStr(*username));
1975 mode = convert_language_priv_string(priv_type_text);
1977 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1979 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1983 * has_language_privilege_id
1984 * Check user privileges on a language given
1985 * language oid, and text priv name.
1986 * current_user is assumed
1989 has_language_privilege_id(PG_FUNCTION_ARGS)
1991 Oid languageoid = PG_GETARG_OID(0);
1992 text *priv_type_text = PG_GETARG_TEXT_P(1);
1995 AclResult aclresult;
1997 roleid = GetUserId();
1998 mode = convert_language_priv_string(priv_type_text);
2000 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2002 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2006 * has_language_privilege_id_name
2007 * Check user privileges on a language given
2008 * roleid, text languagename, and text priv name.
2011 has_language_privilege_id_name(PG_FUNCTION_ARGS)
2013 Oid roleid = PG_GETARG_OID(0);
2014 text *languagename = PG_GETARG_TEXT_P(1);
2015 text *priv_type_text = PG_GETARG_TEXT_P(2);
2018 AclResult aclresult;
2020 languageoid = convert_language_name(languagename);
2021 mode = convert_language_priv_string(priv_type_text);
2023 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2025 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2029 * has_language_privilege_id_id
2030 * Check user privileges on a language given
2031 * roleid, language oid, and text priv name.
2034 has_language_privilege_id_id(PG_FUNCTION_ARGS)
2036 Oid roleid = PG_GETARG_OID(0);
2037 Oid languageoid = PG_GETARG_OID(1);
2038 text *priv_type_text = PG_GETARG_TEXT_P(2);
2040 AclResult aclresult;
2042 mode = convert_language_priv_string(priv_type_text);
2044 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2046 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2050 * Support routines for has_language_privilege family.
2054 * Given a language name expressed as a string, look it up and return Oid
2057 convert_language_name(text *languagename)
2062 langname = DatumGetCString(DirectFunctionCall1(textout,
2063 PointerGetDatum(languagename)));
2065 oid = GetSysCacheOid(LANGNAME,
2066 CStringGetDatum(langname),
2068 if (!OidIsValid(oid))
2070 (errcode(ERRCODE_UNDEFINED_OBJECT),
2071 errmsg("language \"%s\" does not exist", langname)));
2077 * convert_language_priv_string
2078 * Convert text string to AclMode value.
2081 convert_language_priv_string(text *priv_type_text)
2085 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2086 PointerGetDatum(priv_type_text)));
2089 * Return mode from priv_type string
2091 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2093 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2094 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2097 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2098 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2099 return ACL_NO_RIGHTS; /* keep compiler quiet */
2104 * has_schema_privilege variants
2105 * These are all named "has_schema_privilege" at the SQL level.
2106 * They take various combinations of schema name, schema OID,
2107 * user name, user OID, or implicit user = current_user.
2109 * The result is a boolean value: true if user has the indicated
2110 * privilege, false if not.
2114 * has_schema_privilege_name_name
2115 * Check user privileges on a schema given
2116 * name username, text schemaname, and text priv name.
2119 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2121 Name username = PG_GETARG_NAME(0);
2122 text *schemaname = PG_GETARG_TEXT_P(1);
2123 text *priv_type_text = PG_GETARG_TEXT_P(2);
2127 AclResult aclresult;
2129 roleid = get_roleid_checked(NameStr(*username));
2130 schemaoid = convert_schema_name(schemaname);
2131 mode = convert_schema_priv_string(priv_type_text);
2133 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2135 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2139 * has_schema_privilege_name
2140 * Check user privileges on a schema given
2141 * text schemaname and text priv name.
2142 * current_user is assumed
2145 has_schema_privilege_name(PG_FUNCTION_ARGS)
2147 text *schemaname = PG_GETARG_TEXT_P(0);
2148 text *priv_type_text = PG_GETARG_TEXT_P(1);
2152 AclResult aclresult;
2154 roleid = GetUserId();
2155 schemaoid = convert_schema_name(schemaname);
2156 mode = convert_schema_priv_string(priv_type_text);
2158 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2160 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2164 * has_schema_privilege_name_id
2165 * Check user privileges on a schema given
2166 * name usename, schema oid, and text priv name.
2169 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2171 Name username = PG_GETARG_NAME(0);
2172 Oid schemaoid = PG_GETARG_OID(1);
2173 text *priv_type_text = PG_GETARG_TEXT_P(2);
2176 AclResult aclresult;
2178 roleid = get_roleid_checked(NameStr(*username));
2179 mode = convert_schema_priv_string(priv_type_text);
2181 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2183 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2187 * has_schema_privilege_id
2188 * Check user privileges on a schema given
2189 * schema oid, and text priv name.
2190 * current_user is assumed
2193 has_schema_privilege_id(PG_FUNCTION_ARGS)
2195 Oid schemaoid = PG_GETARG_OID(0);
2196 text *priv_type_text = PG_GETARG_TEXT_P(1);
2199 AclResult aclresult;
2201 roleid = GetUserId();
2202 mode = convert_schema_priv_string(priv_type_text);
2204 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2206 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2210 * has_schema_privilege_id_name
2211 * Check user privileges on a schema given
2212 * roleid, text schemaname, and text priv name.
2215 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2217 Oid roleid = PG_GETARG_OID(0);
2218 text *schemaname = PG_GETARG_TEXT_P(1);
2219 text *priv_type_text = PG_GETARG_TEXT_P(2);
2222 AclResult aclresult;
2224 schemaoid = convert_schema_name(schemaname);
2225 mode = convert_schema_priv_string(priv_type_text);
2227 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2229 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2233 * has_schema_privilege_id_id
2234 * Check user privileges on a schema given
2235 * roleid, schema oid, and text priv name.
2238 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2240 Oid roleid = PG_GETARG_OID(0);
2241 Oid schemaoid = PG_GETARG_OID(1);
2242 text *priv_type_text = PG_GETARG_TEXT_P(2);
2244 AclResult aclresult;
2246 mode = convert_schema_priv_string(priv_type_text);
2248 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2250 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2254 * Support routines for has_schema_privilege family.
2258 * Given a schema name expressed as a string, look it up and return Oid
2261 convert_schema_name(text *schemaname)
2266 nspname = DatumGetCString(DirectFunctionCall1(textout,
2267 PointerGetDatum(schemaname)));
2269 oid = GetSysCacheOid(NAMESPACENAME,
2270 CStringGetDatum(nspname),
2272 if (!OidIsValid(oid))
2274 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2275 errmsg("schema \"%s\" does not exist", nspname)));
2281 * convert_schema_priv_string
2282 * Convert text string to AclMode value.
2285 convert_schema_priv_string(text *priv_type_text)
2289 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2290 PointerGetDatum(priv_type_text)));
2293 * Return mode from priv_type string
2295 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2297 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2298 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2300 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2302 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2303 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2306 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2307 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2308 return ACL_NO_RIGHTS; /* keep compiler quiet */
2312 * has_tablespace_privilege variants
2313 * These are all named "has_tablespace_privilege" at the SQL level.
2314 * They take various combinations of tablespace name, tablespace OID,
2315 * user name, user OID, or implicit user = current_user.
2317 * The result is a boolean value: true if user has the indicated
2318 * privilege, false if not.
2322 * has_tablespace_privilege_name_name
2323 * Check user privileges on a tablespace given
2324 * name username, text tablespacename, and text priv name.
2327 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2329 Name username = PG_GETARG_NAME(0);
2330 text *tablespacename = PG_GETARG_TEXT_P(1);
2331 text *priv_type_text = PG_GETARG_TEXT_P(2);
2335 AclResult aclresult;
2337 roleid = get_roleid_checked(NameStr(*username));
2338 tablespaceoid = convert_tablespace_name(tablespacename);
2339 mode = convert_tablespace_priv_string(priv_type_text);
2341 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2343 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2347 * has_tablespace_privilege_name
2348 * Check user privileges on a tablespace given
2349 * text tablespacename and text priv name.
2350 * current_user is assumed
2353 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2355 text *tablespacename = PG_GETARG_TEXT_P(0);
2356 text *priv_type_text = PG_GETARG_TEXT_P(1);
2360 AclResult aclresult;
2362 roleid = GetUserId();
2363 tablespaceoid = convert_tablespace_name(tablespacename);
2364 mode = convert_tablespace_priv_string(priv_type_text);
2366 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2368 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2372 * has_tablespace_privilege_name_id
2373 * Check user privileges on a tablespace given
2374 * name usename, tablespace oid, and text priv name.
2377 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2379 Name username = PG_GETARG_NAME(0);
2380 Oid tablespaceoid = PG_GETARG_OID(1);
2381 text *priv_type_text = PG_GETARG_TEXT_P(2);
2384 AclResult aclresult;
2386 roleid = get_roleid_checked(NameStr(*username));
2387 mode = convert_tablespace_priv_string(priv_type_text);
2389 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2391 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2395 * has_tablespace_privilege_id
2396 * Check user privileges on a tablespace given
2397 * tablespace oid, and text priv name.
2398 * current_user is assumed
2401 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2403 Oid tablespaceoid = PG_GETARG_OID(0);
2404 text *priv_type_text = PG_GETARG_TEXT_P(1);
2407 AclResult aclresult;
2409 roleid = GetUserId();
2410 mode = convert_tablespace_priv_string(priv_type_text);
2412 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2414 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2418 * has_tablespace_privilege_id_name
2419 * Check user privileges on a tablespace given
2420 * roleid, text tablespacename, and text priv name.
2423 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2425 Oid roleid = PG_GETARG_OID(0);
2426 text *tablespacename = PG_GETARG_TEXT_P(1);
2427 text *priv_type_text = PG_GETARG_TEXT_P(2);
2430 AclResult aclresult;
2432 tablespaceoid = convert_tablespace_name(tablespacename);
2433 mode = convert_tablespace_priv_string(priv_type_text);
2435 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2437 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2441 * has_tablespace_privilege_id_id
2442 * Check user privileges on a tablespace given
2443 * roleid, tablespace oid, and text priv name.
2446 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2448 Oid roleid = PG_GETARG_OID(0);
2449 Oid tablespaceoid = PG_GETARG_OID(1);
2450 text *priv_type_text = PG_GETARG_TEXT_P(2);
2452 AclResult aclresult;
2454 mode = convert_tablespace_priv_string(priv_type_text);
2456 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2458 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2462 * Support routines for has_tablespace_privilege family.
2466 * Given a tablespace name expressed as a string, look it up and return Oid
2469 convert_tablespace_name(text *tablespacename)
2474 spcname = DatumGetCString(DirectFunctionCall1(textout,
2475 PointerGetDatum(tablespacename)));
2476 oid = get_tablespace_oid(spcname);
2478 if (!OidIsValid(oid))
2480 (errcode(ERRCODE_UNDEFINED_OBJECT),
2481 errmsg("tablespace \"%s\" does not exist", spcname)));
2487 * convert_tablespace_priv_string
2488 * Convert text string to AclMode value.
2491 convert_tablespace_priv_string(text *priv_type_text)
2495 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2496 PointerGetDatum(priv_type_text)));
2499 * Return mode from priv_type string
2501 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2503 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2504 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2507 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2508 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2509 return ACL_NO_RIGHTS; /* keep compiler quiet */
2513 * pg_has_role variants
2514 * These are all named "pg_has_role" at the SQL level.
2515 * They take various combinations of role name, role OID,
2516 * user name, user OID, or implicit user = current_user.
2518 * The result is a boolean value: true if user has the indicated
2519 * privilege, false if not.
2523 * pg_has_role_name_name
2524 * Check user privileges on a role given
2525 * name username, name rolename, and text priv name.
2528 pg_has_role_name_name(PG_FUNCTION_ARGS)
2530 Name username = PG_GETARG_NAME(0);
2531 Name rolename = PG_GETARG_NAME(1);
2532 text *priv_type_text = PG_GETARG_TEXT_P(2);
2536 AclResult aclresult;
2538 roleid = get_roleid_checked(NameStr(*username));
2539 roleoid = get_roleid_checked(NameStr(*rolename));
2540 mode = convert_role_priv_string(priv_type_text);
2542 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2544 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2549 * Check user privileges on a role given
2550 * name rolename and text priv name.
2551 * current_user is assumed
2554 pg_has_role_name(PG_FUNCTION_ARGS)
2556 Name rolename = PG_GETARG_NAME(0);
2557 text *priv_type_text = PG_GETARG_TEXT_P(1);
2561 AclResult aclresult;
2563 roleid = GetUserId();
2564 roleoid = get_roleid_checked(NameStr(*rolename));
2565 mode = convert_role_priv_string(priv_type_text);
2567 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2569 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2573 * pg_has_role_name_id
2574 * Check user privileges on a role given
2575 * name usename, role oid, and text priv name.
2578 pg_has_role_name_id(PG_FUNCTION_ARGS)
2580 Name username = PG_GETARG_NAME(0);
2581 Oid roleoid = PG_GETARG_OID(1);
2582 text *priv_type_text = PG_GETARG_TEXT_P(2);
2585 AclResult aclresult;
2587 roleid = get_roleid_checked(NameStr(*username));
2588 mode = convert_role_priv_string(priv_type_text);
2590 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2592 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2597 * Check user privileges on a role given
2598 * role oid, and text priv name.
2599 * current_user is assumed
2602 pg_has_role_id(PG_FUNCTION_ARGS)
2604 Oid roleoid = PG_GETARG_OID(0);
2605 text *priv_type_text = PG_GETARG_TEXT_P(1);
2608 AclResult aclresult;
2610 roleid = GetUserId();
2611 mode = convert_role_priv_string(priv_type_text);
2613 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2615 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2619 * pg_has_role_id_name
2620 * Check user privileges on a role given
2621 * roleid, name rolename, and text priv name.
2624 pg_has_role_id_name(PG_FUNCTION_ARGS)
2626 Oid roleid = PG_GETARG_OID(0);
2627 Name rolename = PG_GETARG_NAME(1);
2628 text *priv_type_text = PG_GETARG_TEXT_P(2);
2631 AclResult aclresult;
2633 roleoid = get_roleid_checked(NameStr(*rolename));
2634 mode = convert_role_priv_string(priv_type_text);
2636 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2638 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2643 * Check user privileges on a role given
2644 * roleid, role oid, and text priv name.
2647 pg_has_role_id_id(PG_FUNCTION_ARGS)
2649 Oid roleid = PG_GETARG_OID(0);
2650 Oid roleoid = PG_GETARG_OID(1);
2651 text *priv_type_text = PG_GETARG_TEXT_P(2);
2653 AclResult aclresult;
2655 mode = convert_role_priv_string(priv_type_text);
2657 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
2659 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2663 * Support routines for pg_has_role family.
2667 * convert_role_priv_string
2668 * Convert text string to AclMode value.
2670 * We use USAGE to denote whether the privileges of the role are accessible
2671 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
2672 * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
2673 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
2674 * is shared only with pg_role_aclcheck, below.
2677 convert_role_priv_string(text *priv_type_text)
2681 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2682 PointerGetDatum(priv_type_text)));
2685 * Return mode from priv_type string
2687 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2689 if (pg_strcasecmp(priv_type, "MEMBER") == 0)
2691 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0 ||
2692 pg_strcasecmp(priv_type, "USAGE WITH ADMIN OPTION") == 0 ||
2693 pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0 ||
2694 pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
2695 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2698 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2699 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2700 return ACL_NO_RIGHTS; /* keep compiler quiet */
2705 * Quick-and-dirty support for pg_has_role
2708 pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
2710 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
2712 if (is_admin_of_role(roleid, role_oid))
2715 if (mode & ACL_CREATE)
2717 if (is_member_of_role(roleid, role_oid))
2720 if (mode & ACL_USAGE)
2722 if (has_privs_of_role(roleid, role_oid))
2725 return ACLCHECK_NO_PRIV;
2730 * initialization function (called by InitPostgres)
2733 initialize_acl(void)
2735 if (!IsBootstrapProcessingMode())
2738 * In normal mode, set a callback on any syscache
2739 * invalidation of pg_auth_members rows
2741 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
2742 RoleMembershipCacheCallback,
2748 * RoleMembershipCacheCallback
2749 * Syscache inval callback function
2752 RoleMembershipCacheCallback(Datum arg, Oid relid)
2754 /* Force membership caches to be recomputed on next use */
2755 cached_privs_role = InvalidOid;
2756 cached_member_role = InvalidOid;
2760 /* Check if specified role has rolinherit set */
2762 has_rolinherit(Oid roleid)
2764 bool result = false;
2767 utup = SearchSysCache(AUTHOID,
2768 ObjectIdGetDatum(roleid),
2770 if (HeapTupleIsValid(utup))
2772 result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
2773 ReleaseSysCache(utup);
2780 * Does member have the privileges of role (directly or indirectly)?
2782 * This is defined not to recurse through roles that don't have rolinherit
2783 * set; for such roles, membership implies the ability to do SET ROLE, but
2784 * the privileges are not available until you've done so.
2786 * Since indirect membership testing is relatively expensive, we cache
2787 * a list of memberships.
2790 has_privs_of_role(Oid member, Oid role)
2794 List *new_cached_privs_roles;
2795 MemoryContext oldctx;
2797 /* Fast path for simple case */
2801 /* Superusers have every privilege, so are part of every role */
2802 if (superuser_arg(member))
2805 /* If cache is already valid, just use the list */
2806 if (OidIsValid(cached_privs_role) && cached_privs_role == member)
2807 return list_member_oid(cached_privs_roles, role);
2810 * Find all the roles that member is a member of,
2811 * including multi-level recursion. The role itself will always
2812 * be the first element of the resulting list.
2814 * Each element of the list is scanned to see if it adds any indirect
2815 * memberships. We can use a single list as both the record of
2816 * already-found memberships and the agenda of roles yet to be scanned.
2817 * This is a bit tricky but works because the foreach() macro doesn't
2818 * fetch the next list element until the bottom of the loop.
2820 roles_list = list_make1_oid(member);
2822 foreach(l, roles_list)
2824 Oid memberid = lfirst_oid(l);
2828 /* Ignore non-inheriting roles */
2829 if (!has_rolinherit(memberid))
2832 /* Find roles that memberid is directly a member of */
2833 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
2834 ObjectIdGetDatum(memberid),
2836 for (i = 0; i < memlist->n_members; i++)
2838 HeapTuple tup = &memlist->members[i]->tuple;
2839 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
2842 * Even though there shouldn't be any loops in the membership
2843 * graph, we must test for having already seen this role.
2844 * It is legal for instance to have both A->B and A->C->B.
2846 if (!list_member_oid(roles_list, otherid))
2847 roles_list = lappend_oid(roles_list, otherid);
2849 ReleaseSysCacheList(memlist);
2853 * Copy the completed list into TopMemoryContext so it will persist.
2855 oldctx = MemoryContextSwitchTo(TopMemoryContext);
2856 new_cached_privs_roles = list_copy(roles_list);
2857 MemoryContextSwitchTo(oldctx);
2858 list_free(roles_list);
2861 * Now safe to assign to state variable
2863 cached_privs_role = InvalidOid; /* just paranoia */
2864 list_free(cached_privs_roles);
2865 cached_privs_roles = new_cached_privs_roles;
2866 cached_privs_role = member;
2868 /* And now we can return the answer */
2869 return list_member_oid(cached_privs_roles, role);
2874 * Is member a member of role (directly or indirectly)?
2876 * This is defined to recurse through roles regardless of rolinherit.
2878 * Since indirect membership testing is relatively expensive, we cache
2879 * a list of memberships.
2882 is_member_of_role(Oid member, Oid role)
2886 List *new_cached_membership_roles;
2887 MemoryContext oldctx;
2889 /* Fast path for simple case */
2893 /* Superusers have every privilege, so are part of every role */
2894 if (superuser_arg(member))
2897 /* If cache is already valid, just use the list */
2898 if (OidIsValid(cached_member_role) && cached_member_role == member)
2899 return list_member_oid(cached_membership_roles, role);
2902 * Find all the roles that member is a member of,
2903 * including multi-level recursion. The role itself will always
2904 * be the first element of the resulting list.
2906 * Each element of the list is scanned to see if it adds any indirect
2907 * memberships. We can use a single list as both the record of
2908 * already-found memberships and the agenda of roles yet to be scanned.
2909 * This is a bit tricky but works because the foreach() macro doesn't
2910 * fetch the next list element until the bottom of the loop.
2912 roles_list = list_make1_oid(member);
2914 foreach(l, roles_list)
2916 Oid memberid = lfirst_oid(l);
2920 /* Find roles that memberid is directly a member of */
2921 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
2922 ObjectIdGetDatum(memberid),
2924 for (i = 0; i < memlist->n_members; i++)
2926 HeapTuple tup = &memlist->members[i]->tuple;
2927 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
2930 * Even though there shouldn't be any loops in the membership
2931 * graph, we must test for having already seen this role.
2932 * It is legal for instance to have both A->B and A->C->B.
2934 if (!list_member_oid(roles_list, otherid))
2935 roles_list = lappend_oid(roles_list, otherid);
2937 ReleaseSysCacheList(memlist);
2941 * Copy the completed list into TopMemoryContext so it will persist.
2943 oldctx = MemoryContextSwitchTo(TopMemoryContext);
2944 new_cached_membership_roles = list_copy(roles_list);
2945 MemoryContextSwitchTo(oldctx);
2946 list_free(roles_list);
2949 * Now safe to assign to state variable
2951 cached_member_role = InvalidOid; /* just paranoia */
2952 list_free(cached_membership_roles);
2953 cached_membership_roles = new_cached_membership_roles;
2954 cached_member_role = member;
2956 /* And now we can return the answer */
2957 return list_member_oid(cached_membership_roles, role);
2961 * check_is_member_of_role
2962 * is_member_of_role with a standard permission-violation error if not
2965 check_is_member_of_role(Oid member, Oid role)
2967 if (!is_member_of_role(member, role))
2969 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2970 errmsg("must be member of role \"%s\"",
2971 GetUserNameFromId(role))));
2976 * Is member an admin of role (directly or indirectly)? That is, is it
2977 * a member WITH ADMIN OPTION?
2979 * We could cache the result as for is_member_of_role, but currently this
2980 * is not used in any performance-critical paths, so we don't.
2983 is_admin_of_role(Oid member, Oid role)
2985 bool result = false;
2989 /* Fast path for simple case */
2993 /* Superusers have every privilege, so are part of every role */
2994 if (superuser_arg(member))
2998 * Find all the roles that member is a member of,
2999 * including multi-level recursion. We build a list in the same way
3000 * that is_member_of_role does to track visited and unvisited roles.
3002 roles_list = list_make1_oid(member);
3004 foreach(l, roles_list)
3006 Oid memberid = lfirst_oid(l);
3010 /* Find roles that memberid is directly a member of */
3011 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
3012 ObjectIdGetDatum(memberid),
3014 for (i = 0; i < memlist->n_members; i++)
3016 HeapTuple tup = &memlist->members[i]->tuple;
3017 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
3019 if (otherid == role &&
3020 ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
3022 /* Found what we came for, so can stop searching */
3027 if (!list_member_oid(roles_list, otherid))
3028 roles_list = lappend_oid(roles_list, otherid);
3030 ReleaseSysCacheList(memlist);
3035 list_free(roles_list);