1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2009, 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.147 2009/02/06 21:15:11 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 "foreign/foreign.h"
26 #include "miscadmin.h"
27 #include "utils/acl.h"
28 #include "utils/builtins.h"
29 #include "utils/inval.h"
30 #include "utils/lsyscache.h"
31 #include "utils/memutils.h"
32 #include "utils/syscache.h"
42 * We frequently need to test whether a given role is a member of some other
43 * role. In most of these tests the "given role" is the same, namely the
44 * active current user. So we can optimize it by keeping a cached list of
45 * all the roles the "given role" is a member of, directly or indirectly.
46 * The cache is flushed whenever we detect a change in pg_auth_members.
48 * There are actually two caches, one computed under "has_privs" rules
49 * (do not recurse where rolinherit isn't true) and one computed under
50 * "is_member" rules (recurse regardless of rolinherit).
52 * Possibly this mechanism should be generalized to allow caching membership
53 * info for multiple roles?
55 * The has_privs cache is:
56 * cached_privs_role is the role OID the cache is for.
57 * cached_privs_roles is an OID list of roles that cached_privs_role
58 * has the privileges of (always including itself).
59 * The cache is valid if cached_privs_role is not InvalidOid.
61 * The is_member cache is similarly:
62 * cached_member_role is the role OID the cache is for.
63 * cached_membership_roles is an OID list of roles that cached_member_role
64 * is a member of (always including itself).
65 * The cache is valid if cached_member_role is not InvalidOid.
67 static Oid cached_privs_role = InvalidOid;
68 static List *cached_privs_roles = NIL;
69 static Oid cached_member_role = InvalidOid;
70 static List *cached_membership_roles = NIL;
73 static const char *getid(const char *s, char *n);
74 static void putid(char *p, const char *s);
75 static Acl *allocacl(int n);
76 static void check_acl(const Acl *acl);
77 static const char *aclparse(const char *s, AclItem *aip);
78 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
79 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
81 static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
82 Oid ownerId, DropBehavior behavior);
83 static int oidComparator(const void *arg1, const void *arg2);
85 static AclMode convert_priv_string(text *priv_type_text);
86 static AclMode convert_any_priv_string(text *priv_type_text,
87 const priv_map *privileges);
89 static Oid convert_table_name(text *tablename);
90 static AclMode convert_table_priv_string(text *priv_type_text);
91 static AttrNumber convert_column_name(Oid tableoid, text *column);
92 static AclMode convert_column_priv_string(text *priv_type_text);
93 static Oid convert_database_name(text *databasename);
94 static AclMode convert_database_priv_string(text *priv_type_text);
95 static Oid convert_foreign_data_wrapper_name(text *fdwname);
96 static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text);
97 static Oid convert_function_name(text *functionname);
98 static AclMode convert_function_priv_string(text *priv_type_text);
99 static Oid convert_language_name(text *languagename);
100 static AclMode convert_language_priv_string(text *priv_type_text);
101 static Oid convert_schema_name(text *schemaname);
102 static AclMode convert_schema_priv_string(text *priv_type_text);
103 static Oid convert_server_name(text *servername);
104 static AclMode convert_server_priv_string(text *priv_type_text);
105 static Oid convert_tablespace_name(text *tablespacename);
106 static AclMode convert_tablespace_priv_string(text *priv_type_text);
107 static AclMode convert_role_priv_string(text *priv_type_text);
108 static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
110 static void RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
115 * Consumes the first alphanumeric string (identifier) found in string
116 * 's', ignoring any leading white space. If it finds a double quote
117 * it returns the word inside the quotes.
120 * the string position in 's' that points to the next non-space character
121 * in 's', after any quotes. Also:
122 * - loads the identifier into 'n'. (If no identifier is found, 'n'
123 * contains an empty string.) 'n' must be NAMEDATALEN bytes.
126 getid(const char *s, char *n)
129 bool in_quotes = false;
133 while (isspace((unsigned char) *s))
135 /* This code had better match what putid() does, below */
138 (isalnum((unsigned char) *s) ||
146 /* safe to look at next char (could be '\0' though) */
149 in_quotes = !in_quotes;
152 /* it's an escaped double quote; skip the escaping char */
156 /* Add the character to the string */
157 if (len >= NAMEDATALEN - 1)
159 (errcode(ERRCODE_NAME_TOO_LONG),
160 errmsg("identifier too long"),
161 errdetail("Identifier must be less than %d characters.",
167 while (isspace((unsigned char) *s))
173 * Write a role name at *p, adding double quotes if needed.
174 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
175 * This needs to be kept in sync with copyAclUserName in pg_dump/dumputils.c
178 putid(char *p, const char *s)
183 for (src = s; *src; src++)
185 /* This test had better match what getid() does, above */
186 if (!isalnum((unsigned char) *src) && *src != '_')
194 for (src = s; *src; src++)
196 /* A double quote character in a username is encoded as "" */
208 * Consumes and parses an ACL specification of the form:
209 * [group|user] [A-Za-z0-9]*=[rwaR]*
210 * from string 's', ignoring any leading white space or white space
211 * between the optional id type keyword (group|user) and the actual
214 * The group|user decoration is unnecessary in the roles world,
215 * but we still accept it for backward compatibility.
217 * This routine is called by the parser as well as aclitemin(), hence
218 * the added generality.
221 * the string position in 's' immediately following the ACL
222 * specification. Also:
223 * - loads the structure pointed to by 'aip' with the appropriate
224 * UID/GID, id type identifier and mode type values.
227 aclparse(const char *s, AclItem *aip)
232 char name[NAMEDATALEN];
233 char name2[NAMEDATALEN];
238 elog(LOG, "aclparse: input = \"%s\"", s);
243 /* we just read a keyword, not a name */
244 if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
246 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
247 errmsg("unrecognized key word: \"%s\"", name),
248 errhint("ACL key word must be \"group\" or \"user\".")));
249 s = getid(s, name); /* move s to the name beyond the keyword */
252 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
253 errmsg("missing name"),
254 errhint("A name must follow the \"group\" or \"user\" key word.")));
259 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
260 errmsg("missing \"=\" sign")));
262 privs = goption = ACL_NO_RIGHTS;
264 for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
283 case ACL_TRUNCATE_CHR:
286 case ACL_REFERENCES_CHR:
287 read = ACL_REFERENCES;
289 case ACL_TRIGGER_CHR:
292 case ACL_EXECUTE_CHR:
301 case ACL_CREATE_TEMP_CHR:
302 read = ACL_CREATE_TEMP;
304 case ACL_CONNECT_CHR:
307 case 'R': /* ignore old RULE privileges */
312 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
313 errmsg("invalid mode character: must be one of \"%s\"",
314 ACL_ALL_RIGHTS_STR)));
321 aip->ai_grantee = ACL_ID_PUBLIC;
323 aip->ai_grantee = get_roleid_checked(name);
326 * XXX Allow a degree of backward compatibility by defaulting the grantor
331 s = getid(s + 1, name2);
332 if (name2[0] == '\0')
334 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
335 errmsg("a name must follow the \"/\" sign")));
336 aip->ai_grantor = get_roleid_checked(name2);
340 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
342 (errcode(ERRCODE_INVALID_GRANTOR),
343 errmsg("defaulting grantor to user ID %u",
344 BOOTSTRAP_SUPERUSERID)));
347 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
350 elog(LOG, "aclparse: correctly read [%u %x %x]",
351 aip->ai_grantee, privs, goption);
359 * Allocates storage for a new Acl with 'n' entries.
371 elog(ERROR, "invalid size: %d", n);
372 size = ACL_N_SIZE(n);
373 new_acl = (Acl *) palloc0(size);
374 SET_VARSIZE(new_acl, size);
376 new_acl->dataoffset = 0; /* we never put in any nulls */
377 new_acl->elemtype = ACLITEMOID;
378 ARR_LBOUND(new_acl)[0] = 1;
379 ARR_DIMS(new_acl)[0] = n;
387 aclcopy(const Acl *orig_acl)
391 result_acl = allocacl(ACL_NUM(orig_acl));
393 memcpy(ACL_DAT(result_acl),
395 ACL_NUM(orig_acl) * sizeof(AclItem));
401 * Concatenate two ACLs
403 * This is a bit cheesy, since we may produce an ACL with redundant entries.
404 * Be careful what the result is used for!
407 aclconcat(const Acl *left_acl, const Acl *right_acl)
411 result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
413 memcpy(ACL_DAT(result_acl),
415 ACL_NUM(left_acl) * sizeof(AclItem));
417 memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
419 ACL_NUM(right_acl) * sizeof(AclItem));
425 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
428 check_acl(const Acl *acl)
430 if (ARR_ELEMTYPE(acl) != ACLITEMOID)
432 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
433 errmsg("ACL array contains wrong data type")));
434 if (ARR_NDIM(acl) != 1)
436 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
437 errmsg("ACL arrays must be one-dimensional")));
438 if (ARR_HASNULL(acl))
440 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
441 errmsg("ACL arrays must not contain null values")));
446 * Allocates storage for, and fills in, a new AclItem given a string
447 * 's' that contains an ACL specification. See aclparse for details.
453 aclitemin(PG_FUNCTION_ARGS)
455 const char *s = PG_GETARG_CSTRING(0);
458 aip = (AclItem *) palloc(sizeof(AclItem));
459 s = aclparse(s, aip);
460 while (isspace((unsigned char) *s))
464 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
465 errmsg("extra garbage at the end of the ACL specification")));
467 PG_RETURN_ACLITEM_P(aip);
472 * Allocates storage for, and fills in, a new null-delimited string
473 * containing a formatted ACL specification. See aclparse for details.
479 aclitemout(PG_FUNCTION_ARGS)
481 AclItem *aip = PG_GETARG_ACLITEM_P(0);
487 out = palloc(strlen("=/") +
489 2 * (2 * NAMEDATALEN + 2) +
495 if (aip->ai_grantee != ACL_ID_PUBLIC)
497 htup = SearchSysCache(AUTHOID,
498 ObjectIdGetDatum(aip->ai_grantee),
500 if (HeapTupleIsValid(htup))
502 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
503 ReleaseSysCache(htup);
507 /* Generate numeric OID if we don't find an entry */
508 sprintf(p, "%u", aip->ai_grantee);
516 for (i = 0; i < N_ACL_RIGHTS; ++i)
518 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
519 *p++ = ACL_ALL_RIGHTS_STR[i];
520 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
527 htup = SearchSysCache(AUTHOID,
528 ObjectIdGetDatum(aip->ai_grantor),
530 if (HeapTupleIsValid(htup))
532 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
533 ReleaseSysCache(htup);
537 /* Generate numeric OID if we don't find an entry */
538 sprintf(p, "%u", aip->ai_grantor);
541 PG_RETURN_CSTRING(out);
546 * Two AclItems are considered to match iff they have the same
547 * grantee and grantor; the privileges are ignored.
550 aclitem_match(const AclItem *a1, const AclItem *a2)
552 return a1->ai_grantee == a2->ai_grantee &&
553 a1->ai_grantor == a2->ai_grantor;
557 * aclitem equality operator
560 aclitem_eq(PG_FUNCTION_ARGS)
562 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
563 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
566 result = a1->ai_privs == a2->ai_privs &&
567 a1->ai_grantee == a2->ai_grantee &&
568 a1->ai_grantor == a2->ai_grantor;
569 PG_RETURN_BOOL(result);
573 * aclitem hash function
575 * We make aclitems hashable not so much because anyone is likely to hash
576 * them, as because we want array equality to work on aclitem arrays, and
577 * with the typcache mechanism we must have a hash or btree opclass.
580 hash_aclitem(PG_FUNCTION_ARGS)
582 AclItem *a = PG_GETARG_ACLITEM_P(0);
584 /* not very bright, but avoids any issue of padding in struct */
585 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
590 * acldefault() --- create an ACL describing default access permissions
592 * Change this routine if you want to alter the default access policy for
593 * newly-created objects (or any object with a NULL acl entry).
596 acldefault(GrantObjectType objtype, Oid ownerId)
598 AclMode world_default;
599 AclMode owner_default;
606 case ACL_OBJECT_COLUMN:
607 /* by default, columns have no extra privileges */
608 world_default = ACL_NO_RIGHTS;
609 owner_default = ACL_NO_RIGHTS;
611 case ACL_OBJECT_RELATION:
612 world_default = ACL_NO_RIGHTS;
613 owner_default = ACL_ALL_RIGHTS_RELATION;
615 case ACL_OBJECT_SEQUENCE:
616 world_default = ACL_NO_RIGHTS;
617 owner_default = ACL_ALL_RIGHTS_SEQUENCE;
619 case ACL_OBJECT_DATABASE:
620 /* for backwards compatibility, grant some rights by default */
621 world_default = ACL_CREATE_TEMP | ACL_CONNECT;
622 owner_default = ACL_ALL_RIGHTS_DATABASE;
624 case ACL_OBJECT_FUNCTION:
625 /* Grant EXECUTE by default, for now */
626 world_default = ACL_EXECUTE;
627 owner_default = ACL_ALL_RIGHTS_FUNCTION;
629 case ACL_OBJECT_LANGUAGE:
630 /* Grant USAGE by default, for now */
631 world_default = ACL_USAGE;
632 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
634 case ACL_OBJECT_NAMESPACE:
635 world_default = ACL_NO_RIGHTS;
636 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
638 case ACL_OBJECT_TABLESPACE:
639 world_default = ACL_NO_RIGHTS;
640 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
643 world_default = ACL_NO_RIGHTS;
644 owner_default = ACL_ALL_RIGHTS_FDW;
646 case ACL_OBJECT_FOREIGN_SERVER:
647 world_default = ACL_NO_RIGHTS;
648 owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
651 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
652 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
653 owner_default = ACL_NO_RIGHTS;
658 if (world_default != ACL_NO_RIGHTS)
660 if (owner_default != ACL_NO_RIGHTS)
663 acl = allocacl(nacl);
666 if (world_default != ACL_NO_RIGHTS)
668 aip->ai_grantee = ACL_ID_PUBLIC;
669 aip->ai_grantor = ownerId;
670 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
675 * Note that the owner's entry shows all ordinary privileges but no grant
676 * options. This is because his grant options come "from the system" and
677 * not from his own efforts. (The SQL spec says that the owner's rights
678 * come from a "_SYSTEM" authid.) However, we do consider that the
679 * owner's ordinary privileges are self-granted; this lets him revoke
680 * them. We implement the owner's grant options without any explicit
681 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
682 * whereever we are testing grant options.
684 if (owner_default != ACL_NO_RIGHTS)
686 aip->ai_grantee = ownerId;
687 aip->ai_grantor = ownerId;
688 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
696 * Update an ACL array to add or remove specified privileges.
698 * old_acl: the input ACL array
699 * mod_aip: defines the privileges to be added, removed, or substituted
700 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
701 * ownerId: Oid of object owner
702 * behavior: RESTRICT or CASCADE behavior for recursive removal
704 * ownerid and behavior are only relevant when the update operation specifies
705 * deletion of grant options.
707 * The result is a modified copy; the input object is not changed.
709 * NB: caller is responsible for having detoasted the input ACL, if needed.
712 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
713 int modechg, Oid ownerId, DropBehavior behavior)
725 /* Caller probably already checked old_acl, but be safe */
728 /* If granting grant options, check for circularity */
729 if (modechg != ACL_MODECHG_DEL &&
730 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
731 check_circularity(old_acl, mod_aip, ownerId);
733 num = ACL_NUM(old_acl);
734 old_aip = ACL_DAT(old_acl);
737 * Search the ACL for an existing entry for this grantee and grantor. If
738 * one exists, just modify the entry in-place (well, in the same position,
739 * since we actually return a copy); otherwise, insert the new entry at
743 for (dst = 0; dst < num; ++dst)
745 if (aclitem_match(mod_aip, old_aip + dst))
747 /* found a match, so modify existing item */
748 new_acl = allocacl(num);
749 new_aip = ACL_DAT(new_acl);
750 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
757 /* need to append a new item */
758 new_acl = allocacl(num + 1);
759 new_aip = ACL_DAT(new_acl);
760 memcpy(new_aip, old_aip, num * sizeof(AclItem));
762 /* initialize the new entry with no permissions */
763 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
764 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
765 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
766 ACL_NO_RIGHTS, ACL_NO_RIGHTS);
767 num++; /* set num to the size of new_acl */
770 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
771 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
773 /* apply the specified permissions change */
776 case ACL_MODECHG_ADD:
777 ACLITEM_SET_RIGHTS(new_aip[dst],
778 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
780 case ACL_MODECHG_DEL:
781 ACLITEM_SET_RIGHTS(new_aip[dst],
782 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
784 case ACL_MODECHG_EQL:
785 ACLITEM_SET_RIGHTS(new_aip[dst],
786 ACLITEM_GET_RIGHTS(*mod_aip));
790 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
791 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
794 * If the adjusted entry has no permissions, delete it from the list.
796 if (new_rights == ACL_NO_RIGHTS)
798 memmove(new_aip + dst,
800 (num - dst - 1) * sizeof(AclItem));
801 /* Adjust array size to be 'num - 1' items */
802 ARR_DIMS(new_acl)[0] = num - 1;
803 SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
807 * Remove abandoned privileges (cascading revoke). Currently we can only
808 * handle this when the grantee is not PUBLIC.
810 if ((old_goptions & ~new_goptions) != 0)
812 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
813 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
814 (old_goptions & ~new_goptions),
822 * Update an ACL array to reflect a change of owner to the parent object
824 * old_acl: the input ACL array (must not be NULL)
825 * oldOwnerId: Oid of the old object owner
826 * newOwnerId: Oid of the new object owner
828 * The result is a modified copy; the input object is not changed.
830 * NB: caller is responsible for having detoasted the input ACL, if needed.
833 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
841 bool newpresent = false;
850 * Make a copy of the given ACL, substituting new owner ID for old
851 * wherever it appears as either grantor or grantee. Also note if the new
852 * owner ID is already present.
854 num = ACL_NUM(old_acl);
855 old_aip = ACL_DAT(old_acl);
856 new_acl = allocacl(num);
857 new_aip = ACL_DAT(new_acl);
858 memcpy(new_aip, old_aip, num * sizeof(AclItem));
859 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
861 if (dst_aip->ai_grantor == oldOwnerId)
862 dst_aip->ai_grantor = newOwnerId;
863 else if (dst_aip->ai_grantor == newOwnerId)
865 if (dst_aip->ai_grantee == oldOwnerId)
866 dst_aip->ai_grantee = newOwnerId;
867 else if (dst_aip->ai_grantee == newOwnerId)
872 * If the old ACL contained any references to the new owner, then we may
873 * now have generated an ACL containing duplicate entries. Find them and
874 * merge them so that there are not duplicates. (This is relatively
875 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
876 * be the normal case.)
878 * To simplify deletion of duplicate entries, we temporarily leave them in
879 * the array but set their privilege masks to zero; when we reach such an
880 * entry it's just skipped. (Thus, a side effect of this code will be to
881 * remove privilege-free entries, should there be any in the input.) dst
882 * is the next output slot, targ is the currently considered input slot
883 * (always >= dst), and src scans entries to the right of targ looking for
884 * duplicates. Once an entry has been emitted to dst it is known
885 * duplicate-free and need not be considered anymore.
890 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
892 /* ignore if deleted in an earlier pass */
893 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
895 /* find and merge any duplicates */
896 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
899 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
901 if (aclitem_match(targ_aip, src_aip))
903 ACLITEM_SET_RIGHTS(*targ_aip,
904 ACLITEM_GET_RIGHTS(*targ_aip) |
905 ACLITEM_GET_RIGHTS(*src_aip));
906 /* mark the duplicate deleted */
907 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
910 /* and emit to output */
911 new_aip[dst] = *targ_aip;
914 /* Adjust array size to be 'dst' items */
915 ARR_DIMS(new_acl)[0] = dst;
916 SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
924 * When granting grant options, we must disallow attempts to set up circular
925 * chains of grant options. Suppose A (the object owner) grants B some
926 * privileges with grant option, and B re-grants them to C. If C could
927 * grant the privileges to B as well, then A would be unable to effectively
928 * revoke the privileges from B, since recursive_revoke would consider that
929 * B still has 'em from C.
931 * We check for this by recursively deleting all grant options belonging to
932 * the target grantee, and then seeing if the would-be grantor still has the
933 * grant option or not.
936 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
948 * For now, grant options can only be granted to roles, not PUBLIC.
949 * Otherwise we'd have to work a bit harder here.
951 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
953 /* The owner always has grant options, no need to check */
954 if (mod_aip->ai_grantor == ownerId)
957 /* Make a working copy */
958 acl = allocacl(ACL_NUM(old_acl));
959 memcpy(acl, old_acl, ACL_SIZE(old_acl));
961 /* Zap all grant options of target grantee, plus what depends on 'em */
965 for (i = 0; i < num; i++)
967 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
968 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
972 /* We'll actually zap ordinary privs too, but no matter */
973 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
974 ownerId, DROP_CASCADE);
983 /* Now we can compute grantor's independently-derived privileges */
984 own_privs = aclmask(acl,
987 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
989 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
991 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
993 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
994 errmsg("grant options cannot be granted back to your own grantor")));
1001 * Ensure that no privilege is "abandoned". A privilege is abandoned
1002 * if the user that granted the privilege loses the grant option. (So
1003 * the chain through which it was granted is broken.) Either the
1004 * abandoned privileges are revoked as well, or an error message is
1005 * printed, depending on the drop behavior option.
1007 * acl: the input ACL list
1008 * grantee: the user from whom some grant options have been revoked
1009 * revoke_privs: the grant options being revoked
1010 * ownerId: Oid of object owner
1011 * behavior: RESTRICT or CASCADE behavior for recursive removal
1013 * The input Acl object is pfree'd if replaced.
1016 recursive_revoke(Acl *acl,
1018 AclMode revoke_privs,
1020 DropBehavior behavior)
1029 /* The owner can never truly lose grant options, so short-circuit */
1030 if (grantee == ownerId)
1033 /* The grantee might still have the privileges via another grantor */
1034 still_has = aclmask(acl, grantee, ownerId,
1035 ACL_GRANT_OPTION_FOR(revoke_privs),
1037 revoke_privs &= ~still_has;
1038 if (revoke_privs == ACL_NO_RIGHTS)
1044 for (i = 0; i < num; i++)
1046 if (aip[i].ai_grantor == grantee
1047 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1052 if (behavior == DROP_RESTRICT)
1054 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1055 errmsg("dependent privileges exist"),
1056 errhint("Use CASCADE to revoke them too.")));
1058 mod_acl.ai_grantor = grantee;
1059 mod_acl.ai_grantee = aip[i].ai_grantee;
1060 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
1064 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1079 * aclmask --- compute bitmask of all privileges held by roleid.
1081 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1082 * held by the given roleid according to the given ACL list, ANDed
1083 * with 'mask'. (The point of passing 'mask' is to let the routine
1084 * exit early if all privileges of interest have been found.)
1086 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1087 * is known true. (This lets us exit soonest in cases where the
1088 * caller is only going to test for zero or nonzero result.)
1092 * To see if any of a set of privileges are held:
1093 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1095 * To see if all of a set of privileges are held:
1096 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1098 * To determine exactly which of a set of privileges are held:
1099 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1102 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1103 AclMode mask, AclMaskHow how)
1112 * Null ACL should not happen, since caller should have inserted
1113 * appropriate default
1116 elog(ERROR, "null ACL");
1120 /* Quick exit for mask == 0 */
1126 /* Owner always implicitly has all grant options */
1127 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1128 has_privs_of_role(roleid, ownerId))
1130 result = mask & ACLITEM_ALL_GOPTION_BITS;
1131 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1136 aidat = ACL_DAT(acl);
1139 * Check privileges granted directly to roleid or to public
1141 for (i = 0; i < num; i++)
1143 AclItem *aidata = &aidat[i];
1145 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1146 aidata->ai_grantee == roleid)
1148 result |= aidata->ai_privs & mask;
1149 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1155 * Check privileges granted indirectly via role memberships. We do this in
1156 * a separate pass to minimize expensive indirect membership tests. In
1157 * particular, it's worth testing whether a given ACL entry grants any
1158 * privileges still of interest before we perform the has_privs_of_role
1161 remaining = mask & ~result;
1162 for (i = 0; i < num; i++)
1164 AclItem *aidata = &aidat[i];
1166 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1167 aidata->ai_grantee == roleid)
1168 continue; /* already checked it */
1170 if ((aidata->ai_privs & remaining) &&
1171 has_privs_of_role(roleid, aidata->ai_grantee))
1173 result |= aidata->ai_privs & mask;
1174 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1176 remaining = mask & ~result;
1185 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1187 * This is exactly like aclmask() except that we consider only privileges
1188 * held *directly* by roleid, not those inherited via role membership.
1191 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1192 AclMode mask, AclMaskHow how)
1200 * Null ACL should not happen, since caller should have inserted
1201 * appropriate default
1204 elog(ERROR, "null ACL");
1208 /* Quick exit for mask == 0 */
1214 /* Owner always implicitly has all grant options */
1215 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1218 result = mask & ACLITEM_ALL_GOPTION_BITS;
1219 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1224 aidat = ACL_DAT(acl);
1227 * Check privileges granted directly to roleid (and not to public)
1229 for (i = 0; i < num; i++)
1231 AclItem *aidata = &aidat[i];
1233 if (aidata->ai_grantee == roleid)
1235 result |= aidata->ai_privs & mask;
1236 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1247 * Find out all the roleids mentioned in an Acl.
1248 * Note that we do not distinguish grantors from grantees.
1250 * *roleids is set to point to a palloc'd array containing distinct OIDs
1251 * in sorted order. The length of the array is the function result.
1254 aclmembers(const Acl *acl, Oid **roleids)
1257 const AclItem *acldat;
1262 if (acl == NULL || ACL_NUM(acl) == 0)
1270 /* Allocate the worst-case space requirement */
1271 list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1272 acldat = ACL_DAT(acl);
1275 * Walk the ACL collecting mentioned RoleIds.
1278 for (i = 0; i < ACL_NUM(acl); i++)
1280 const AclItem *ai = &acldat[i];
1282 if (ai->ai_grantee != ACL_ID_PUBLIC)
1283 list[j++] = ai->ai_grantee;
1284 /* grantor is currently never PUBLIC, but let's check anyway */
1285 if (ai->ai_grantor != ACL_ID_PUBLIC)
1286 list[j++] = ai->ai_grantor;
1289 /* Sort the array */
1290 qsort(list, j, sizeof(Oid), oidComparator);
1292 /* Remove duplicates from the array */
1294 for (i = 1; i < j; i++)
1296 if (list[k] != list[i])
1297 list[++k] = list[i];
1301 * We could repalloc the array down to minimum size, but it's hardly worth
1302 * it since it's only transient memory.
1311 * qsort comparison function for Oids
1314 oidComparator(const void *arg1, const void *arg2)
1316 Oid oid1 = *(const Oid *) arg1;
1317 Oid oid2 = *(const Oid *) arg2;
1328 * aclinsert (exported function)
1331 aclinsert(PG_FUNCTION_ARGS)
1334 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1335 errmsg("aclinsert is no longer supported")));
1337 PG_RETURN_NULL(); /* keep compiler quiet */
1341 aclremove(PG_FUNCTION_ARGS)
1344 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1345 errmsg("aclremove is no longer supported")));
1347 PG_RETURN_NULL(); /* keep compiler quiet */
1351 aclcontains(PG_FUNCTION_ARGS)
1353 Acl *acl = PG_GETARG_ACL_P(0);
1354 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1361 aidat = ACL_DAT(acl);
1362 for (i = 0; i < num; ++i)
1364 if (aip->ai_grantee == aidat[i].ai_grantee &&
1365 aip->ai_grantor == aidat[i].ai_grantor &&
1366 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1367 PG_RETURN_BOOL(true);
1369 PG_RETURN_BOOL(false);
1373 makeaclitem(PG_FUNCTION_ARGS)
1375 Oid grantee = PG_GETARG_OID(0);
1376 Oid grantor = PG_GETARG_OID(1);
1377 text *privtext = PG_GETARG_TEXT_P(2);
1378 bool goption = PG_GETARG_BOOL(3);
1382 priv = convert_priv_string(privtext);
1384 result = (AclItem *) palloc(sizeof(AclItem));
1386 result->ai_grantee = grantee;
1387 result->ai_grantor = grantor;
1389 ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1390 (goption ? priv : ACL_NO_RIGHTS));
1392 PG_RETURN_ACLITEM_P(result);
1396 convert_priv_string(text *priv_type_text)
1398 char *priv_type = text_to_cstring(priv_type_text);
1400 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1402 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1404 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1406 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1408 if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
1409 return ACL_TRUNCATE;
1410 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1411 return ACL_REFERENCES;
1412 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1414 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1416 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1418 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1420 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1421 return ACL_CREATE_TEMP;
1422 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1423 return ACL_CREATE_TEMP;
1424 if (pg_strcasecmp(priv_type, "CONNECT") == 0)
1426 if (pg_strcasecmp(priv_type, "RULE") == 0)
1427 return 0; /* ignore old RULE privileges */
1430 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1431 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1432 return ACL_NO_RIGHTS; /* keep compiler quiet */
1437 * convert_any_priv_string: recognize privilege strings for has_foo_privilege
1439 * We accept a comma-separated list of case-insensitive privilege names,
1440 * producing a bitmask of the OR'd privilege bits. We are liberal about
1441 * whitespace between items, not so much about whitespace within items.
1442 * The allowed privilege names are given as an array of priv_map structs,
1443 * terminated by one with a NULL name pointer.
1446 convert_any_priv_string(text *priv_type_text,
1447 const priv_map *privileges)
1450 char *priv_type = text_to_cstring(priv_type_text);
1454 /* We rely on priv_type being a private, modifiable string */
1455 for (chunk = priv_type; chunk; chunk = next_chunk)
1458 const priv_map *this_priv;
1460 /* Split string at commas */
1461 next_chunk = strchr(chunk, ',');
1463 *next_chunk++ = '\0';
1465 /* Drop leading/trailing whitespace in this chunk */
1466 while (*chunk && isspace((unsigned char) *chunk))
1468 chunk_len = strlen(chunk);
1469 while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
1471 chunk[chunk_len] = '\0';
1473 /* Match to the privileges list */
1474 for (this_priv = privileges; this_priv->name; this_priv++)
1476 if (pg_strcasecmp(this_priv->name, chunk) == 0)
1478 result |= this_priv->value;
1482 if (!this_priv->name)
1484 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1485 errmsg("unrecognized privilege type: \"%s\"", chunk)));
1494 * has_table_privilege variants
1495 * These are all named "has_table_privilege" at the SQL level.
1496 * They take various combinations of relation name, relation OID,
1497 * user name, user OID, or implicit user = current_user.
1499 * The result is a boolean value: true if user has the indicated
1500 * privilege, false if not. The variants that take a relation OID
1501 * return NULL if the OID doesn't exist (rather than failing, as
1502 * they did before Postgres 8.4).
1506 * has_table_privilege_name_name
1507 * Check user privileges on a table given
1508 * name username, text tablename, and text priv name.
1511 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1513 Name rolename = PG_GETARG_NAME(0);
1514 text *tablename = PG_GETARG_TEXT_P(1);
1515 text *priv_type_text = PG_GETARG_TEXT_P(2);
1519 AclResult aclresult;
1521 roleid = get_roleid_checked(NameStr(*rolename));
1522 tableoid = convert_table_name(tablename);
1523 mode = convert_table_priv_string(priv_type_text);
1525 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1527 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1531 * has_table_privilege_name
1532 * Check user privileges on a table given
1533 * text tablename and text priv name.
1534 * current_user is assumed
1537 has_table_privilege_name(PG_FUNCTION_ARGS)
1539 text *tablename = PG_GETARG_TEXT_P(0);
1540 text *priv_type_text = PG_GETARG_TEXT_P(1);
1544 AclResult aclresult;
1546 roleid = GetUserId();
1547 tableoid = convert_table_name(tablename);
1548 mode = convert_table_priv_string(priv_type_text);
1550 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1552 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1556 * has_table_privilege_name_id
1557 * Check user privileges on a table given
1558 * name usename, table oid, and text priv name.
1561 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1563 Name username = PG_GETARG_NAME(0);
1564 Oid tableoid = PG_GETARG_OID(1);
1565 text *priv_type_text = PG_GETARG_TEXT_P(2);
1568 AclResult aclresult;
1570 roleid = get_roleid_checked(NameStr(*username));
1571 mode = convert_table_priv_string(priv_type_text);
1573 if (!SearchSysCacheExists(RELOID,
1574 ObjectIdGetDatum(tableoid),
1578 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1580 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1584 * has_table_privilege_id
1585 * Check user privileges on a table given
1586 * table oid, and text priv name.
1587 * current_user is assumed
1590 has_table_privilege_id(PG_FUNCTION_ARGS)
1592 Oid tableoid = PG_GETARG_OID(0);
1593 text *priv_type_text = PG_GETARG_TEXT_P(1);
1596 AclResult aclresult;
1598 roleid = GetUserId();
1599 mode = convert_table_priv_string(priv_type_text);
1601 if (!SearchSysCacheExists(RELOID,
1602 ObjectIdGetDatum(tableoid),
1606 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1608 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1612 * has_table_privilege_id_name
1613 * Check user privileges on a table given
1614 * roleid, text tablename, and text priv name.
1617 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1619 Oid roleid = PG_GETARG_OID(0);
1620 text *tablename = PG_GETARG_TEXT_P(1);
1621 text *priv_type_text = PG_GETARG_TEXT_P(2);
1624 AclResult aclresult;
1626 tableoid = convert_table_name(tablename);
1627 mode = convert_table_priv_string(priv_type_text);
1629 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1631 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1635 * has_table_privilege_id_id
1636 * Check user privileges on a table given
1637 * roleid, table oid, and text priv name.
1640 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1642 Oid roleid = PG_GETARG_OID(0);
1643 Oid tableoid = PG_GETARG_OID(1);
1644 text *priv_type_text = PG_GETARG_TEXT_P(2);
1646 AclResult aclresult;
1648 mode = convert_table_priv_string(priv_type_text);
1650 if (!SearchSysCacheExists(RELOID,
1651 ObjectIdGetDatum(tableoid),
1655 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1657 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1661 * Support routines for has_table_privilege family.
1665 * Given a table name expressed as a string, look it up and return Oid
1668 convert_table_name(text *tablename)
1672 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1674 return RangeVarGetRelid(relrv, false);
1678 * convert_table_priv_string
1679 * Convert text string to AclMode value.
1682 convert_table_priv_string(text *priv_type_text)
1684 static const priv_map table_priv_map[] = {
1685 { "SELECT", ACL_SELECT },
1686 { "SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT) },
1687 { "INSERT", ACL_INSERT },
1688 { "INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT) },
1689 { "UPDATE", ACL_UPDATE },
1690 { "UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE) },
1691 { "DELETE", ACL_DELETE },
1692 { "DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE) },
1693 { "TRUNCATE", ACL_TRUNCATE },
1694 { "TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE) },
1695 { "REFERENCES", ACL_REFERENCES },
1696 { "REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES) },
1697 { "TRIGGER", ACL_TRIGGER },
1698 { "TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER) },
1699 { "RULE", 0 }, /* ignore old RULE privileges */
1700 { "RULE WITH GRANT OPTION", 0 },
1704 return convert_any_priv_string(priv_type_text, table_priv_map);
1709 * has_any_column_privilege variants
1710 * These are all named "has_any_column_privilege" at the SQL level.
1711 * They take various combinations of relation name, relation OID,
1712 * user name, user OID, or implicit user = current_user.
1714 * The result is a boolean value: true if user has the indicated
1715 * privilege for any column of the table, false if not. The variants
1716 * that take a relation OID return NULL if the OID doesn't exist.
1720 * has_any_column_privilege_name_name
1721 * Check user privileges on any column of a table given
1722 * name username, text tablename, and text priv name.
1725 has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
1727 Name rolename = PG_GETARG_NAME(0);
1728 text *tablename = PG_GETARG_TEXT_P(1);
1729 text *priv_type_text = PG_GETARG_TEXT_P(2);
1733 AclResult aclresult;
1735 roleid = get_roleid_checked(NameStr(*rolename));
1736 tableoid = convert_table_name(tablename);
1737 mode = convert_column_priv_string(priv_type_text);
1739 /* First check at table level, then examine each column if needed */
1740 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1741 if (aclresult != ACLCHECK_OK)
1742 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
1745 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1749 * has_any_column_privilege_name
1750 * Check user privileges on any column of a table given
1751 * text tablename and text priv name.
1752 * current_user is assumed
1755 has_any_column_privilege_name(PG_FUNCTION_ARGS)
1757 text *tablename = PG_GETARG_TEXT_P(0);
1758 text *priv_type_text = PG_GETARG_TEXT_P(1);
1762 AclResult aclresult;
1764 roleid = GetUserId();
1765 tableoid = convert_table_name(tablename);
1766 mode = convert_column_priv_string(priv_type_text);
1768 /* First check at table level, then examine each column if needed */
1769 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1770 if (aclresult != ACLCHECK_OK)
1771 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
1774 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1778 * has_any_column_privilege_name_id
1779 * Check user privileges on any column of a table given
1780 * name usename, table oid, and text priv name.
1783 has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
1785 Name username = PG_GETARG_NAME(0);
1786 Oid tableoid = PG_GETARG_OID(1);
1787 text *priv_type_text = PG_GETARG_TEXT_P(2);
1790 AclResult aclresult;
1792 roleid = get_roleid_checked(NameStr(*username));
1793 mode = convert_column_priv_string(priv_type_text);
1795 if (!SearchSysCacheExists(RELOID,
1796 ObjectIdGetDatum(tableoid),
1800 /* First check at table level, then examine each column if needed */
1801 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1802 if (aclresult != ACLCHECK_OK)
1803 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
1806 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1810 * has_any_column_privilege_id
1811 * Check user privileges on any column of a table given
1812 * table oid, and text priv name.
1813 * current_user is assumed
1816 has_any_column_privilege_id(PG_FUNCTION_ARGS)
1818 Oid tableoid = PG_GETARG_OID(0);
1819 text *priv_type_text = PG_GETARG_TEXT_P(1);
1822 AclResult aclresult;
1824 roleid = GetUserId();
1825 mode = convert_column_priv_string(priv_type_text);
1827 if (!SearchSysCacheExists(RELOID,
1828 ObjectIdGetDatum(tableoid),
1832 /* First check at table level, then examine each column if needed */
1833 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1834 if (aclresult != ACLCHECK_OK)
1835 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
1838 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1842 * has_any_column_privilege_id_name
1843 * Check user privileges on any column of a table given
1844 * roleid, text tablename, and text priv name.
1847 has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
1849 Oid roleid = PG_GETARG_OID(0);
1850 text *tablename = PG_GETARG_TEXT_P(1);
1851 text *priv_type_text = PG_GETARG_TEXT_P(2);
1854 AclResult aclresult;
1856 tableoid = convert_table_name(tablename);
1857 mode = convert_column_priv_string(priv_type_text);
1859 /* First check at table level, then examine each column if needed */
1860 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1861 if (aclresult != ACLCHECK_OK)
1862 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
1865 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1869 * has_any_column_privilege_id_id
1870 * Check user privileges on any column of a table given
1871 * roleid, table oid, and text priv name.
1874 has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
1876 Oid roleid = PG_GETARG_OID(0);
1877 Oid tableoid = PG_GETARG_OID(1);
1878 text *priv_type_text = PG_GETARG_TEXT_P(2);
1880 AclResult aclresult;
1882 mode = convert_column_priv_string(priv_type_text);
1884 if (!SearchSysCacheExists(RELOID,
1885 ObjectIdGetDatum(tableoid),
1889 /* First check at table level, then examine each column if needed */
1890 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1891 if (aclresult != ACLCHECK_OK)
1892 aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
1895 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1900 * has_column_privilege variants
1901 * These are all named "has_column_privilege" at the SQL level.
1902 * They take various combinations of relation name, relation OID,
1903 * column name, column attnum, user name, user OID, or
1904 * implicit user = current_user.
1906 * The result is a boolean value: true if user has the indicated
1907 * privilege, false if not. The variants that take a relation OID
1908 * and an integer attnum return NULL (rather than throwing an error)
1909 * if the column doesn't exist or is dropped.
1913 * column_privilege_check: check column privileges, but don't throw an error
1914 * for dropped column or table
1916 * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
1919 column_privilege_check(Oid tableoid, AttrNumber attnum,
1920 Oid roleid, AclMode mode)
1922 AclResult aclresult;
1924 Form_pg_attribute attributeForm;
1927 * First check if we have the privilege at the table level. We check
1928 * existence of the pg_class row before risking calling pg_class_aclcheck.
1929 * Note: it might seem there's a race condition against concurrent DROP,
1930 * but really it's safe because there will be no syscache flush between
1931 * here and there. So if we see the row in the syscache, so will
1932 * pg_class_aclcheck.
1934 if (!SearchSysCacheExists(RELOID,
1935 ObjectIdGetDatum(tableoid),
1939 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1941 if (aclresult == ACLCHECK_OK)
1945 * No table privilege, so try per-column privileges. Again, we have to
1946 * check for dropped attribute first, and we rely on the syscache not to
1947 * notice a concurrent drop before pg_attribute_aclcheck fetches the row.
1949 attTuple = SearchSysCache(ATTNUM,
1950 ObjectIdGetDatum(tableoid),
1951 Int16GetDatum(attnum),
1953 if (!HeapTupleIsValid(attTuple))
1955 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
1956 if (attributeForm->attisdropped)
1958 ReleaseSysCache(attTuple);
1961 ReleaseSysCache(attTuple);
1963 aclresult = pg_attribute_aclcheck(tableoid, attnum, roleid, mode);
1965 return (aclresult == ACLCHECK_OK);
1969 * has_column_privilege_name_name_name
1970 * Check user privileges on a column given
1971 * name username, text tablename, text colname, and text priv name.
1974 has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
1976 Name rolename = PG_GETARG_NAME(0);
1977 text *tablename = PG_GETARG_TEXT_P(1);
1978 text *column = PG_GETARG_TEXT_P(2);
1979 text *priv_type_text = PG_GETARG_TEXT_P(3);
1982 AttrNumber colattnum;
1986 roleid = get_roleid_checked(NameStr(*rolename));
1987 tableoid = convert_table_name(tablename);
1988 colattnum = convert_column_name(tableoid, column);
1989 mode = convert_column_priv_string(priv_type_text);
1991 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
1994 PG_RETURN_BOOL(privresult);
1998 * has_column_privilege_name_name_attnum
1999 * Check user privileges on a column given
2000 * name username, text tablename, int attnum, and text priv name.
2003 has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
2005 Name rolename = PG_GETARG_NAME(0);
2006 text *tablename = PG_GETARG_TEXT_P(1);
2007 AttrNumber colattnum = PG_GETARG_INT16(2);
2008 text *priv_type_text = PG_GETARG_TEXT_P(3);
2014 roleid = get_roleid_checked(NameStr(*rolename));
2015 tableoid = convert_table_name(tablename);
2016 mode = convert_column_priv_string(priv_type_text);
2018 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2021 PG_RETURN_BOOL(privresult);
2025 * has_column_privilege_name_id_name
2026 * Check user privileges on a column given
2027 * name username, table oid, text colname, and text priv name.
2030 has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
2032 Name username = PG_GETARG_NAME(0);
2033 Oid tableoid = PG_GETARG_OID(1);
2034 text *column = PG_GETARG_TEXT_P(2);
2035 text *priv_type_text = PG_GETARG_TEXT_P(3);
2037 AttrNumber colattnum;
2041 roleid = get_roleid_checked(NameStr(*username));
2042 colattnum = convert_column_name(tableoid, column);
2043 mode = convert_column_priv_string(priv_type_text);
2045 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2048 PG_RETURN_BOOL(privresult);
2052 * has_column_privilege_name_id_attnum
2053 * Check user privileges on a column given
2054 * name username, table oid, int attnum, and text priv name.
2057 has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
2059 Name username = PG_GETARG_NAME(0);
2060 Oid tableoid = PG_GETARG_OID(1);
2061 AttrNumber colattnum = PG_GETARG_INT16(2);
2062 text *priv_type_text = PG_GETARG_TEXT_P(3);
2067 roleid = get_roleid_checked(NameStr(*username));
2068 mode = convert_column_priv_string(priv_type_text);
2070 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2073 PG_RETURN_BOOL(privresult);
2077 * has_column_privilege_id_name_name
2078 * Check user privileges on a column given
2079 * oid roleid, text tablename, text colname, and text priv name.
2082 has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
2084 Oid roleid = PG_GETARG_OID(0);
2085 text *tablename = PG_GETARG_TEXT_P(1);
2086 text *column = PG_GETARG_TEXT_P(2);
2087 text *priv_type_text = PG_GETARG_TEXT_P(3);
2089 AttrNumber colattnum;
2093 tableoid = convert_table_name(tablename);
2094 colattnum = convert_column_name(tableoid, column);
2095 mode = convert_column_priv_string(priv_type_text);
2097 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2100 PG_RETURN_BOOL(privresult);
2104 * has_column_privilege_id_name_attnum
2105 * Check user privileges on a column given
2106 * oid roleid, text tablename, int attnum, and text priv name.
2109 has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
2111 Oid roleid = PG_GETARG_OID(0);
2112 text *tablename = PG_GETARG_TEXT_P(1);
2113 AttrNumber colattnum = PG_GETARG_INT16(2);
2114 text *priv_type_text = PG_GETARG_TEXT_P(3);
2119 tableoid = convert_table_name(tablename);
2120 mode = convert_column_priv_string(priv_type_text);
2122 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2125 PG_RETURN_BOOL(privresult);
2129 * has_column_privilege_id_id_name
2130 * Check user privileges on a column given
2131 * oid roleid, table oid, text colname, and text priv name.
2134 has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
2136 Oid roleid = PG_GETARG_OID(0);
2137 Oid tableoid = PG_GETARG_OID(1);
2138 text *column = PG_GETARG_TEXT_P(2);
2139 text *priv_type_text = PG_GETARG_TEXT_P(3);
2140 AttrNumber colattnum;
2144 colattnum = convert_column_name(tableoid, column);
2145 mode = convert_column_priv_string(priv_type_text);
2147 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2150 PG_RETURN_BOOL(privresult);
2154 * has_column_privilege_id_id_attnum
2155 * Check user privileges on a column given
2156 * oid roleid, table oid, int attnum, and text priv name.
2159 has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
2161 Oid roleid = PG_GETARG_OID(0);
2162 Oid tableoid = PG_GETARG_OID(1);
2163 AttrNumber colattnum = PG_GETARG_INT16(2);
2164 text *priv_type_text = PG_GETARG_TEXT_P(3);
2168 mode = convert_column_priv_string(priv_type_text);
2170 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2173 PG_RETURN_BOOL(privresult);
2177 * has_column_privilege_name_name
2178 * Check user privileges on a column given
2179 * text tablename, text colname, and text priv name.
2180 * current_user is assumed
2183 has_column_privilege_name_name(PG_FUNCTION_ARGS)
2185 text *tablename = PG_GETARG_TEXT_P(0);
2186 text *column = PG_GETARG_TEXT_P(1);
2187 text *priv_type_text = PG_GETARG_TEXT_P(2);
2190 AttrNumber colattnum;
2194 roleid = GetUserId();
2195 tableoid = convert_table_name(tablename);
2196 colattnum = convert_column_name(tableoid, column);
2197 mode = convert_column_priv_string(priv_type_text);
2199 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2202 PG_RETURN_BOOL(privresult);
2206 * has_column_privilege_name_attnum
2207 * Check user privileges on a column given
2208 * text tablename, int attnum, and text priv name.
2209 * current_user is assumed
2212 has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
2214 text *tablename = PG_GETARG_TEXT_P(0);
2215 AttrNumber colattnum = PG_GETARG_INT16(1);
2216 text *priv_type_text = PG_GETARG_TEXT_P(2);
2222 roleid = GetUserId();
2223 tableoid = convert_table_name(tablename);
2224 mode = convert_column_priv_string(priv_type_text);
2226 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2229 PG_RETURN_BOOL(privresult);
2233 * has_column_privilege_id_name
2234 * Check user privileges on a column given
2235 * table oid, text colname, and text priv name.
2236 * current_user is assumed
2239 has_column_privilege_id_name(PG_FUNCTION_ARGS)
2241 Oid tableoid = PG_GETARG_OID(0);
2242 text *column = PG_GETARG_TEXT_P(1);
2243 text *priv_type_text = PG_GETARG_TEXT_P(2);
2245 AttrNumber colattnum;
2249 roleid = GetUserId();
2250 colattnum = convert_column_name(tableoid, column);
2251 mode = convert_column_priv_string(priv_type_text);
2253 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2256 PG_RETURN_BOOL(privresult);
2260 * has_column_privilege_id_attnum
2261 * Check user privileges on a column given
2262 * table oid, int attnum, and text priv name.
2263 * current_user is assumed
2266 has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
2268 Oid tableoid = PG_GETARG_OID(0);
2269 AttrNumber colattnum = PG_GETARG_INT16(1);
2270 text *priv_type_text = PG_GETARG_TEXT_P(2);
2275 roleid = GetUserId();
2276 mode = convert_column_priv_string(priv_type_text);
2278 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2281 PG_RETURN_BOOL(privresult);
2285 * Support routines for has_column_privilege family.
2289 * Given a table OID and a column name expressed as a string, look it up
2290 * and return the column number
2293 convert_column_name(Oid tableoid, text *column)
2298 colname = text_to_cstring(column);
2299 attnum = get_attnum(tableoid, colname);
2300 if (attnum == InvalidAttrNumber)
2302 (errcode(ERRCODE_UNDEFINED_COLUMN),
2303 errmsg("column \"%s\" of relation \"%s\" does not exist",
2304 colname, get_rel_name(tableoid))));
2310 * convert_column_priv_string
2311 * Convert text string to AclMode value.
2314 convert_column_priv_string(text *priv_type_text)
2316 static const priv_map column_priv_map[] = {
2317 { "SELECT", ACL_SELECT },
2318 { "SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT) },
2319 { "INSERT", ACL_INSERT },
2320 { "INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT) },
2321 { "UPDATE", ACL_UPDATE },
2322 { "UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE) },
2323 { "REFERENCES", ACL_REFERENCES },
2324 { "REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES) },
2328 return convert_any_priv_string(priv_type_text, column_priv_map);
2333 * has_database_privilege variants
2334 * These are all named "has_database_privilege" at the SQL level.
2335 * They take various combinations of database name, database OID,
2336 * user name, user OID, or implicit user = current_user.
2338 * The result is a boolean value: true if user has the indicated
2339 * privilege, false if not, or NULL if object doesn't exist.
2343 * has_database_privilege_name_name
2344 * Check user privileges on a database given
2345 * name username, text databasename, and text priv name.
2348 has_database_privilege_name_name(PG_FUNCTION_ARGS)
2350 Name username = PG_GETARG_NAME(0);
2351 text *databasename = PG_GETARG_TEXT_P(1);
2352 text *priv_type_text = PG_GETARG_TEXT_P(2);
2356 AclResult aclresult;
2358 roleid = get_roleid_checked(NameStr(*username));
2359 databaseoid = convert_database_name(databasename);
2360 mode = convert_database_priv_string(priv_type_text);
2362 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2364 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2368 * has_database_privilege_name
2369 * Check user privileges on a database given
2370 * text databasename and text priv name.
2371 * current_user is assumed
2374 has_database_privilege_name(PG_FUNCTION_ARGS)
2376 text *databasename = PG_GETARG_TEXT_P(0);
2377 text *priv_type_text = PG_GETARG_TEXT_P(1);
2381 AclResult aclresult;
2383 roleid = GetUserId();
2384 databaseoid = convert_database_name(databasename);
2385 mode = convert_database_priv_string(priv_type_text);
2387 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2389 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2393 * has_database_privilege_name_id
2394 * Check user privileges on a database given
2395 * name usename, database oid, and text priv name.
2398 has_database_privilege_name_id(PG_FUNCTION_ARGS)
2400 Name username = PG_GETARG_NAME(0);
2401 Oid databaseoid = PG_GETARG_OID(1);
2402 text *priv_type_text = PG_GETARG_TEXT_P(2);
2405 AclResult aclresult;
2407 roleid = get_roleid_checked(NameStr(*username));
2408 mode = convert_database_priv_string(priv_type_text);
2410 if (!SearchSysCacheExists(DATABASEOID,
2411 ObjectIdGetDatum(databaseoid),
2415 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2417 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2421 * has_database_privilege_id
2422 * Check user privileges on a database given
2423 * database oid, and text priv name.
2424 * current_user is assumed
2427 has_database_privilege_id(PG_FUNCTION_ARGS)
2429 Oid databaseoid = PG_GETARG_OID(0);
2430 text *priv_type_text = PG_GETARG_TEXT_P(1);
2433 AclResult aclresult;
2435 roleid = GetUserId();
2436 mode = convert_database_priv_string(priv_type_text);
2438 if (!SearchSysCacheExists(DATABASEOID,
2439 ObjectIdGetDatum(databaseoid),
2443 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2445 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2449 * has_database_privilege_id_name
2450 * Check user privileges on a database given
2451 * roleid, text databasename, and text priv name.
2454 has_database_privilege_id_name(PG_FUNCTION_ARGS)
2456 Oid roleid = PG_GETARG_OID(0);
2457 text *databasename = PG_GETARG_TEXT_P(1);
2458 text *priv_type_text = PG_GETARG_TEXT_P(2);
2461 AclResult aclresult;
2463 databaseoid = convert_database_name(databasename);
2464 mode = convert_database_priv_string(priv_type_text);
2466 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2468 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2472 * has_database_privilege_id_id
2473 * Check user privileges on a database given
2474 * roleid, database oid, and text priv name.
2477 has_database_privilege_id_id(PG_FUNCTION_ARGS)
2479 Oid roleid = PG_GETARG_OID(0);
2480 Oid databaseoid = PG_GETARG_OID(1);
2481 text *priv_type_text = PG_GETARG_TEXT_P(2);
2483 AclResult aclresult;
2485 mode = convert_database_priv_string(priv_type_text);
2487 if (!SearchSysCacheExists(DATABASEOID,
2488 ObjectIdGetDatum(databaseoid),
2492 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2494 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2498 * Support routines for has_database_privilege family.
2502 * Given a database name expressed as a string, look it up and return Oid
2505 convert_database_name(text *databasename)
2507 char *dbname = text_to_cstring(databasename);
2510 oid = get_database_oid(dbname);
2511 if (!OidIsValid(oid))
2513 (errcode(ERRCODE_UNDEFINED_DATABASE),
2514 errmsg("database \"%s\" does not exist", dbname)));
2520 * convert_database_priv_string
2521 * Convert text string to AclMode value.
2524 convert_database_priv_string(text *priv_type_text)
2526 static const priv_map database_priv_map[] = {
2527 { "CREATE", ACL_CREATE },
2528 { "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
2529 { "TEMPORARY", ACL_CREATE_TEMP },
2530 { "TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP) },
2531 { "TEMP", ACL_CREATE_TEMP },
2532 { "TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP) },
2533 { "CONNECT", ACL_CONNECT },
2534 { "CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT) },
2538 return convert_any_priv_string(priv_type_text, database_priv_map);
2544 * has_foreign_data_wrapper_privilege variants
2545 * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
2546 * They take various combinations of foreign-data wrapper name,
2547 * fdw OID, user name, user OID, or implicit user = current_user.
2549 * The result is a boolean value: true if user has the indicated
2550 * privilege, false if not.
2554 * has_foreign_data_wrapper_privilege_name_name
2555 * Check user privileges on a foreign-data wrapper given
2556 * name username, text fdwname, and text priv name.
2559 has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
2561 Name username = PG_GETARG_NAME(0);
2562 text *fdwname = PG_GETARG_TEXT_P(1);
2563 text *priv_type_text = PG_GETARG_TEXT_P(2);
2567 AclResult aclresult;
2569 roleid = get_roleid_checked(NameStr(*username));
2570 fdwid = convert_foreign_data_wrapper_name(fdwname);
2571 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2573 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2575 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2579 * has_foreign_data_wrapper_privilege_name
2580 * Check user privileges on a foreign-data wrapper given
2581 * text fdwname and text priv name.
2582 * current_user is assumed
2585 has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
2587 text *fdwname = PG_GETARG_TEXT_P(0);
2588 text *priv_type_text = PG_GETARG_TEXT_P(1);
2592 AclResult aclresult;
2594 roleid = GetUserId();
2595 fdwid = convert_foreign_data_wrapper_name(fdwname);
2596 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2598 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2600 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2604 * has_foreign_data_wrapper_privilege_name_id
2605 * Check user privileges on a foreign-data wrapper given
2606 * name usename, foreign-data wrapper oid, and text priv name.
2609 has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
2611 Name username = PG_GETARG_NAME(0);
2612 Oid fdwid = PG_GETARG_OID(1);
2613 text *priv_type_text = PG_GETARG_TEXT_P(2);
2616 AclResult aclresult;
2618 roleid = get_roleid_checked(NameStr(*username));
2619 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2621 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2623 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2627 * has_foreign_data_wrapper_privilege_id
2628 * Check user privileges on a foreign-data wrapper given
2629 * foreign-data wrapper oid, and text priv name.
2630 * current_user is assumed
2633 has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
2635 Oid fdwid = PG_GETARG_OID(0);
2636 text *priv_type_text = PG_GETARG_TEXT_P(1);
2639 AclResult aclresult;
2641 roleid = GetUserId();
2642 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2644 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2646 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2650 * has_foreign_data_wrapper_privilege_id_name
2651 * Check user privileges on a foreign-data wrapper given
2652 * roleid, text fdwname, and text priv name.
2655 has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
2657 Oid roleid = PG_GETARG_OID(0);
2658 text *fdwname = PG_GETARG_TEXT_P(1);
2659 text *priv_type_text = PG_GETARG_TEXT_P(2);
2662 AclResult aclresult;
2664 fdwid = convert_foreign_data_wrapper_name(fdwname);
2665 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2667 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2669 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2673 * has_foreign_data_wrapper_privilege_id_id
2674 * Check user privileges on a foreign-data wrapper given
2675 * roleid, fdw oid, and text priv name.
2678 has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
2680 Oid roleid = PG_GETARG_OID(0);
2681 Oid fdwid = PG_GETARG_OID(1);
2682 text *priv_type_text = PG_GETARG_TEXT_P(2);
2684 AclResult aclresult;
2686 mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2688 aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2690 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2694 * Support routines for has_foreign_data_wrapper_privilege family.
2698 * Given a FDW name expressed as a string, look it up and return Oid
2701 convert_foreign_data_wrapper_name(text *fdwname)
2703 char *fdwstr = text_to_cstring(fdwname);
2705 return GetForeignDataWrapperOidByName(fdwstr, false);
2709 * convert_foreign_data_wrapper_priv_string
2710 * Convert text string to AclMode value.
2713 convert_foreign_data_wrapper_priv_string(text *priv_type_text)
2715 static const priv_map foreign_data_wrapper_priv_map[] = {
2716 { "USAGE", ACL_USAGE },
2717 { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
2721 return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
2726 * has_function_privilege variants
2727 * These are all named "has_function_privilege" at the SQL level.
2728 * They take various combinations of function name, function OID,
2729 * user name, user OID, or implicit user = current_user.
2731 * The result is a boolean value: true if user has the indicated
2732 * privilege, false if not, or NULL if object doesn't exist.
2736 * has_function_privilege_name_name
2737 * Check user privileges on a function given
2738 * name username, text functionname, and text priv name.
2741 has_function_privilege_name_name(PG_FUNCTION_ARGS)
2743 Name username = PG_GETARG_NAME(0);
2744 text *functionname = PG_GETARG_TEXT_P(1);
2745 text *priv_type_text = PG_GETARG_TEXT_P(2);
2749 AclResult aclresult;
2751 roleid = get_roleid_checked(NameStr(*username));
2752 functionoid = convert_function_name(functionname);
2753 mode = convert_function_priv_string(priv_type_text);
2755 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2757 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2761 * has_function_privilege_name
2762 * Check user privileges on a function given
2763 * text functionname and text priv name.
2764 * current_user is assumed
2767 has_function_privilege_name(PG_FUNCTION_ARGS)
2769 text *functionname = PG_GETARG_TEXT_P(0);
2770 text *priv_type_text = PG_GETARG_TEXT_P(1);
2774 AclResult aclresult;
2776 roleid = GetUserId();
2777 functionoid = convert_function_name(functionname);
2778 mode = convert_function_priv_string(priv_type_text);
2780 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2782 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2786 * has_function_privilege_name_id
2787 * Check user privileges on a function given
2788 * name usename, function oid, and text priv name.
2791 has_function_privilege_name_id(PG_FUNCTION_ARGS)
2793 Name username = PG_GETARG_NAME(0);
2794 Oid functionoid = PG_GETARG_OID(1);
2795 text *priv_type_text = PG_GETARG_TEXT_P(2);
2798 AclResult aclresult;
2800 roleid = get_roleid_checked(NameStr(*username));
2801 mode = convert_function_priv_string(priv_type_text);
2803 if (!SearchSysCacheExists(PROCOID,
2804 ObjectIdGetDatum(functionoid),
2808 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2810 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2814 * has_function_privilege_id
2815 * Check user privileges on a function given
2816 * function oid, and text priv name.
2817 * current_user is assumed
2820 has_function_privilege_id(PG_FUNCTION_ARGS)
2822 Oid functionoid = PG_GETARG_OID(0);
2823 text *priv_type_text = PG_GETARG_TEXT_P(1);
2826 AclResult aclresult;
2828 roleid = GetUserId();
2829 mode = convert_function_priv_string(priv_type_text);
2831 if (!SearchSysCacheExists(PROCOID,
2832 ObjectIdGetDatum(functionoid),
2836 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2838 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2842 * has_function_privilege_id_name
2843 * Check user privileges on a function given
2844 * roleid, text functionname, and text priv name.
2847 has_function_privilege_id_name(PG_FUNCTION_ARGS)
2849 Oid roleid = PG_GETARG_OID(0);
2850 text *functionname = PG_GETARG_TEXT_P(1);
2851 text *priv_type_text = PG_GETARG_TEXT_P(2);
2854 AclResult aclresult;
2856 functionoid = convert_function_name(functionname);
2857 mode = convert_function_priv_string(priv_type_text);
2859 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2861 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2865 * has_function_privilege_id_id
2866 * Check user privileges on a function given
2867 * roleid, function oid, and text priv name.
2870 has_function_privilege_id_id(PG_FUNCTION_ARGS)
2872 Oid roleid = PG_GETARG_OID(0);
2873 Oid functionoid = PG_GETARG_OID(1);
2874 text *priv_type_text = PG_GETARG_TEXT_P(2);
2876 AclResult aclresult;
2878 mode = convert_function_priv_string(priv_type_text);
2880 if (!SearchSysCacheExists(PROCOID,
2881 ObjectIdGetDatum(functionoid),
2885 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2887 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2891 * Support routines for has_function_privilege family.
2895 * Given a function name expressed as a string, look it up and return Oid
2898 convert_function_name(text *functionname)
2900 char *funcname = text_to_cstring(functionname);
2903 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
2904 CStringGetDatum(funcname)));
2906 if (!OidIsValid(oid))
2908 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2909 errmsg("function \"%s\" does not exist", funcname)));
2915 * convert_function_priv_string
2916 * Convert text string to AclMode value.
2919 convert_function_priv_string(text *priv_type_text)
2921 static const priv_map function_priv_map[] = {
2922 { "EXECUTE", ACL_EXECUTE },
2923 { "EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE) },
2927 return convert_any_priv_string(priv_type_text, function_priv_map);
2932 * has_language_privilege variants
2933 * These are all named "has_language_privilege" at the SQL level.
2934 * They take various combinations of language name, language OID,
2935 * user name, user OID, or implicit user = current_user.
2937 * The result is a boolean value: true if user has the indicated
2938 * privilege, false if not, or NULL if object doesn't exist.
2942 * has_language_privilege_name_name
2943 * Check user privileges on a language given
2944 * name username, text languagename, and text priv name.
2947 has_language_privilege_name_name(PG_FUNCTION_ARGS)
2949 Name username = PG_GETARG_NAME(0);
2950 text *languagename = PG_GETARG_TEXT_P(1);
2951 text *priv_type_text = PG_GETARG_TEXT_P(2);
2955 AclResult aclresult;
2957 roleid = get_roleid_checked(NameStr(*username));
2958 languageoid = convert_language_name(languagename);
2959 mode = convert_language_priv_string(priv_type_text);
2961 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2963 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2967 * has_language_privilege_name
2968 * Check user privileges on a language given
2969 * text languagename and text priv name.
2970 * current_user is assumed
2973 has_language_privilege_name(PG_FUNCTION_ARGS)
2975 text *languagename = PG_GETARG_TEXT_P(0);
2976 text *priv_type_text = PG_GETARG_TEXT_P(1);
2980 AclResult aclresult;
2982 roleid = GetUserId();
2983 languageoid = convert_language_name(languagename);
2984 mode = convert_language_priv_string(priv_type_text);
2986 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2988 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2992 * has_language_privilege_name_id
2993 * Check user privileges on a language given
2994 * name usename, language oid, and text priv name.
2997 has_language_privilege_name_id(PG_FUNCTION_ARGS)
2999 Name username = PG_GETARG_NAME(0);
3000 Oid languageoid = PG_GETARG_OID(1);
3001 text *priv_type_text = PG_GETARG_TEXT_P(2);
3004 AclResult aclresult;
3006 roleid = get_roleid_checked(NameStr(*username));
3007 mode = convert_language_priv_string(priv_type_text);
3009 if (!SearchSysCacheExists(LANGOID,
3010 ObjectIdGetDatum(languageoid),
3014 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3016 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3020 * has_language_privilege_id
3021 * Check user privileges on a language given
3022 * language oid, and text priv name.
3023 * current_user is assumed
3026 has_language_privilege_id(PG_FUNCTION_ARGS)
3028 Oid languageoid = PG_GETARG_OID(0);
3029 text *priv_type_text = PG_GETARG_TEXT_P(1);
3032 AclResult aclresult;
3034 roleid = GetUserId();
3035 mode = convert_language_priv_string(priv_type_text);
3037 if (!SearchSysCacheExists(LANGOID,
3038 ObjectIdGetDatum(languageoid),
3042 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3044 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3048 * has_language_privilege_id_name
3049 * Check user privileges on a language given
3050 * roleid, text languagename, and text priv name.
3053 has_language_privilege_id_name(PG_FUNCTION_ARGS)
3055 Oid roleid = PG_GETARG_OID(0);
3056 text *languagename = PG_GETARG_TEXT_P(1);
3057 text *priv_type_text = PG_GETARG_TEXT_P(2);
3060 AclResult aclresult;
3062 languageoid = convert_language_name(languagename);
3063 mode = convert_language_priv_string(priv_type_text);
3065 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3067 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3071 * has_language_privilege_id_id
3072 * Check user privileges on a language given
3073 * roleid, language oid, and text priv name.
3076 has_language_privilege_id_id(PG_FUNCTION_ARGS)
3078 Oid roleid = PG_GETARG_OID(0);
3079 Oid languageoid = PG_GETARG_OID(1);
3080 text *priv_type_text = PG_GETARG_TEXT_P(2);
3082 AclResult aclresult;
3084 mode = convert_language_priv_string(priv_type_text);
3086 if (!SearchSysCacheExists(LANGOID,
3087 ObjectIdGetDatum(languageoid),
3091 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3093 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3097 * Support routines for has_language_privilege family.
3101 * Given a language name expressed as a string, look it up and return Oid
3104 convert_language_name(text *languagename)
3106 char *langname = text_to_cstring(languagename);
3109 oid = GetSysCacheOid(LANGNAME,
3110 CStringGetDatum(langname),
3112 if (!OidIsValid(oid))
3114 (errcode(ERRCODE_UNDEFINED_OBJECT),
3115 errmsg("language \"%s\" does not exist", langname)));
3121 * convert_language_priv_string
3122 * Convert text string to AclMode value.
3125 convert_language_priv_string(text *priv_type_text)
3127 static const priv_map language_priv_map[] = {
3128 { "USAGE", ACL_USAGE },
3129 { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
3133 return convert_any_priv_string(priv_type_text, language_priv_map);
3138 * has_schema_privilege variants
3139 * These are all named "has_schema_privilege" at the SQL level.
3140 * They take various combinations of schema name, schema OID,
3141 * user name, user OID, or implicit user = current_user.
3143 * The result is a boolean value: true if user has the indicated
3144 * privilege, false if not, or NULL if object doesn't exist.
3148 * has_schema_privilege_name_name
3149 * Check user privileges on a schema given
3150 * name username, text schemaname, and text priv name.
3153 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
3155 Name username = PG_GETARG_NAME(0);
3156 text *schemaname = PG_GETARG_TEXT_P(1);
3157 text *priv_type_text = PG_GETARG_TEXT_P(2);
3161 AclResult aclresult;
3163 roleid = get_roleid_checked(NameStr(*username));
3164 schemaoid = convert_schema_name(schemaname);
3165 mode = convert_schema_priv_string(priv_type_text);
3167 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3169 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3173 * has_schema_privilege_name
3174 * Check user privileges on a schema given
3175 * text schemaname and text priv name.
3176 * current_user is assumed
3179 has_schema_privilege_name(PG_FUNCTION_ARGS)
3181 text *schemaname = PG_GETARG_TEXT_P(0);
3182 text *priv_type_text = PG_GETARG_TEXT_P(1);
3186 AclResult aclresult;
3188 roleid = GetUserId();
3189 schemaoid = convert_schema_name(schemaname);
3190 mode = convert_schema_priv_string(priv_type_text);
3192 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3194 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3198 * has_schema_privilege_name_id
3199 * Check user privileges on a schema given
3200 * name usename, schema oid, and text priv name.
3203 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
3205 Name username = PG_GETARG_NAME(0);
3206 Oid schemaoid = PG_GETARG_OID(1);
3207 text *priv_type_text = PG_GETARG_TEXT_P(2);
3210 AclResult aclresult;
3212 roleid = get_roleid_checked(NameStr(*username));
3213 mode = convert_schema_priv_string(priv_type_text);
3215 if (!SearchSysCacheExists(NAMESPACEOID,
3216 ObjectIdGetDatum(schemaoid),
3220 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3222 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3226 * has_schema_privilege_id
3227 * Check user privileges on a schema given
3228 * schema oid, and text priv name.
3229 * current_user is assumed
3232 has_schema_privilege_id(PG_FUNCTION_ARGS)
3234 Oid schemaoid = PG_GETARG_OID(0);
3235 text *priv_type_text = PG_GETARG_TEXT_P(1);
3238 AclResult aclresult;
3240 roleid = GetUserId();
3241 mode = convert_schema_priv_string(priv_type_text);
3243 if (!SearchSysCacheExists(NAMESPACEOID,
3244 ObjectIdGetDatum(schemaoid),
3248 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3250 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3254 * has_schema_privilege_id_name
3255 * Check user privileges on a schema given
3256 * roleid, text schemaname, and text priv name.
3259 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
3261 Oid roleid = PG_GETARG_OID(0);
3262 text *schemaname = PG_GETARG_TEXT_P(1);
3263 text *priv_type_text = PG_GETARG_TEXT_P(2);
3266 AclResult aclresult;
3268 schemaoid = convert_schema_name(schemaname);
3269 mode = convert_schema_priv_string(priv_type_text);
3271 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3273 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3277 * has_schema_privilege_id_id
3278 * Check user privileges on a schema given
3279 * roleid, schema oid, and text priv name.
3282 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
3284 Oid roleid = PG_GETARG_OID(0);
3285 Oid schemaoid = PG_GETARG_OID(1);
3286 text *priv_type_text = PG_GETARG_TEXT_P(2);
3288 AclResult aclresult;
3290 mode = convert_schema_priv_string(priv_type_text);
3292 if (!SearchSysCacheExists(NAMESPACEOID,
3293 ObjectIdGetDatum(schemaoid),
3297 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3299 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3303 * Support routines for has_schema_privilege family.
3307 * Given a schema name expressed as a string, look it up and return Oid
3310 convert_schema_name(text *schemaname)
3312 char *nspname = text_to_cstring(schemaname);
3315 oid = GetSysCacheOid(NAMESPACENAME,
3316 CStringGetDatum(nspname),
3318 if (!OidIsValid(oid))
3320 (errcode(ERRCODE_UNDEFINED_SCHEMA),
3321 errmsg("schema \"%s\" does not exist", nspname)));
3327 * convert_schema_priv_string
3328 * Convert text string to AclMode value.
3331 convert_schema_priv_string(text *priv_type_text)
3333 static const priv_map schema_priv_map[] = {
3334 { "CREATE", ACL_CREATE },
3335 { "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
3336 { "USAGE", ACL_USAGE },
3337 { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
3341 return convert_any_priv_string(priv_type_text, schema_priv_map);
3346 * has_server_privilege variants
3347 * These are all named "has_server_privilege" at the SQL level.
3348 * They take various combinations of foreign server name,
3349 * server OID, user name, user OID, or implicit user = current_user.
3351 * The result is a boolean value: true if user has the indicated
3352 * privilege, false if not.
3356 * has_server_privilege_name_name
3357 * Check user privileges on a foreign server given
3358 * name username, text servername, and text priv name.
3361 has_server_privilege_name_name(PG_FUNCTION_ARGS)
3363 Name username = PG_GETARG_NAME(0);
3364 text *servername = PG_GETARG_TEXT_P(1);
3365 text *priv_type_text = PG_GETARG_TEXT_P(2);
3369 AclResult aclresult;
3371 roleid = get_roleid_checked(NameStr(*username));
3372 serverid = convert_server_name(servername);
3373 mode = convert_server_priv_string(priv_type_text);
3375 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3377 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3381 * has_server_privilege_name
3382 * Check user privileges on a foreign server given
3383 * text servername and text priv name.
3384 * current_user is assumed
3387 has_server_privilege_name(PG_FUNCTION_ARGS)
3389 text *servername = PG_GETARG_TEXT_P(0);
3390 text *priv_type_text = PG_GETARG_TEXT_P(1);
3394 AclResult aclresult;
3396 roleid = GetUserId();
3397 serverid = convert_server_name(servername);
3398 mode = convert_server_priv_string(priv_type_text);
3400 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3402 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3406 * has_server_privilege_name_id
3407 * Check user privileges on a foreign server given
3408 * name usename, foreign server oid, and text priv name.
3411 has_server_privilege_name_id(PG_FUNCTION_ARGS)
3413 Name username = PG_GETARG_NAME(0);
3414 Oid serverid = PG_GETARG_OID(1);
3415 text *priv_type_text = PG_GETARG_TEXT_P(2);
3418 AclResult aclresult;
3420 roleid = get_roleid_checked(NameStr(*username));
3421 mode = convert_server_priv_string(priv_type_text);
3423 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3425 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3429 * has_server_privilege_id
3430 * Check user privileges on a foreign server given
3431 * server oid, and text priv name.
3432 * current_user is assumed
3435 has_server_privilege_id(PG_FUNCTION_ARGS)
3437 Oid serverid = PG_GETARG_OID(0);
3438 text *priv_type_text = PG_GETARG_TEXT_P(1);
3441 AclResult aclresult;
3443 roleid = GetUserId();
3444 mode = convert_server_priv_string(priv_type_text);
3446 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3448 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3452 * has_server_privilege_id_name
3453 * Check user privileges on a foreign server given
3454 * roleid, text servername, and text priv name.
3457 has_server_privilege_id_name(PG_FUNCTION_ARGS)
3459 Oid roleid = PG_GETARG_OID(0);
3460 text *servername = PG_GETARG_TEXT_P(1);
3461 text *priv_type_text = PG_GETARG_TEXT_P(2);
3464 AclResult aclresult;
3466 serverid = convert_server_name(servername);
3467 mode = convert_server_priv_string(priv_type_text);
3469 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3471 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3475 * has_server_privilege_id_id
3476 * Check user privileges on a foreign server given
3477 * roleid, server oid, and text priv name.
3480 has_server_privilege_id_id(PG_FUNCTION_ARGS)
3482 Oid roleid = PG_GETARG_OID(0);
3483 Oid serverid = PG_GETARG_OID(1);
3484 text *priv_type_text = PG_GETARG_TEXT_P(2);
3486 AclResult aclresult;
3488 mode = convert_server_priv_string(priv_type_text);
3490 aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3492 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3496 * Support routines for has_server_privilege family.
3500 * Given a server name expressed as a string, look it up and return Oid
3503 convert_server_name(text *servername)
3505 char *serverstr = text_to_cstring(servername);
3507 return GetForeignServerOidByName(serverstr, false);
3511 * convert_server_priv_string
3512 * Convert text string to AclMode value.
3515 convert_server_priv_string(text *priv_type_text)
3517 static const priv_map server_priv_map[] = {
3518 { "USAGE", ACL_USAGE },
3519 { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
3523 return convert_any_priv_string(priv_type_text, server_priv_map);
3528 * has_tablespace_privilege variants
3529 * These are all named "has_tablespace_privilege" at the SQL level.
3530 * They take various combinations of tablespace name, tablespace OID,
3531 * user name, user OID, or implicit user = current_user.
3533 * The result is a boolean value: true if user has the indicated
3534 * privilege, false if not.
3538 * has_tablespace_privilege_name_name
3539 * Check user privileges on a tablespace given
3540 * name username, text tablespacename, and text priv name.
3543 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
3545 Name username = PG_GETARG_NAME(0);
3546 text *tablespacename = PG_GETARG_TEXT_P(1);
3547 text *priv_type_text = PG_GETARG_TEXT_P(2);
3551 AclResult aclresult;
3553 roleid = get_roleid_checked(NameStr(*username));
3554 tablespaceoid = convert_tablespace_name(tablespacename);
3555 mode = convert_tablespace_priv_string(priv_type_text);
3557 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3559 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3563 * has_tablespace_privilege_name
3564 * Check user privileges on a tablespace given
3565 * text tablespacename and text priv name.
3566 * current_user is assumed
3569 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
3571 text *tablespacename = PG_GETARG_TEXT_P(0);
3572 text *priv_type_text = PG_GETARG_TEXT_P(1);
3576 AclResult aclresult;
3578 roleid = GetUserId();
3579 tablespaceoid = convert_tablespace_name(tablespacename);
3580 mode = convert_tablespace_priv_string(priv_type_text);
3582 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3584 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3588 * has_tablespace_privilege_name_id
3589 * Check user privileges on a tablespace given
3590 * name usename, tablespace oid, and text priv name.
3593 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
3595 Name username = PG_GETARG_NAME(0);
3596 Oid tablespaceoid = PG_GETARG_OID(1);
3597 text *priv_type_text = PG_GETARG_TEXT_P(2);
3600 AclResult aclresult;
3602 roleid = get_roleid_checked(NameStr(*username));
3603 mode = convert_tablespace_priv_string(priv_type_text);
3605 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3607 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3611 * has_tablespace_privilege_id
3612 * Check user privileges on a tablespace given
3613 * tablespace oid, and text priv name.
3614 * current_user is assumed
3617 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
3619 Oid tablespaceoid = PG_GETARG_OID(0);
3620 text *priv_type_text = PG_GETARG_TEXT_P(1);
3623 AclResult aclresult;
3625 roleid = GetUserId();
3626 mode = convert_tablespace_priv_string(priv_type_text);
3628 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3630 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3634 * has_tablespace_privilege_id_name
3635 * Check user privileges on a tablespace given
3636 * roleid, text tablespacename, and text priv name.
3639 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
3641 Oid roleid = PG_GETARG_OID(0);
3642 text *tablespacename = PG_GETARG_TEXT_P(1);
3643 text *priv_type_text = PG_GETARG_TEXT_P(2);
3646 AclResult aclresult;
3648 tablespaceoid = convert_tablespace_name(tablespacename);
3649 mode = convert_tablespace_priv_string(priv_type_text);
3651 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3653 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3657 * has_tablespace_privilege_id_id
3658 * Check user privileges on a tablespace given
3659 * roleid, tablespace oid, and text priv name.
3662 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
3664 Oid roleid = PG_GETARG_OID(0);
3665 Oid tablespaceoid = PG_GETARG_OID(1);
3666 text *priv_type_text = PG_GETARG_TEXT_P(2);
3668 AclResult aclresult;
3670 mode = convert_tablespace_priv_string(priv_type_text);
3672 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3674 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3678 * Support routines for has_tablespace_privilege family.
3682 * Given a tablespace name expressed as a string, look it up and return Oid
3685 convert_tablespace_name(text *tablespacename)
3687 char *spcname = text_to_cstring(tablespacename);
3690 oid = get_tablespace_oid(spcname);
3692 if (!OidIsValid(oid))
3694 (errcode(ERRCODE_UNDEFINED_OBJECT),
3695 errmsg("tablespace \"%s\" does not exist", spcname)));
3701 * convert_tablespace_priv_string
3702 * Convert text string to AclMode value.
3705 convert_tablespace_priv_string(text *priv_type_text)
3707 static const priv_map tablespace_priv_map[] = {
3708 { "CREATE", ACL_CREATE },
3709 { "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
3713 return convert_any_priv_string(priv_type_text, tablespace_priv_map);
3717 * pg_has_role variants
3718 * These are all named "pg_has_role" at the SQL level.
3719 * They take various combinations of role name, role OID,
3720 * user name, user OID, or implicit user = current_user.
3722 * The result is a boolean value: true if user has the indicated
3723 * privilege, false if not.
3727 * pg_has_role_name_name
3728 * Check user privileges on a role given
3729 * name username, name rolename, and text priv name.
3732 pg_has_role_name_name(PG_FUNCTION_ARGS)
3734 Name username = PG_GETARG_NAME(0);
3735 Name rolename = PG_GETARG_NAME(1);
3736 text *priv_type_text = PG_GETARG_TEXT_P(2);
3740 AclResult aclresult;
3742 roleid = get_roleid_checked(NameStr(*username));
3743 roleoid = get_roleid_checked(NameStr(*rolename));
3744 mode = convert_role_priv_string(priv_type_text);
3746 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3748 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3753 * Check user privileges on a role given
3754 * name rolename and text priv name.
3755 * current_user is assumed
3758 pg_has_role_name(PG_FUNCTION_ARGS)
3760 Name rolename = PG_GETARG_NAME(0);
3761 text *priv_type_text = PG_GETARG_TEXT_P(1);
3765 AclResult aclresult;
3767 roleid = GetUserId();
3768 roleoid = get_roleid_checked(NameStr(*rolename));
3769 mode = convert_role_priv_string(priv_type_text);
3771 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3773 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3777 * pg_has_role_name_id
3778 * Check user privileges on a role given
3779 * name usename, role oid, and text priv name.
3782 pg_has_role_name_id(PG_FUNCTION_ARGS)
3784 Name username = PG_GETARG_NAME(0);
3785 Oid roleoid = PG_GETARG_OID(1);
3786 text *priv_type_text = PG_GETARG_TEXT_P(2);
3789 AclResult aclresult;
3791 roleid = get_roleid_checked(NameStr(*username));
3792 mode = convert_role_priv_string(priv_type_text);
3794 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3796 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3801 * Check user privileges on a role given
3802 * role oid, and text priv name.
3803 * current_user is assumed
3806 pg_has_role_id(PG_FUNCTION_ARGS)
3808 Oid roleoid = PG_GETARG_OID(0);
3809 text *priv_type_text = PG_GETARG_TEXT_P(1);
3812 AclResult aclresult;
3814 roleid = GetUserId();
3815 mode = convert_role_priv_string(priv_type_text);
3817 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3819 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3823 * pg_has_role_id_name
3824 * Check user privileges on a role given
3825 * roleid, name rolename, and text priv name.
3828 pg_has_role_id_name(PG_FUNCTION_ARGS)
3830 Oid roleid = PG_GETARG_OID(0);
3831 Name rolename = PG_GETARG_NAME(1);
3832 text *priv_type_text = PG_GETARG_TEXT_P(2);
3835 AclResult aclresult;
3837 roleoid = get_roleid_checked(NameStr(*rolename));
3838 mode = convert_role_priv_string(priv_type_text);
3840 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3842 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3847 * Check user privileges on a role given
3848 * roleid, role oid, and text priv name.
3851 pg_has_role_id_id(PG_FUNCTION_ARGS)
3853 Oid roleid = PG_GETARG_OID(0);
3854 Oid roleoid = PG_GETARG_OID(1);
3855 text *priv_type_text = PG_GETARG_TEXT_P(2);
3857 AclResult aclresult;
3859 mode = convert_role_priv_string(priv_type_text);
3861 aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3863 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3867 * Support routines for pg_has_role family.
3871 * convert_role_priv_string
3872 * Convert text string to AclMode value.
3874 * We use USAGE to denote whether the privileges of the role are accessible
3875 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
3876 * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
3877 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
3878 * is shared only with pg_role_aclcheck, below.
3881 convert_role_priv_string(text *priv_type_text)
3883 static const priv_map role_priv_map[] = {
3884 { "USAGE", ACL_USAGE },
3885 { "MEMBER", ACL_CREATE },
3886 { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
3887 { "USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
3888 { "MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
3889 { "MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
3893 return convert_any_priv_string(priv_type_text, role_priv_map);
3898 * Quick-and-dirty support for pg_has_role
3901 pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
3903 if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
3905 if (is_admin_of_role(roleid, role_oid))
3908 if (mode & ACL_CREATE)
3910 if (is_member_of_role(roleid, role_oid))
3913 if (mode & ACL_USAGE)
3915 if (has_privs_of_role(roleid, role_oid))
3918 return ACLCHECK_NO_PRIV;
3923 * initialization function (called by InitPostgres)
3926 initialize_acl(void)
3928 if (!IsBootstrapProcessingMode())
3931 * In normal mode, set a callback on any syscache invalidation of
3932 * pg_auth_members rows
3934 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
3935 RoleMembershipCacheCallback,
3941 * RoleMembershipCacheCallback
3942 * Syscache inval callback function
3945 RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
3947 /* Force membership caches to be recomputed on next use */
3948 cached_privs_role = InvalidOid;
3949 cached_member_role = InvalidOid;
3953 /* Check if specified role has rolinherit set */
3955 has_rolinherit(Oid roleid)
3957 bool result = false;
3960 utup = SearchSysCache(AUTHOID,
3961 ObjectIdGetDatum(roleid),
3963 if (HeapTupleIsValid(utup))
3965 result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
3966 ReleaseSysCache(utup);
3973 * Get a list of roles that the specified roleid has the privileges of
3975 * This is defined not to recurse through roles that don't have rolinherit
3976 * set; for such roles, membership implies the ability to do SET ROLE, but
3977 * the privileges are not available until you've done so.
3979 * Since indirect membership testing is relatively expensive, we cache
3980 * a list of memberships. Hence, the result is only guaranteed good until
3981 * the next call of roles_has_privs_of()!
3983 * For the benefit of select_best_grantor, the result is defined to be
3984 * in breadth-first order, ie, closer relationships earlier.
3987 roles_has_privs_of(Oid roleid)
3991 List *new_cached_privs_roles;
3992 MemoryContext oldctx;
3994 /* If cache is already valid, just return the list */
3995 if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
3996 return cached_privs_roles;
3999 * Find all the roles that roleid is a member of, including multi-level
4000 * recursion. The role itself will always be the first element of the
4003 * Each element of the list is scanned to see if it adds any indirect
4004 * memberships. We can use a single list as both the record of
4005 * already-found memberships and the agenda of roles yet to be scanned.
4006 * This is a bit tricky but works because the foreach() macro doesn't
4007 * fetch the next list element until the bottom of the loop.
4009 roles_list = list_make1_oid(roleid);
4011 foreach(l, roles_list)
4013 Oid memberid = lfirst_oid(l);
4017 /* Ignore non-inheriting roles */
4018 if (!has_rolinherit(memberid))
4021 /* Find roles that memberid is directly a member of */
4022 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
4023 ObjectIdGetDatum(memberid),
4025 for (i = 0; i < memlist->n_members; i++)
4027 HeapTuple tup = &memlist->members[i]->tuple;
4028 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
4031 * Even though there shouldn't be any loops in the membership
4032 * graph, we must test for having already seen this role. It is
4033 * legal for instance to have both A->B and A->C->B.
4035 roles_list = list_append_unique_oid(roles_list, otherid);
4037 ReleaseSysCacheList(memlist);
4041 * Copy the completed list into TopMemoryContext so it will persist.
4043 oldctx = MemoryContextSwitchTo(TopMemoryContext);
4044 new_cached_privs_roles = list_copy(roles_list);
4045 MemoryContextSwitchTo(oldctx);
4046 list_free(roles_list);
4049 * Now safe to assign to state variable
4051 cached_privs_role = InvalidOid; /* just paranoia */
4052 list_free(cached_privs_roles);
4053 cached_privs_roles = new_cached_privs_roles;
4054 cached_privs_role = roleid;
4056 /* And now we can return the answer */
4057 return cached_privs_roles;
4062 * Get a list of roles that the specified roleid is a member of
4064 * This is defined to recurse through roles regardless of rolinherit.
4066 * Since indirect membership testing is relatively expensive, we cache
4067 * a list of memberships. Hence, the result is only guaranteed good until
4068 * the next call of roles_is_member_of()!
4071 roles_is_member_of(Oid roleid)
4075 List *new_cached_membership_roles;
4076 MemoryContext oldctx;
4078 /* If cache is already valid, just return the list */
4079 if (OidIsValid(cached_member_role) && cached_member_role == roleid)
4080 return cached_membership_roles;
4083 * Find all the roles that roleid is a member of, including multi-level
4084 * recursion. The role itself will always be the first element of the
4087 * Each element of the list is scanned to see if it adds any indirect
4088 * memberships. We can use a single list as both the record of
4089 * already-found memberships and the agenda of roles yet to be scanned.
4090 * This is a bit tricky but works because the foreach() macro doesn't
4091 * fetch the next list element until the bottom of the loop.
4093 roles_list = list_make1_oid(roleid);
4095 foreach(l, roles_list)
4097 Oid memberid = lfirst_oid(l);
4101 /* Find roles that memberid is directly a member of */
4102 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
4103 ObjectIdGetDatum(memberid),
4105 for (i = 0; i < memlist->n_members; i++)
4107 HeapTuple tup = &memlist->members[i]->tuple;
4108 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
4111 * Even though there shouldn't be any loops in the membership
4112 * graph, we must test for having already seen this role. It is
4113 * legal for instance to have both A->B and A->C->B.
4115 roles_list = list_append_unique_oid(roles_list, otherid);
4117 ReleaseSysCacheList(memlist);
4121 * Copy the completed list into TopMemoryContext so it will persist.
4123 oldctx = MemoryContextSwitchTo(TopMemoryContext);
4124 new_cached_membership_roles = list_copy(roles_list);
4125 MemoryContextSwitchTo(oldctx);
4126 list_free(roles_list);
4129 * Now safe to assign to state variable
4131 cached_member_role = InvalidOid; /* just paranoia */
4132 list_free(cached_membership_roles);
4133 cached_membership_roles = new_cached_membership_roles;
4134 cached_member_role = roleid;
4136 /* And now we can return the answer */
4137 return cached_membership_roles;
4142 * Does member have the privileges of role (directly or indirectly)?
4144 * This is defined not to recurse through roles that don't have rolinherit
4145 * set; for such roles, membership implies the ability to do SET ROLE, but
4146 * the privileges are not available until you've done so.
4149 has_privs_of_role(Oid member, Oid role)
4151 /* Fast path for simple case */
4155 /* Superusers have every privilege, so are part of every role */
4156 if (superuser_arg(member))
4160 * Find all the roles that member has the privileges of, including
4161 * multi-level recursion, then see if target role is any one of them.
4163 return list_member_oid(roles_has_privs_of(member), role);
4168 * Is member a member of role (directly or indirectly)?
4170 * This is defined to recurse through roles regardless of rolinherit.
4173 is_member_of_role(Oid member, Oid role)
4175 /* Fast path for simple case */
4179 /* Superusers have every privilege, so are part of every role */
4180 if (superuser_arg(member))
4184 * Find all the roles that member is a member of, including multi-level
4185 * recursion, then see if target role is any one of them.
4187 return list_member_oid(roles_is_member_of(member), role);
4191 * check_is_member_of_role
4192 * is_member_of_role with a standard permission-violation error if not
4195 check_is_member_of_role(Oid member, Oid role)
4197 if (!is_member_of_role(member, role))
4199 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4200 errmsg("must be member of role \"%s\"",
4201 GetUserNameFromId(role))));
4205 * Is member a member of role, not considering superuserness?
4207 * This is identical to is_member_of_role except we ignore superuser
4211 is_member_of_role_nosuper(Oid member, Oid role)
4213 /* Fast path for simple case */
4218 * Find all the roles that member is a member of, including multi-level
4219 * recursion, then see if target role is any one of them.
4221 return list_member_oid(roles_is_member_of(member), role);
4226 * Is member an admin of role (directly or indirectly)? That is, is it
4227 * a member WITH ADMIN OPTION?
4229 * We could cache the result as for is_member_of_role, but currently this
4230 * is not used in any performance-critical paths, so we don't.
4233 is_admin_of_role(Oid member, Oid role)
4235 bool result = false;
4239 /* Fast path for simple case */
4243 /* Superusers have every privilege, so are part of every role */
4244 if (superuser_arg(member))
4248 * Find all the roles that member is a member of, including multi-level
4249 * recursion. We build a list in the same way that is_member_of_role does
4250 * to track visited and unvisited roles.
4252 roles_list = list_make1_oid(member);
4254 foreach(l, roles_list)
4256 Oid memberid = lfirst_oid(l);
4260 /* Find roles that memberid is directly a member of */
4261 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
4262 ObjectIdGetDatum(memberid),
4264 for (i = 0; i < memlist->n_members; i++)
4266 HeapTuple tup = &memlist->members[i]->tuple;
4267 Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
4269 if (otherid == role &&
4270 ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
4272 /* Found what we came for, so can stop searching */
4277 roles_list = list_append_unique_oid(roles_list, otherid);
4279 ReleaseSysCacheList(memlist);
4284 list_free(roles_list);
4290 /* does what it says ... */
4292 count_one_bits(AclMode mask)
4296 /* this code relies on AclMode being an unsigned type */
4308 * Select the effective grantor ID for a GRANT or REVOKE operation.
4310 * The grantor must always be either the object owner or some role that has
4311 * been explicitly granted grant options. This ensures that all granted
4312 * privileges appear to flow from the object owner, and there are never
4313 * multiple "original sources" of a privilege. Therefore, if the would-be
4314 * grantor is a member of a role that has the needed grant options, we have
4315 * to do the grant as that role instead.
4317 * It is possible that the would-be grantor is a member of several roles
4318 * that have different subsets of the desired grant options, but no one
4319 * role has 'em all. In this case we pick a role with the largest number
4320 * of desired options. Ties are broken in favor of closer ancestors.
4322 * roleId: the role attempting to do the GRANT/REVOKE
4323 * privileges: the privileges to be granted/revoked
4324 * acl: the ACL of the object in question
4325 * ownerId: the role owning the object in question
4326 * *grantorId: receives the OID of the role to do the grant as
4327 * *grantOptions: receives the grant options actually held by grantorId
4329 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
4332 select_best_grantor(Oid roleId, AclMode privileges,
4333 const Acl *acl, Oid ownerId,
4334 Oid *grantorId, AclMode *grantOptions)
4336 AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
4342 * The object owner is always treated as having all grant options, so if
4343 * roleId is the owner it's easy. Also, if roleId is a superuser it's
4344 * easy: superusers are implicitly members of every role, so they act as
4347 if (roleId == ownerId || superuser_arg(roleId))
4349 *grantorId = ownerId;
4350 *grantOptions = needed_goptions;
4355 * Otherwise we have to do a careful search to see if roleId has the
4356 * privileges of any suitable role. Note: we can hang onto the result of
4357 * roles_has_privs_of() throughout this loop, because aclmask_direct()
4358 * doesn't query any role memberships.
4360 roles_list = roles_has_privs_of(roleId);
4362 /* initialize candidate result as default */
4363 *grantorId = roleId;
4364 *grantOptions = ACL_NO_RIGHTS;
4367 foreach(l, roles_list)
4369 Oid otherrole = lfirst_oid(l);
4372 otherprivs = aclmask_direct(acl, otherrole, ownerId,
4373 needed_goptions, ACLMASK_ALL);
4374 if (otherprivs == needed_goptions)
4376 /* Found a suitable grantor */
4377 *grantorId = otherrole;
4378 *grantOptions = otherprivs;
4383 * If it has just some of the needed privileges, remember best
4386 if (otherprivs != ACL_NO_RIGHTS)
4388 int nnewrights = count_one_bits(otherprivs);
4390 if (nnewrights > nrights)
4392 *grantorId = otherrole;
4393 *grantOptions = otherprivs;
4394 nrights = nnewrights;