1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.115 2005/06/28 05:09:00 tgl Exp $
13 *-------------------------------------------------------------------------
19 #include "catalog/namespace.h"
20 #include "catalog/pg_authid.h"
21 #include "catalog/pg_auth_members.h"
22 #include "catalog/pg_type.h"
23 #include "commands/dbcommands.h"
24 #include "commands/tablespace.h"
25 #include "miscadmin.h"
26 #include "utils/acl.h"
27 #include "utils/builtins.h"
28 #include "utils/catcache.h"
29 #include "utils/inval.h"
30 #include "utils/lsyscache.h"
31 #include "utils/memutils.h"
32 #include "utils/syscache.h"
35 #define ACL_IDTYPE_ROLE_KEYWORD "role"
37 /* The rolmemcache is a possibly-empty list of role OIDs.
38 * rolmemRole is the Role for which the cache was generated.
39 * In the event of a Role change the cache will be regenerated.
41 static List *rolmemcache = NIL;
42 static Oid rolmemRole = InvalidOid;
44 /* rolmemcache and rolmemRole only valid when
45 * rolmemcacheValid is true */
46 static bool rolmemcacheValid = false;
48 static const char *getid(const char *s, char *n);
49 static void putid(char *p, const char *s);
50 static Acl *allocacl(int n);
51 static const char *aclparse(const char *s, AclItem *aip);
52 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
53 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
55 static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
56 Oid ownerId, DropBehavior behavior);
58 static AclMode convert_priv_string(text *priv_type_text);
60 static Oid convert_table_name(text *tablename);
61 static AclMode convert_table_priv_string(text *priv_type_text);
62 static Oid convert_database_name(text *databasename);
63 static AclMode convert_database_priv_string(text *priv_type_text);
64 static Oid convert_function_name(text *functionname);
65 static AclMode convert_function_priv_string(text *priv_type_text);
66 static Oid convert_language_name(text *languagename);
67 static AclMode convert_language_priv_string(text *priv_type_text);
68 static Oid convert_schema_name(text *schemaname);
69 static AclMode convert_schema_priv_string(text *priv_type_text);
70 static Oid convert_tablespace_name(text *tablespacename);
71 static AclMode convert_tablespace_priv_string(text *priv_type_text);
73 static void RolMemCacheCallback(Datum arg, Oid relid);
74 static void recomputeRolMemCache(Oid roleid);
79 * Consumes the first alphanumeric string (identifier) found in string
80 * 's', ignoring any leading white space. If it finds a double quote
81 * it returns the word inside the quotes.
84 * the string position in 's' that points to the next non-space character
85 * in 's', after any quotes. Also:
86 * - loads the identifier into 'n'. (If no identifier is found, 'n'
87 * contains an empty string.) 'n' must be NAMEDATALEN bytes.
90 getid(const char *s, char *n)
93 bool in_quotes = false;
97 while (isspace((unsigned char) *s))
99 /* This code had better match what putid() does, below */
102 (isalnum((unsigned char) *s) ||
110 /* safe to look at next char (could be '\0' though) */
113 in_quotes = !in_quotes;
116 /* it's an escaped double quote; skip the escaping char */
120 /* Add the character to the string */
121 if (len >= NAMEDATALEN - 1)
123 (errcode(ERRCODE_NAME_TOO_LONG),
124 errmsg("identifier too long"),
125 errdetail("Identifier must be less than %d characters.",
131 while (isspace((unsigned char) *s))
137 * Write a user or group Name at *p, adding double quotes if needed.
138 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
139 * This needs to be kept in sync with copyAclUserName in pg_dump/dumputils.c
142 putid(char *p, const char *s)
147 for (src = s; *src; src++)
149 /* This test had better match what getid() does, above */
150 if (!isalnum((unsigned char) *src) && *src != '_')
158 for (src = s; *src; src++)
160 /* A double quote character in a username is encoded as "" */
172 * Consumes and parses an ACL specification of the form:
173 * [group|user] [A-Za-z0-9]*=[rwaR]*
174 * from string 's', ignoring any leading white space or white space
175 * between the optional id type keyword (group|user) and the actual
178 * This routine is called by the parser as well as aclitemin(), hence
179 * the added generality.
182 * the string position in 's' immediately following the ACL
183 * specification. Also:
184 * - loads the structure pointed to by 'aip' with the appropriate
185 * UID/GID, id type identifier and mode type values.
188 aclparse(const char *s, AclItem *aip)
193 char name[NAMEDATALEN];
194 char name2[NAMEDATALEN];
199 elog(LOG, "aclparse: input = \"%s\"", s);
204 /* we just read a keyword, not a name */
205 if (strcmp(name, ACL_IDTYPE_ROLE_KEYWORD) != 0)
207 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
208 errmsg("unrecognized key word: \"%s\"", name),
209 errhint("ACL key word must be \"role\".")));
210 s = getid(s, name); /* move s to the name beyond the keyword */
213 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
214 errmsg("missing name"),
215 errhint("A name must follow the \"role\" key word.")));
220 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
221 errmsg("missing \"=\" sign")));
223 privs = goption = ACL_NO_RIGHTS;
225 for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
247 case ACL_REFERENCES_CHR:
248 read = ACL_REFERENCES;
250 case ACL_TRIGGER_CHR:
253 case ACL_EXECUTE_CHR:
262 case ACL_CREATE_TEMP_CHR:
263 read = ACL_CREATE_TEMP;
267 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
268 errmsg("invalid mode character: must be one of \"%s\"",
269 ACL_ALL_RIGHTS_STR)));
276 aip->ai_grantee = ACL_ID_PUBLIC;
278 aip->ai_grantee = get_roleid_checked(name);
281 * XXX Allow a degree of backward compatibility by defaulting the
282 * grantor to the superuser.
286 s = getid(s + 1, name2);
287 if (name2[0] == '\0')
289 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
290 errmsg("a name must follow the \"/\" sign")));
291 aip->ai_grantor = get_roleid_checked(name2);
295 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
297 (errcode(ERRCODE_INVALID_GRANTOR),
298 errmsg("defaulting grantor to user ID %u",
299 BOOTSTRAP_SUPERUSERID)));
302 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
305 elog(LOG, "aclparse: correctly read [%u %x %x]",
306 aip->ai_grantee, privs, goption);
314 * Allocates storage for a new Acl with 'n' entries.
326 elog(ERROR, "invalid size: %d", n);
327 size = ACL_N_SIZE(n);
328 new_acl = (Acl *) palloc0(size);
329 new_acl->size = size;
332 new_acl->elemtype = ACLITEMOID;
333 ARR_LBOUND(new_acl)[0] = 1;
334 ARR_DIMS(new_acl)[0] = n;
340 * Allocates storage for, and fills in, a new AclItem given a string
341 * 's' that contains an ACL specification. See aclparse for details.
347 aclitemin(PG_FUNCTION_ARGS)
349 const char *s = PG_GETARG_CSTRING(0);
352 aip = (AclItem *) palloc(sizeof(AclItem));
353 s = aclparse(s, aip);
354 while (isspace((unsigned char) *s))
358 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
359 errmsg("extra garbage at the end of the ACL specification")));
361 PG_RETURN_ACLITEM_P(aip);
366 * Allocates storage for, and fills in, a new null-delimited string
367 * containing a formatted ACL specification. See aclparse for details.
373 aclitemout(PG_FUNCTION_ARGS)
375 AclItem *aip = PG_GETARG_ACLITEM_P(0);
381 out = palloc(strlen("group =/") +
383 2 * (2 * NAMEDATALEN + 2) +
389 if (aip->ai_grantee != ACL_ID_PUBLIC)
391 htup = SearchSysCache(AUTHOID,
392 ObjectIdGetDatum(aip->ai_grantee),
394 if (HeapTupleIsValid(htup))
396 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
397 ReleaseSysCache(htup);
401 /* Generate numeric OID if we don't find an entry */
402 sprintf(p, "%u", aip->ai_grantee);
410 for (i = 0; i < N_ACL_RIGHTS; ++i)
412 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
413 *p++ = ACL_ALL_RIGHTS_STR[i];
414 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
421 htup = SearchSysCache(AUTHOID,
422 ObjectIdGetDatum(aip->ai_grantor),
424 if (HeapTupleIsValid(htup))
426 putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
427 ReleaseSysCache(htup);
431 /* Generate numeric OID if we don't find an entry */
432 sprintf(p, "%u", aip->ai_grantor);
439 PG_RETURN_CSTRING(out);
444 * Two AclItems are considered to match iff they have the same
445 * grantee and grantor; the privileges are ignored.
448 aclitem_match(const AclItem *a1, const AclItem *a2)
450 return a1->ai_grantee == a2->ai_grantee &&
451 a1->ai_grantor == a2->ai_grantor;
455 * aclitem equality operator
458 aclitem_eq(PG_FUNCTION_ARGS)
460 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
461 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
464 result = a1->ai_privs == a2->ai_privs &&
465 a1->ai_grantee == a2->ai_grantee &&
466 a1->ai_grantor == a2->ai_grantor;
467 PG_RETURN_BOOL(result);
471 * aclitem hash function
473 * We make aclitems hashable not so much because anyone is likely to hash
474 * them, as because we want array equality to work on aclitem arrays, and
475 * with the typcache mechanism we must have a hash or btree opclass.
478 hash_aclitem(PG_FUNCTION_ARGS)
480 AclItem *a = PG_GETARG_ACLITEM_P(0);
482 /* not very bright, but avoids any issue of padding in struct */
483 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
488 * acldefault() --- create an ACL describing default access permissions
490 * Change this routine if you want to alter the default access policy for
491 * newly-created objects (or any object with a NULL acl entry).
494 acldefault(GrantObjectType objtype, Oid ownerId)
496 AclMode world_default;
497 AclMode owner_default;
503 case ACL_OBJECT_RELATION:
504 world_default = ACL_NO_RIGHTS;
505 owner_default = ACL_ALL_RIGHTS_RELATION;
507 case ACL_OBJECT_DATABASE:
508 world_default = ACL_CREATE_TEMP; /* not NO_RIGHTS! */
509 owner_default = ACL_ALL_RIGHTS_DATABASE;
511 case ACL_OBJECT_FUNCTION:
512 /* Grant EXECUTE by default, for now */
513 world_default = ACL_EXECUTE;
514 owner_default = ACL_ALL_RIGHTS_FUNCTION;
516 case ACL_OBJECT_LANGUAGE:
517 /* Grant USAGE by default, for now */
518 world_default = ACL_USAGE;
519 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
521 case ACL_OBJECT_NAMESPACE:
522 world_default = ACL_NO_RIGHTS;
523 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
525 case ACL_OBJECT_TABLESPACE:
526 world_default = ACL_NO_RIGHTS;
527 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
530 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
531 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
532 owner_default = ACL_NO_RIGHTS;
536 acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);
539 if (world_default != ACL_NO_RIGHTS)
541 aip->ai_grantee = ACL_ID_PUBLIC;
542 aip->ai_grantor = ownerId;
543 ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
548 * Note that the owner's entry shows all ordinary privileges but no
549 * grant options. This is because his grant options come "from the
550 * system" and not from his own efforts. (The SQL spec says that the
551 * owner's rights come from a "_SYSTEM" authid.) However, we do
552 * consider that the owner's ordinary privileges are self-granted;
553 * this lets him revoke them. We implement the owner's grant options
554 * without any explicit "_SYSTEM"-like ACL entry, by internally
555 * special-casing the owner whereever we are testing grant options.
557 aip->ai_grantee = ownerId;
558 aip->ai_grantor = ownerId;
559 ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
566 * Update an ACL array to add or remove specified privileges.
568 * old_acl: the input ACL array
569 * mod_aip: defines the privileges to be added, removed, or substituted
570 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
571 * ownerId: Oid of object owner
572 * behavior: RESTRICT or CASCADE behavior for recursive removal
574 * ownerid and behavior are only relevant when the update operation specifies
575 * deletion of grant options.
577 * The result is a modified copy; the input object is not changed.
579 * NB: caller is responsible for having detoasted the input ACL, if needed.
582 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
583 int modechg, Oid ownerId, DropBehavior behavior)
595 /* These checks for null input are probably dead code, but... */
596 if (!old_acl || ACL_NUM(old_acl) < 0)
597 old_acl = allocacl(0);
600 new_acl = allocacl(ACL_NUM(old_acl));
601 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
605 /* If granting grant options, check for circularity */
606 if (modechg != ACL_MODECHG_DEL &&
607 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
608 check_circularity(old_acl, mod_aip, ownerId);
610 num = ACL_NUM(old_acl);
611 old_aip = ACL_DAT(old_acl);
614 * Search the ACL for an existing entry for this grantee and grantor.
615 * If one exists, just modify the entry in-place (well, in the same
616 * position, since we actually return a copy); otherwise, insert the
617 * new entry at the end.
620 for (dst = 0; dst < num; ++dst)
622 if (aclitem_match(mod_aip, old_aip + dst))
624 /* found a match, so modify existing item */
625 new_acl = allocacl(num);
626 new_aip = ACL_DAT(new_acl);
627 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
634 /* need to append a new item */
635 new_acl = allocacl(num + 1);
636 new_aip = ACL_DAT(new_acl);
637 memcpy(new_aip, old_aip, num * sizeof(AclItem));
639 /* initialize the new entry with no permissions */
640 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
641 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
642 ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
643 ACL_NO_RIGHTS, ACL_NO_RIGHTS);
644 num++; /* set num to the size of new_acl */
647 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
648 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
650 /* apply the specified permissions change */
653 case ACL_MODECHG_ADD:
654 ACLITEM_SET_RIGHTS(new_aip[dst],
655 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
657 case ACL_MODECHG_DEL:
658 ACLITEM_SET_RIGHTS(new_aip[dst],
659 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
661 case ACL_MODECHG_EQL:
662 ACLITEM_SET_RIGHTS(new_aip[dst],
663 ACLITEM_GET_RIGHTS(*mod_aip));
667 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
668 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
671 * If the adjusted entry has no permissions, delete it from the list.
673 if (new_rights == ACL_NO_RIGHTS)
675 memmove(new_aip + dst,
677 (num - dst - 1) * sizeof(AclItem));
678 ARR_DIMS(new_acl)[0] = num - 1;
679 ARR_SIZE(new_acl) -= sizeof(AclItem);
683 * Remove abandoned privileges (cascading revoke). Currently we can
684 * only handle this when the grantee is not PUBLIC.
686 if ((old_goptions & ~new_goptions) != 0)
688 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
689 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
690 (old_goptions & ~new_goptions),
698 * Update an ACL array to reflect a change of owner to the parent object
700 * old_acl: the input ACL array (must not be NULL)
701 * oldOwnerId: Oid of the old object owner
702 * newOwnerId: Oid of the new object owner
704 * The result is a modified copy; the input object is not changed.
706 * NB: caller is responsible for having detoasted the input ACL, if needed.
709 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
717 bool newpresent = false;
724 * Make a copy of the given ACL, substituting new owner ID for old
725 * wherever it appears as either grantor or grantee. Also note if the
726 * new owner ID is already present.
728 num = ACL_NUM(old_acl);
729 old_aip = ACL_DAT(old_acl);
730 new_acl = allocacl(num);
731 new_aip = ACL_DAT(new_acl);
732 memcpy(new_aip, old_aip, num * sizeof(AclItem));
733 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
735 if (dst_aip->ai_grantor == oldOwnerId)
736 dst_aip->ai_grantor = newOwnerId;
737 else if (dst_aip->ai_grantor == newOwnerId)
739 if (dst_aip->ai_grantee == oldOwnerId)
740 dst_aip->ai_grantee = newOwnerId;
741 else if (dst_aip->ai_grantee == newOwnerId)
746 * If the old ACL contained any references to the new owner, then we
747 * may now have generated an ACL containing duplicate entries. Find
748 * them and merge them so that there are not duplicates. (This is
749 * relatively expensive since we use a stupid O(N^2) algorithm, but
750 * it's unlikely to be the normal case.)
752 * To simplify deletion of duplicate entries, we temporarily leave them
753 * in the array but set their privilege masks to zero; when we reach
754 * such an entry it's just skipped. (Thus, a side effect of this code
755 * will be to remove privilege-free entries, should there be any in
756 * the input.) dst is the next output slot, targ is the currently
757 * considered input slot (always >= dst), and src scans entries to the
758 * right of targ looking for duplicates. Once an entry has been
759 * emitted to dst it is known duplicate-free and need not be
760 * considered anymore.
765 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
767 /* ignore if deleted in an earlier pass */
768 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
770 /* find and merge any duplicates */
771 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
774 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
776 if (aclitem_match(targ_aip, src_aip))
778 ACLITEM_SET_RIGHTS(*targ_aip,
779 ACLITEM_GET_RIGHTS(*targ_aip) |
780 ACLITEM_GET_RIGHTS(*src_aip));
781 /* mark the duplicate deleted */
782 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
785 /* and emit to output */
786 new_aip[dst] = *targ_aip;
789 /* Adjust array size to be 'dst' items */
790 ARR_DIMS(new_acl)[0] = dst;
791 ARR_SIZE(new_acl) = ACL_N_SIZE(dst);
799 * When granting grant options, we must disallow attempts to set up circular
800 * chains of grant options. Suppose A (the object owner) grants B some
801 * privileges with grant option, and B re-grants them to C. If C could
802 * grant the privileges to B as well, then A would be unable to effectively
803 * revoke the privileges from B, since recursive_revoke would consider that
804 * B still has 'em from C.
806 * We check for this by recursively deleting all grant options belonging to
807 * the target grantee, and then seeing if the would-be grantor still has the
808 * grant option or not.
811 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
821 * For now, grant options can only be granted to roles, not PUBLIC.
822 * Otherwise we'd have to work a bit harder here.
824 Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
826 /* The owner always has grant options, no need to check */
827 if (mod_aip->ai_grantor == ownerId)
830 /* Make a working copy */
831 acl = allocacl(ACL_NUM(old_acl));
832 memcpy(acl, old_acl, ACL_SIZE(old_acl));
834 /* Zap all grant options of target grantee, plus what depends on 'em */
838 for (i = 0; i < num; i++)
840 if (aip[i].ai_grantee == mod_aip->ai_grantee &&
841 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
845 /* We'll actually zap ordinary privs too, but no matter */
846 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
847 ownerId, DROP_CASCADE);
856 /* Now we can compute grantor's independently-derived privileges */
857 own_privs = aclmask(acl,
860 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
862 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
864 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
866 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
867 errmsg("grant options cannot be granted back to your own grantor")));
874 * Ensure that no privilege is "abandoned". A privilege is abandoned
875 * if the user that granted the privilege loses the grant option. (So
876 * the chain through which it was granted is broken.) Either the
877 * abandoned privileges are revoked as well, or an error message is
878 * printed, depending on the drop behavior option.
880 * acl: the input ACL list
881 * grantee: the user from whom some grant options have been revoked
882 * revoke_privs: the grant options being revoked
883 * ownerId: Oid of object owner
884 * behavior: RESTRICT or CASCADE behavior for recursive removal
886 * The input Acl object is pfree'd if replaced.
889 recursive_revoke(Acl *acl,
891 AclMode revoke_privs,
893 DropBehavior behavior)
900 /* The owner can never truly lose grant options, so short-circuit */
901 if (grantee == ownerId)
904 /* The grantee might still have the privileges via another grantor */
905 still_has = aclmask(acl, grantee, ownerId,
906 ACL_GRANT_OPTION_FOR(revoke_privs),
908 revoke_privs &= ~still_has;
909 if (revoke_privs == ACL_NO_RIGHTS)
915 for (i = 0; i < num; i++)
917 if (aip[i].ai_grantor == grantee
918 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
923 if (behavior == DROP_RESTRICT)
925 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
926 errmsg("dependent privileges exist"),
927 errhint("Use CASCADE to revoke them too.")));
929 mod_acl.ai_grantor = grantee;
930 mod_acl.ai_grantee = aip[i].ai_grantee;
931 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
935 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
950 * aclmask --- compute bitmask of all privileges held by roleid.
952 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
953 * held by the given roleid according to the given ACL list, ANDed
954 * with 'mask'. (The point of passing 'mask' is to let the routine
955 * exit early if all privileges of interest have been found.)
957 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
958 * is known true. (This lets us exit soonest in cases where the
959 * caller is only going to test for zero or nonzero result.)
963 * To see if any of a set of privileges are held:
964 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
966 * To see if all of a set of privileges are held:
967 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
969 * To determine exactly which of a set of privileges are held:
970 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
974 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
975 AclMode mask, AclMaskHow how)
983 * Null ACL should not happen, since caller should have inserted
984 * appropriate default
987 elog(ERROR, "null ACL");
989 /* Quick exit for mask == 0 */
995 /* Owner always implicitly has all grant options */
996 if (is_member_of_role(roleid,ownerId))
998 result = mask & ACLITEM_ALL_GOPTION_BITS;
1004 aidat = ACL_DAT(acl);
1007 * Check privileges granted directly to role, indirectly
1008 * via role membership or to public
1010 for (i = 0; i < num; i++)
1012 AclItem *aidata = &aidat[i];
1014 if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1015 is_member_of_role(roleid, aidata->ai_grantee))
1017 result |= (aidata->ai_privs & mask);
1018 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1028 * Is member a member of role?
1029 * relmemcache includes the role itself too
1032 is_member_of_role(Oid member, Oid role)
1034 /* Fast path for simple case */
1038 recomputeRolMemCache(member);
1040 return list_member_oid(rolmemcache, role);
1045 * aclinsert (exported function)
1048 aclinsert(PG_FUNCTION_ARGS)
1051 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1052 errmsg("aclinsert is no longer supported")));
1054 PG_RETURN_NULL(); /* keep compiler quiet */
1058 aclremove(PG_FUNCTION_ARGS)
1061 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1062 errmsg("aclremove is no longer supported")));
1064 PG_RETURN_NULL(); /* keep compiler quiet */
1068 aclcontains(PG_FUNCTION_ARGS)
1070 Acl *acl = PG_GETARG_ACL_P(0);
1071 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1077 aidat = ACL_DAT(acl);
1078 for (i = 0; i < num; ++i)
1080 if (aip->ai_grantee == aidat[i].ai_grantee &&
1081 aip->ai_grantor == aidat[i].ai_grantor &&
1082 (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1083 PG_RETURN_BOOL(true);
1085 PG_RETURN_BOOL(false);
1089 makeaclitem(PG_FUNCTION_ARGS)
1091 Oid grantee = PG_GETARG_OID(0);
1092 Oid grantor = PG_GETARG_OID(1);
1093 text *privtext = PG_GETARG_TEXT_P(2);
1094 bool goption = PG_GETARG_BOOL(3);
1098 priv = convert_priv_string(privtext);
1100 aclitem = (AclItem *) palloc(sizeof(AclItem));
1102 aclitem->ai_grantee = grantee;
1103 aclitem->ai_grantor = grantor;
1105 ACLITEM_SET_PRIVS_GOPTIONS(*aclitem, priv,
1106 (goption ? priv : ACL_NO_RIGHTS));
1108 PG_RETURN_ACLITEM_P(aclitem);
1112 convert_priv_string(text *priv_type_text)
1116 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1117 PointerGetDatum(priv_type_text)));
1119 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1121 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1123 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1125 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1127 if (pg_strcasecmp(priv_type, "RULE") == 0)
1129 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1130 return ACL_REFERENCES;
1131 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1133 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1135 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1137 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1139 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1140 return ACL_CREATE_TEMP;
1141 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1142 return ACL_CREATE_TEMP;
1145 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1146 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1147 return ACL_NO_RIGHTS; /* keep compiler quiet */
1152 * has_table_privilege variants
1153 * These are all named "has_table_privilege" at the SQL level.
1154 * They take various combinations of relation name, relation OID,
1155 * user name, user OID, or implicit user = current_user.
1157 * The result is a boolean value: true if user has the indicated
1158 * privilege, false if not.
1162 * has_table_privilege_name_name
1163 * Check user privileges on a table given
1164 * name username, text tablename, and text priv name.
1167 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1169 Name rolename = PG_GETARG_NAME(0);
1170 text *tablename = PG_GETARG_TEXT_P(1);
1171 text *priv_type_text = PG_GETARG_TEXT_P(2);
1175 AclResult aclresult;
1177 roleid = get_roleid_checked(NameStr(*rolename));
1179 tableoid = convert_table_name(tablename);
1180 mode = convert_table_priv_string(priv_type_text);
1182 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1184 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1188 * has_table_privilege_name
1189 * Check user privileges on a table given
1190 * text tablename and text priv name.
1191 * current_user is assumed
1194 has_table_privilege_name(PG_FUNCTION_ARGS)
1196 text *tablename = PG_GETARG_TEXT_P(0);
1197 text *priv_type_text = PG_GETARG_TEXT_P(1);
1201 AclResult aclresult;
1203 roleid = GetUserId();
1204 tableoid = convert_table_name(tablename);
1205 mode = convert_table_priv_string(priv_type_text);
1207 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1209 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1213 * has_table_privilege_name_id
1214 * Check user privileges on a table given
1215 * name usename, table oid, and text priv name.
1218 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1220 Name username = PG_GETARG_NAME(0);
1221 Oid tableoid = PG_GETARG_OID(1);
1222 text *priv_type_text = PG_GETARG_TEXT_P(2);
1225 AclResult aclresult;
1227 roleid = get_roleid_checked(NameStr(*username));
1229 mode = convert_table_priv_string(priv_type_text);
1231 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1233 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1237 * has_table_privilege_id
1238 * Check user privileges on a table given
1239 * table oid, and text priv name.
1240 * current_user is assumed
1243 has_table_privilege_id(PG_FUNCTION_ARGS)
1245 Oid tableoid = PG_GETARG_OID(0);
1246 text *priv_type_text = PG_GETARG_TEXT_P(1);
1249 AclResult aclresult;
1251 roleid = GetUserId();
1252 mode = convert_table_priv_string(priv_type_text);
1254 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1256 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1260 * has_table_privilege_id_name
1261 * Check user privileges on a table given
1262 * roleid, text tablename, and text priv name.
1265 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1267 Oid roleid = PG_GETARG_OID(0);
1268 text *tablename = PG_GETARG_TEXT_P(1);
1269 text *priv_type_text = PG_GETARG_TEXT_P(2);
1272 AclResult aclresult;
1274 tableoid = convert_table_name(tablename);
1275 mode = convert_table_priv_string(priv_type_text);
1277 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1279 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1283 * has_table_privilege_id_id
1284 * Check user privileges on a table given
1285 * roleid, table oid, and text priv name.
1288 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1290 Oid roleid = PG_GETARG_OID(0);
1291 Oid tableoid = PG_GETARG_OID(1);
1292 text *priv_type_text = PG_GETARG_TEXT_P(2);
1294 AclResult aclresult;
1296 mode = convert_table_priv_string(priv_type_text);
1298 aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1300 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1304 * Support routines for has_table_privilege family.
1308 * Given a table name expressed as a string, look it up and return Oid
1311 convert_table_name(text *tablename)
1315 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1317 return RangeVarGetRelid(relrv, false);
1321 * convert_table_priv_string
1322 * Convert text string to AclMode value.
1325 convert_table_priv_string(text *priv_type_text)
1329 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1330 PointerGetDatum(priv_type_text)));
1333 * Return mode from priv_type string
1335 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1337 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1338 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1340 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1342 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1343 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1345 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1347 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1348 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1350 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1352 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1353 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1355 if (pg_strcasecmp(priv_type, "RULE") == 0)
1357 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1358 return ACL_GRANT_OPTION_FOR(ACL_RULE);
1360 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1361 return ACL_REFERENCES;
1362 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1363 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1365 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1367 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1368 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1371 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1372 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1373 return ACL_NO_RIGHTS; /* keep compiler quiet */
1378 * has_database_privilege variants
1379 * These are all named "has_database_privilege" at the SQL level.
1380 * They take various combinations of database name, database OID,
1381 * user name, user OID, or implicit user = current_user.
1383 * The result is a boolean value: true if user has the indicated
1384 * privilege, false if not.
1388 * has_database_privilege_name_name
1389 * Check user privileges on a database given
1390 * name username, text databasename, and text priv name.
1393 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1395 Name username = PG_GETARG_NAME(0);
1396 text *databasename = PG_GETARG_TEXT_P(1);
1397 text *priv_type_text = PG_GETARG_TEXT_P(2);
1401 AclResult aclresult;
1403 roleid = get_roleid_checked(NameStr(*username));
1405 databaseoid = convert_database_name(databasename);
1406 mode = convert_database_priv_string(priv_type_text);
1408 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1410 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1414 * has_database_privilege_name
1415 * Check user privileges on a database given
1416 * text databasename and text priv name.
1417 * current_user is assumed
1420 has_database_privilege_name(PG_FUNCTION_ARGS)
1422 text *databasename = PG_GETARG_TEXT_P(0);
1423 text *priv_type_text = PG_GETARG_TEXT_P(1);
1427 AclResult aclresult;
1429 roleid = GetUserId();
1430 databaseoid = convert_database_name(databasename);
1431 mode = convert_database_priv_string(priv_type_text);
1433 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1435 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1439 * has_database_privilege_name_id
1440 * Check user privileges on a database given
1441 * name usename, database oid, and text priv name.
1444 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1446 Name username = PG_GETARG_NAME(0);
1447 Oid databaseoid = PG_GETARG_OID(1);
1448 text *priv_type_text = PG_GETARG_TEXT_P(2);
1451 AclResult aclresult;
1453 roleid = get_roleid_checked(NameStr(*username));
1455 mode = convert_database_priv_string(priv_type_text);
1457 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1459 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1463 * has_database_privilege_id
1464 * Check user privileges on a database given
1465 * database oid, and text priv name.
1466 * current_user is assumed
1469 has_database_privilege_id(PG_FUNCTION_ARGS)
1471 Oid databaseoid = PG_GETARG_OID(0);
1472 text *priv_type_text = PG_GETARG_TEXT_P(1);
1475 AclResult aclresult;
1477 roleid = GetUserId();
1478 mode = convert_database_priv_string(priv_type_text);
1480 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1482 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1486 * has_database_privilege_id_name
1487 * Check user privileges on a database given
1488 * roleid, text databasename, and text priv name.
1491 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1493 Oid roleid = PG_GETARG_OID(0);
1494 text *databasename = PG_GETARG_TEXT_P(1);
1495 text *priv_type_text = PG_GETARG_TEXT_P(2);
1498 AclResult aclresult;
1500 databaseoid = convert_database_name(databasename);
1501 mode = convert_database_priv_string(priv_type_text);
1503 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1505 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1509 * has_database_privilege_id_id
1510 * Check user privileges on a database given
1511 * roleid, database oid, and text priv name.
1514 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1516 Oid roleid = PG_GETARG_OID(0);
1517 Oid databaseoid = PG_GETARG_OID(1);
1518 text *priv_type_text = PG_GETARG_TEXT_P(2);
1520 AclResult aclresult;
1522 mode = convert_database_priv_string(priv_type_text);
1524 aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
1526 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1530 * Support routines for has_database_privilege family.
1534 * Given a database name expressed as a string, look it up and return Oid
1537 convert_database_name(text *databasename)
1542 dbname = DatumGetCString(DirectFunctionCall1(textout,
1543 PointerGetDatum(databasename)));
1545 oid = get_database_oid(dbname);
1546 if (!OidIsValid(oid))
1548 (errcode(ERRCODE_UNDEFINED_DATABASE),
1549 errmsg("database \"%s\" does not exist", dbname)));
1555 * convert_database_priv_string
1556 * Convert text string to AclMode value.
1559 convert_database_priv_string(text *priv_type_text)
1563 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1564 PointerGetDatum(priv_type_text)));
1567 * Return mode from priv_type string
1569 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1571 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1572 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1574 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1575 return ACL_CREATE_TEMP;
1576 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1577 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1579 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1580 return ACL_CREATE_TEMP;
1581 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1582 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1585 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1586 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1587 return ACL_NO_RIGHTS; /* keep compiler quiet */
1592 * has_function_privilege variants
1593 * These are all named "has_function_privilege" at the SQL level.
1594 * They take various combinations of function name, function OID,
1595 * user name, user OID, or implicit user = current_user.
1597 * The result is a boolean value: true if user has the indicated
1598 * privilege, false if not.
1602 * has_function_privilege_name_name
1603 * Check user privileges on a function given
1604 * name username, text functionname, and text priv name.
1607 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1609 Name username = PG_GETARG_NAME(0);
1610 text *functionname = PG_GETARG_TEXT_P(1);
1611 text *priv_type_text = PG_GETARG_TEXT_P(2);
1615 AclResult aclresult;
1617 roleid = get_roleid_checked(NameStr(*username));
1619 functionoid = convert_function_name(functionname);
1620 mode = convert_function_priv_string(priv_type_text);
1622 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1624 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1628 * has_function_privilege_name
1629 * Check user privileges on a function given
1630 * text functionname and text priv name.
1631 * current_user is assumed
1634 has_function_privilege_name(PG_FUNCTION_ARGS)
1636 text *functionname = PG_GETARG_TEXT_P(0);
1637 text *priv_type_text = PG_GETARG_TEXT_P(1);
1641 AclResult aclresult;
1643 roleid = GetUserId();
1644 functionoid = convert_function_name(functionname);
1645 mode = convert_function_priv_string(priv_type_text);
1647 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1649 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1653 * has_function_privilege_name_id
1654 * Check user privileges on a function given
1655 * name usename, function oid, and text priv name.
1658 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1660 Name username = PG_GETARG_NAME(0);
1661 Oid functionoid = PG_GETARG_OID(1);
1662 text *priv_type_text = PG_GETARG_TEXT_P(2);
1665 AclResult aclresult;
1667 roleid = get_roleid_checked(NameStr(*username));
1669 mode = convert_function_priv_string(priv_type_text);
1671 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1673 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1677 * has_function_privilege_id
1678 * Check user privileges on a function given
1679 * function oid, and text priv name.
1680 * current_user is assumed
1683 has_function_privilege_id(PG_FUNCTION_ARGS)
1685 Oid functionoid = PG_GETARG_OID(0);
1686 text *priv_type_text = PG_GETARG_TEXT_P(1);
1689 AclResult aclresult;
1691 roleid = GetUserId();
1692 mode = convert_function_priv_string(priv_type_text);
1694 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1696 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1700 * has_function_privilege_id_name
1701 * Check user privileges on a function given
1702 * roleid, text functionname, and text priv name.
1705 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1707 Oid roleid = PG_GETARG_OID(0);
1708 text *functionname = PG_GETARG_TEXT_P(1);
1709 text *priv_type_text = PG_GETARG_TEXT_P(2);
1712 AclResult aclresult;
1714 functionoid = convert_function_name(functionname);
1715 mode = convert_function_priv_string(priv_type_text);
1717 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1719 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1723 * has_function_privilege_id_id
1724 * Check user privileges on a function given
1725 * roleid, function oid, and text priv name.
1728 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1730 Oid roleid = PG_GETARG_OID(0);
1731 Oid functionoid = PG_GETARG_OID(1);
1732 text *priv_type_text = PG_GETARG_TEXT_P(2);
1734 AclResult aclresult;
1736 mode = convert_function_priv_string(priv_type_text);
1738 aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
1740 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1744 * Support routines for has_function_privilege family.
1748 * Given a function name expressed as a string, look it up and return Oid
1751 convert_function_name(text *functionname)
1756 funcname = DatumGetCString(DirectFunctionCall1(textout,
1757 PointerGetDatum(functionname)));
1759 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1760 CStringGetDatum(funcname)));
1762 if (!OidIsValid(oid))
1764 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1765 errmsg("function \"%s\" does not exist", funcname)));
1771 * convert_function_priv_string
1772 * Convert text string to AclMode value.
1775 convert_function_priv_string(text *priv_type_text)
1779 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1780 PointerGetDatum(priv_type_text)));
1783 * Return mode from priv_type string
1785 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1787 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1788 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1791 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1792 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1793 return ACL_NO_RIGHTS; /* keep compiler quiet */
1798 * has_language_privilege variants
1799 * These are all named "has_language_privilege" at the SQL level.
1800 * They take various combinations of language name, language OID,
1801 * user name, user OID, or implicit user = current_user.
1803 * The result is a boolean value: true if user has the indicated
1804 * privilege, false if not.
1808 * has_language_privilege_name_name
1809 * Check user privileges on a language given
1810 * name username, text languagename, and text priv name.
1813 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1815 Name username = PG_GETARG_NAME(0);
1816 text *languagename = PG_GETARG_TEXT_P(1);
1817 text *priv_type_text = PG_GETARG_TEXT_P(2);
1821 AclResult aclresult;
1823 roleid = get_roleid_checked(NameStr(*username));
1825 languageoid = convert_language_name(languagename);
1826 mode = convert_language_priv_string(priv_type_text);
1828 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1830 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1834 * has_language_privilege_name
1835 * Check user privileges on a language given
1836 * text languagename and text priv name.
1837 * current_user is assumed
1840 has_language_privilege_name(PG_FUNCTION_ARGS)
1842 text *languagename = PG_GETARG_TEXT_P(0);
1843 text *priv_type_text = PG_GETARG_TEXT_P(1);
1847 AclResult aclresult;
1849 roleid = GetUserId();
1850 languageoid = convert_language_name(languagename);
1851 mode = convert_language_priv_string(priv_type_text);
1853 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1855 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1859 * has_language_privilege_name_id
1860 * Check user privileges on a language given
1861 * name usename, language oid, and text priv name.
1864 has_language_privilege_name_id(PG_FUNCTION_ARGS)
1866 Name username = PG_GETARG_NAME(0);
1867 Oid languageoid = PG_GETARG_OID(1);
1868 text *priv_type_text = PG_GETARG_TEXT_P(2);
1871 AclResult aclresult;
1873 roleid = get_roleid_checked(NameStr(*username));
1875 mode = convert_language_priv_string(priv_type_text);
1877 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1879 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1883 * has_language_privilege_id
1884 * Check user privileges on a language given
1885 * language oid, and text priv name.
1886 * current_user is assumed
1889 has_language_privilege_id(PG_FUNCTION_ARGS)
1891 Oid languageoid = PG_GETARG_OID(0);
1892 text *priv_type_text = PG_GETARG_TEXT_P(1);
1895 AclResult aclresult;
1897 roleid = GetUserId();
1898 mode = convert_language_priv_string(priv_type_text);
1900 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1902 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1906 * has_language_privilege_id_name
1907 * Check user privileges on a language given
1908 * roleid, text languagename, and text priv name.
1911 has_language_privilege_id_name(PG_FUNCTION_ARGS)
1913 Oid roleid = PG_GETARG_OID(0);
1914 text *languagename = PG_GETARG_TEXT_P(1);
1915 text *priv_type_text = PG_GETARG_TEXT_P(2);
1918 AclResult aclresult;
1920 languageoid = convert_language_name(languagename);
1921 mode = convert_language_priv_string(priv_type_text);
1923 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1925 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1929 * has_language_privilege_id_id
1930 * Check user privileges on a language given
1931 * roleid, language oid, and text priv name.
1934 has_language_privilege_id_id(PG_FUNCTION_ARGS)
1936 Oid roleid = PG_GETARG_OID(0);
1937 Oid languageoid = PG_GETARG_OID(1);
1938 text *priv_type_text = PG_GETARG_TEXT_P(2);
1940 AclResult aclresult;
1942 mode = convert_language_priv_string(priv_type_text);
1944 aclresult = pg_language_aclcheck(languageoid, roleid, mode);
1946 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1950 * Support routines for has_language_privilege family.
1954 * Given a language name expressed as a string, look it up and return Oid
1957 convert_language_name(text *languagename)
1962 langname = DatumGetCString(DirectFunctionCall1(textout,
1963 PointerGetDatum(languagename)));
1965 oid = GetSysCacheOid(LANGNAME,
1966 CStringGetDatum(langname),
1968 if (!OidIsValid(oid))
1970 (errcode(ERRCODE_UNDEFINED_OBJECT),
1971 errmsg("language \"%s\" does not exist", langname)));
1977 * convert_language_priv_string
1978 * Convert text string to AclMode value.
1981 convert_language_priv_string(text *priv_type_text)
1985 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1986 PointerGetDatum(priv_type_text)));
1989 * Return mode from priv_type string
1991 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1993 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1994 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
1997 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1998 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1999 return ACL_NO_RIGHTS; /* keep compiler quiet */
2004 * has_schema_privilege variants
2005 * These are all named "has_schema_privilege" at the SQL level.
2006 * They take various combinations of schema name, schema OID,
2007 * user name, user OID, or implicit user = current_user.
2009 * The result is a boolean value: true if user has the indicated
2010 * privilege, false if not.
2014 * has_schema_privilege_name_name
2015 * Check user privileges on a schema given
2016 * name username, text schemaname, and text priv name.
2019 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2021 Name username = PG_GETARG_NAME(0);
2022 text *schemaname = PG_GETARG_TEXT_P(1);
2023 text *priv_type_text = PG_GETARG_TEXT_P(2);
2027 AclResult aclresult;
2029 roleid = get_roleid_checked(NameStr(*username));
2031 schemaoid = convert_schema_name(schemaname);
2032 mode = convert_schema_priv_string(priv_type_text);
2034 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2036 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2040 * has_schema_privilege_name
2041 * Check user privileges on a schema given
2042 * text schemaname and text priv name.
2043 * current_user is assumed
2046 has_schema_privilege_name(PG_FUNCTION_ARGS)
2048 text *schemaname = PG_GETARG_TEXT_P(0);
2049 text *priv_type_text = PG_GETARG_TEXT_P(1);
2053 AclResult aclresult;
2055 roleid = GetUserId();
2056 schemaoid = convert_schema_name(schemaname);
2057 mode = convert_schema_priv_string(priv_type_text);
2059 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2061 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2065 * has_schema_privilege_name_id
2066 * Check user privileges on a schema given
2067 * name usename, schema oid, and text priv name.
2070 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2072 Name username = PG_GETARG_NAME(0);
2073 Oid schemaoid = PG_GETARG_OID(1);
2074 text *priv_type_text = PG_GETARG_TEXT_P(2);
2077 AclResult aclresult;
2079 roleid = get_roleid_checked(NameStr(*username));
2081 mode = convert_schema_priv_string(priv_type_text);
2083 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2085 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2089 * has_schema_privilege_id
2090 * Check user privileges on a schema given
2091 * schema oid, and text priv name.
2092 * current_user is assumed
2095 has_schema_privilege_id(PG_FUNCTION_ARGS)
2097 Oid schemaoid = PG_GETARG_OID(0);
2098 text *priv_type_text = PG_GETARG_TEXT_P(1);
2101 AclResult aclresult;
2103 roleid = GetUserId();
2104 mode = convert_schema_priv_string(priv_type_text);
2106 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2108 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2112 * has_schema_privilege_id_name
2113 * Check user privileges on a schema given
2114 * roleid, text schemaname, and text priv name.
2117 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2119 Oid roleid = PG_GETARG_OID(0);
2120 text *schemaname = PG_GETARG_TEXT_P(1);
2121 text *priv_type_text = PG_GETARG_TEXT_P(2);
2124 AclResult aclresult;
2126 schemaoid = convert_schema_name(schemaname);
2127 mode = convert_schema_priv_string(priv_type_text);
2129 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2131 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2135 * has_schema_privilege_id_id
2136 * Check user privileges on a schema given
2137 * roleid, schema oid, and text priv name.
2140 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2142 Oid roleid = PG_GETARG_OID(0);
2143 Oid schemaoid = PG_GETARG_OID(1);
2144 text *priv_type_text = PG_GETARG_TEXT_P(2);
2146 AclResult aclresult;
2148 mode = convert_schema_priv_string(priv_type_text);
2150 aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
2152 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2156 * Support routines for has_schema_privilege family.
2160 * Given a schema name expressed as a string, look it up and return Oid
2163 convert_schema_name(text *schemaname)
2168 nspname = DatumGetCString(DirectFunctionCall1(textout,
2169 PointerGetDatum(schemaname)));
2171 oid = GetSysCacheOid(NAMESPACENAME,
2172 CStringGetDatum(nspname),
2174 if (!OidIsValid(oid))
2176 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2177 errmsg("schema \"%s\" does not exist", nspname)));
2183 * convert_schema_priv_string
2184 * Convert text string to AclMode value.
2187 convert_schema_priv_string(text *priv_type_text)
2191 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2192 PointerGetDatum(priv_type_text)));
2195 * Return mode from priv_type string
2197 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2199 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2200 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2202 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2204 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2205 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2208 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2209 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2210 return ACL_NO_RIGHTS; /* keep compiler quiet */
2214 * has_tablespace_privilege variants
2215 * These are all named "has_tablespace_privilege" at the SQL level.
2216 * They take various combinations of tablespace name, tablespace OID,
2217 * user name, user OID, or implicit user = current_user.
2219 * The result is a boolean value: true if user has the indicated
2220 * privilege, false if not.
2224 * has_tablespace_privilege_name_name
2225 * Check user privileges on a tablespace given
2226 * name username, text tablespacename, and text priv name.
2229 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2231 Name username = PG_GETARG_NAME(0);
2232 text *tablespacename = PG_GETARG_TEXT_P(1);
2233 text *priv_type_text = PG_GETARG_TEXT_P(2);
2237 AclResult aclresult;
2239 roleid = get_roleid_checked(NameStr(*username));
2241 tablespaceoid = convert_tablespace_name(tablespacename);
2242 mode = convert_tablespace_priv_string(priv_type_text);
2244 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2246 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2250 * has_tablespace_privilege_name
2251 * Check user privileges on a tablespace given
2252 * text tablespacename and text priv name.
2253 * current_user is assumed
2256 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2258 text *tablespacename = PG_GETARG_TEXT_P(0);
2259 text *priv_type_text = PG_GETARG_TEXT_P(1);
2263 AclResult aclresult;
2265 roleid = GetUserId();
2266 tablespaceoid = convert_tablespace_name(tablespacename);
2267 mode = convert_tablespace_priv_string(priv_type_text);
2269 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2271 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2275 * has_tablespace_privilege_name_id
2276 * Check user privileges on a tablespace given
2277 * name usename, tablespace oid, and text priv name.
2280 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2282 Name username = PG_GETARG_NAME(0);
2283 Oid tablespaceoid = PG_GETARG_OID(1);
2284 text *priv_type_text = PG_GETARG_TEXT_P(2);
2287 AclResult aclresult;
2289 roleid = get_roleid_checked(NameStr(*username));
2291 mode = convert_tablespace_priv_string(priv_type_text);
2293 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2295 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2299 * has_tablespace_privilege_id
2300 * Check user privileges on a tablespace given
2301 * tablespace oid, and text priv name.
2302 * current_user is assumed
2305 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2307 Oid tablespaceoid = PG_GETARG_OID(0);
2308 text *priv_type_text = PG_GETARG_TEXT_P(1);
2311 AclResult aclresult;
2313 roleid = GetUserId();
2314 mode = convert_tablespace_priv_string(priv_type_text);
2316 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2318 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2322 * has_tablespace_privilege_id_name
2323 * Check user privileges on a tablespace given
2324 * roleid, text tablespacename, and text priv name.
2327 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2329 Oid roleid = PG_GETARG_OID(0);
2330 text *tablespacename = PG_GETARG_TEXT_P(1);
2331 text *priv_type_text = PG_GETARG_TEXT_P(2);
2334 AclResult aclresult;
2336 tablespaceoid = convert_tablespace_name(tablespacename);
2337 mode = convert_tablespace_priv_string(priv_type_text);
2339 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2341 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2345 * has_tablespace_privilege_id_id
2346 * Check user privileges on a tablespace given
2347 * roleid, tablespace oid, and text priv name.
2350 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2352 Oid roleid = PG_GETARG_OID(0);
2353 Oid tablespaceoid = PG_GETARG_OID(1);
2354 text *priv_type_text = PG_GETARG_TEXT_P(2);
2356 AclResult aclresult;
2358 mode = convert_tablespace_priv_string(priv_type_text);
2360 aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
2362 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2366 * Support routines for has_tablespace_privilege family.
2370 * Given a tablespace name expressed as a string, look it up and return Oid
2373 convert_tablespace_name(text *tablespacename)
2378 spcname = DatumGetCString(DirectFunctionCall1(textout,
2379 PointerGetDatum(tablespacename)));
2380 oid = get_tablespace_oid(spcname);
2382 if (!OidIsValid(oid))
2384 (errcode(ERRCODE_UNDEFINED_OBJECT),
2385 errmsg("tablespace \"%s\" does not exist", spcname)));
2391 * convert_tablespace_priv_string
2392 * Convert text string to AclMode value.
2395 convert_tablespace_priv_string(text *priv_type_text)
2399 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2400 PointerGetDatum(priv_type_text)));
2403 * Return mode from priv_type string
2405 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2407 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2408 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2411 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2412 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2413 return ACL_NO_RIGHTS; /* keep compiler quiet */
2419 if (!IsBootstrapProcessingMode())
2422 * In normal mode, set a callback on any syscache
2423 * invalidation of pg_auth_members rows
2425 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
2426 RolMemCacheCallback,
2429 /* Force role/member cache to be recomputed on next use */
2430 rolmemcacheValid = false;
2435 * RolMemCacheCallback
2436 * Syscache inval callback function
2439 RolMemCacheCallback(Datum arg, Oid relid)
2441 /* Force role/member cache to be recomputed on next use */
2442 rolmemcacheValid = false;
2447 * recomputeRolMemCache - recompute the role/member cache if needed
2450 recomputeRolMemCache(Oid roleid)
2454 List *roles_list_hunt = NIL;
2455 List *roles_list = NIL;
2456 List *newrolmemcache;
2458 MemoryContext oldctx;
2460 /* Do nothing if rolmemcache is already valid */
2461 if (rolmemcacheValid && rolmemRole == roleid)
2464 if (rolmemRole != roleid)
2465 rolmemcacheValid = false;
2468 * Find all the roles which this role is a member of,
2469 * including multi-level recursion
2473 * Include the current role itself to simplify checks
2474 * later on, also should be at the head so lookup should
2477 roles_list = lappend_oid(roles_list, roleid);
2478 roles_list_hunt = lappend_oid(roles_list_hunt, roleid);
2480 while (roles_list_hunt)
2482 memberOid = linitial_oid(roles_list_hunt);
2483 memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
2484 ObjectIdGetDatum(memberOid),
2486 for (i = 0; i < memlist->n_members; i++) {
2487 HeapTuple roletup = &memlist->members[i]->tuple;
2488 Form_pg_auth_members rolemem = (Form_pg_auth_members) GETSTRUCT(roletup);
2490 if (!list_member_oid(roles_list,rolemem->roleid)) {
2491 roles_list = lappend_oid(roles_list,rolemem->roleid);
2492 roles_list_hunt = lappend_oid(roles_list_hunt,rolemem->roleid);
2495 roles_list_hunt = list_delete_oid(roles_list_hunt, memberOid);
2496 ReleaseSysCacheList(memlist);
2500 * Now that we've built the list of role Oids this
2501 * role is a member of, save it in permanent storage
2503 oldctx = MemoryContextSwitchTo(TopMemoryContext);
2504 newrolmemcache = list_copy(roles_list);
2505 MemoryContextSwitchTo(oldctx);
2508 * Now safe to assign to state variable
2510 list_free(rolmemcache);
2511 rolmemcache = newrolmemcache;
2516 rolmemRole = roleid;
2517 rolmemcacheValid = true;
2520 list_free(roles_list);