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.113 2004/12/31 22:01:21 pgsql Exp $
13 *-------------------------------------------------------------------------
19 #include "catalog/namespace.h"
20 #include "catalog/pg_group.h"
21 #include "catalog/pg_shadow.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/lsyscache.h"
29 #include "utils/syscache.h"
32 #define ACL_IDTYPE_GID_KEYWORD "group"
33 #define ACL_IDTYPE_UID_KEYWORD "user"
35 static const char *getid(const char *s, char *n);
36 static void putid(char *p, const char *s);
37 static Acl *allocacl(int n);
38 static const char *aclparse(const char *s, AclItem *aip);
39 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
40 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
42 static Acl *recursive_revoke(Acl *acl, AclId grantee, AclMode revoke_privs,
43 AclId ownerid, DropBehavior behavior);
44 static bool in_group(AclId uid, AclId gid);
46 static AclMode convert_priv_string(text *priv_type_text);
48 static Oid convert_table_name(text *tablename);
49 static AclMode convert_table_priv_string(text *priv_type_text);
50 static Oid convert_database_name(text *databasename);
51 static AclMode convert_database_priv_string(text *priv_type_text);
52 static Oid convert_function_name(text *functionname);
53 static AclMode convert_function_priv_string(text *priv_type_text);
54 static Oid convert_language_name(text *languagename);
55 static AclMode convert_language_priv_string(text *priv_type_text);
56 static Oid convert_schema_name(text *schemaname);
57 static AclMode convert_schema_priv_string(text *priv_type_text);
58 static Oid convert_tablespace_name(text *tablespacename);
59 static AclMode convert_tablespace_priv_string(text *priv_type_text);
64 * Consumes the first alphanumeric string (identifier) found in string
65 * 's', ignoring any leading white space. If it finds a double quote
66 * it returns the word inside the quotes.
69 * the string position in 's' that points to the next non-space character
70 * in 's', after any quotes. Also:
71 * - loads the identifier into 'n'. (If no identifier is found, 'n'
72 * contains an empty string.) 'n' must be NAMEDATALEN bytes.
75 getid(const char *s, char *n)
78 bool in_quotes = false;
82 while (isspace((unsigned char) *s))
84 /* This code had better match what putid() does, below */
87 (isalnum((unsigned char) *s) ||
95 /* safe to look at next char (could be '\0' though) */
98 in_quotes = !in_quotes;
101 /* it's an escaped double quote; skip the escaping char */
105 /* Add the character to the string */
106 if (len >= NAMEDATALEN - 1)
108 (errcode(ERRCODE_NAME_TOO_LONG),
109 errmsg("identifier too long"),
110 errdetail("Identifier must be less than %d characters.",
116 while (isspace((unsigned char) *s))
122 * Write a user or group Name at *p, adding double quotes if needed.
123 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
124 * This needs to be kept in sync with copyAclUserName in pg_dump/dumputils.c
127 putid(char *p, const char *s)
132 for (src = s; *src; src++)
134 /* This test had better match what getid() does, above */
135 if (!isalnum((unsigned char) *src) && *src != '_')
143 for (src = s; *src; src++)
145 /* A double quote character in a username is encoded as "" */
157 * Consumes and parses an ACL specification of the form:
158 * [group|user] [A-Za-z0-9]*=[rwaR]*
159 * from string 's', ignoring any leading white space or white space
160 * between the optional id type keyword (group|user) and the actual
163 * This routine is called by the parser as well as aclitemin(), hence
164 * the added generality.
167 * the string position in 's' immediately following the ACL
168 * specification. Also:
169 * - loads the structure pointed to by 'aip' with the appropriate
170 * UID/GID, id type identifier and mode type values.
173 aclparse(const char *s, AclItem *aip)
179 char name[NAMEDATALEN];
180 char name2[NAMEDATALEN];
185 elog(LOG, "aclparse: input = \"%s\"", s);
187 idtype = ACL_IDTYPE_UID;
191 /* we just read a keyword, not a name */
192 if (strcmp(name, ACL_IDTYPE_GID_KEYWORD) == 0)
193 idtype = ACL_IDTYPE_GID;
194 else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD) != 0)
196 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
197 errmsg("unrecognized key word: \"%s\"", name),
198 errhint("ACL key word must be \"group\" or \"user\".")));
199 s = getid(s, name); /* move s to the name beyond the keyword */
202 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
203 errmsg("missing name"),
204 errhint("A name must follow the \"group\" or \"user\" key word.")));
207 idtype = ACL_IDTYPE_WORLD;
211 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
212 errmsg("missing \"=\" sign")));
214 privs = goption = ACL_NO_RIGHTS;
216 for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
238 case ACL_REFERENCES_CHR:
239 read = ACL_REFERENCES;
241 case ACL_TRIGGER_CHR:
244 case ACL_EXECUTE_CHR:
253 case ACL_CREATE_TEMP_CHR:
254 read = ACL_CREATE_TEMP;
258 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
259 errmsg("invalid mode character: must be one of \"%s\"",
260 ACL_ALL_RIGHTS_STR)));
269 aip->ai_grantee = get_usesysid(name);
272 aip->ai_grantee = get_grosysid(name);
274 case ACL_IDTYPE_WORLD:
275 aip->ai_grantee = ACL_ID_WORLD;
280 * XXX Allow a degree of backward compatibility by defaulting the
281 * grantor to the superuser.
285 s = getid(s + 1, name2);
286 if (name2[0] == '\0')
288 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
289 errmsg("a name must follow the \"/\" sign")));
291 aip->ai_grantor = get_usesysid(name2);
295 aip->ai_grantor = BOOTSTRAP_USESYSID;
297 (errcode(ERRCODE_INVALID_GRANTOR),
298 errmsg("defaulting grantor to user ID %u", BOOTSTRAP_USESYSID)));
301 ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, goption, idtype);
304 elog(LOG, "aclparse: correctly read [%x %d %x]",
305 idtype, aip->ai_grantee, privs);
312 * Allocates storage for a new Acl with 'n' entries.
324 elog(ERROR, "invalid size: %d", n);
325 size = ACL_N_SIZE(n);
326 new_acl = (Acl *) palloc0(size);
327 new_acl->size = size;
330 new_acl->elemtype = ACLITEMOID;
331 ARR_LBOUND(new_acl)[0] = 1;
332 ARR_DIMS(new_acl)[0] = n;
338 * Allocates storage for, and fills in, a new AclItem given a string
339 * 's' that contains an ACL specification. See aclparse for details.
345 aclitemin(PG_FUNCTION_ARGS)
347 const char *s = PG_GETARG_CSTRING(0);
350 aip = (AclItem *) palloc(sizeof(AclItem));
351 s = aclparse(s, aip);
352 while (isspace((unsigned char) *s))
356 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
357 errmsg("extra garbage at the end of the ACL specification")));
359 PG_RETURN_ACLITEM_P(aip);
364 * Allocates storage for, and fills in, a new null-delimited string
365 * containing a formatted ACL specification. See aclparse for details.
371 aclitemout(PG_FUNCTION_ARGS)
373 AclItem *aip = PG_GETARG_ACLITEM_P(0);
380 out = palloc(strlen("group =/") +
382 2 * (2 * NAMEDATALEN + 2) +
388 switch (ACLITEM_GET_IDTYPE(*aip))
391 htup = SearchSysCache(SHADOWSYSID,
392 ObjectIdGetDatum(aip->ai_grantee),
394 if (HeapTupleIsValid(htup))
396 putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename));
397 ReleaseSysCache(htup);
401 /* Generate numeric UID if we don't find an entry */
402 sprintf(p, "%d", aip->ai_grantee);
408 tmpname = get_groname(aip->ai_grantee);
413 /* Generate numeric GID if we don't find an entry */
414 sprintf(p, "%d", aip->ai_grantee);
417 case ACL_IDTYPE_WORLD:
420 elog(ERROR, "unrecognized idtype: %d",
421 (int) ACLITEM_GET_IDTYPE(*aip));
429 for (i = 0; i < N_ACL_RIGHTS; ++i)
431 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
432 *p++ = ACL_ALL_RIGHTS_STR[i];
433 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
440 htup = SearchSysCache(SHADOWSYSID,
441 ObjectIdGetDatum(aip->ai_grantor),
443 if (HeapTupleIsValid(htup))
445 putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename));
446 ReleaseSysCache(htup);
450 /* Generate numeric UID if we don't find an entry */
451 sprintf(p, "%d", aip->ai_grantor);
458 PG_RETURN_CSTRING(out);
463 * Two AclItems are considered to match iff they have the same
464 * grantee and grantor; the privileges are ignored.
467 aclitem_match(const AclItem *a1, const AclItem *a2)
469 return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
470 a1->ai_grantee == a2->ai_grantee &&
471 a1->ai_grantor == a2->ai_grantor;
475 * aclitem equality operator
478 aclitem_eq(PG_FUNCTION_ARGS)
480 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
481 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
484 result = a1->ai_privs == a2->ai_privs &&
485 a1->ai_grantee == a2->ai_grantee &&
486 a1->ai_grantor == a2->ai_grantor;
487 PG_RETURN_BOOL(result);
491 * aclitem hash function
493 * We make aclitems hashable not so much because anyone is likely to hash
494 * them, as because we want array equality to work on aclitem arrays, and
495 * with the typcache mechanism we must have a hash or btree opclass.
498 hash_aclitem(PG_FUNCTION_ARGS)
500 AclItem *a = PG_GETARG_ACLITEM_P(0);
502 /* not very bright, but avoids any issue of padding in struct */
503 PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
508 * acldefault() --- create an ACL describing default access permissions
510 * Change this routine if you want to alter the default access policy for
511 * newly-created objects (or any object with a NULL acl entry).
514 acldefault(GrantObjectType objtype, AclId ownerid)
516 AclMode world_default;
517 AclMode owner_default;
523 case ACL_OBJECT_RELATION:
524 world_default = ACL_NO_RIGHTS;
525 owner_default = ACL_ALL_RIGHTS_RELATION;
527 case ACL_OBJECT_DATABASE:
528 world_default = ACL_CREATE_TEMP; /* not NO_RIGHTS! */
529 owner_default = ACL_ALL_RIGHTS_DATABASE;
531 case ACL_OBJECT_FUNCTION:
532 /* Grant EXECUTE by default, for now */
533 world_default = ACL_EXECUTE;
534 owner_default = ACL_ALL_RIGHTS_FUNCTION;
536 case ACL_OBJECT_LANGUAGE:
537 /* Grant USAGE by default, for now */
538 world_default = ACL_USAGE;
539 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
541 case ACL_OBJECT_NAMESPACE:
542 world_default = ACL_NO_RIGHTS;
543 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
545 case ACL_OBJECT_TABLESPACE:
546 world_default = ACL_NO_RIGHTS;
547 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
550 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
551 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
552 owner_default = ACL_NO_RIGHTS;
556 acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);
559 if (world_default != ACL_NO_RIGHTS)
561 aip->ai_grantee = ACL_ID_WORLD;
562 aip->ai_grantor = ownerid;
563 ACLITEM_SET_PRIVS_IDTYPE(*aip, world_default, ACL_NO_RIGHTS,
569 * Note that the owner's entry shows all ordinary privileges but no
570 * grant options. This is because his grant options come "from the
571 * system" and not from his own efforts. (The SQL spec says that the
572 * owner's rights come from a "_SYSTEM" authid.) However, we do
573 * consider that the owner's ordinary privileges are self-granted;
574 * this lets him revoke them. We implement the owner's grant options
575 * without any explicit "_SYSTEM"-like ACL entry, by internally
576 * special-casing the owner whereever we are testing grant options.
578 aip->ai_grantee = ownerid;
579 aip->ai_grantor = ownerid;
580 ACLITEM_SET_PRIVS_IDTYPE(*aip, owner_default, ACL_NO_RIGHTS,
588 * Update an ACL array to add or remove specified privileges.
590 * old_acl: the input ACL array
591 * mod_aip: defines the privileges to be added, removed, or substituted
592 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
593 * ownerid: AclId of object owner
594 * behavior: RESTRICT or CASCADE behavior for recursive removal
596 * ownerid and behavior are only relevant when the update operation specifies
597 * deletion of grant options.
599 * The result is a modified copy; the input object is not changed.
601 * NB: caller is responsible for having detoasted the input ACL, if needed.
604 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
605 int modechg, AclId ownerid, DropBehavior behavior)
617 /* These checks for null input are probably dead code, but... */
618 if (!old_acl || ACL_NUM(old_acl) < 0)
619 old_acl = allocacl(0);
622 new_acl = allocacl(ACL_NUM(old_acl));
623 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
627 /* If granting grant options, check for circularity */
628 if (modechg != ACL_MODECHG_DEL &&
629 ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
630 check_circularity(old_acl, mod_aip, ownerid);
632 num = ACL_NUM(old_acl);
633 old_aip = ACL_DAT(old_acl);
636 * Search the ACL for an existing entry for this grantee and grantor.
637 * If one exists, just modify the entry in-place (well, in the same
638 * position, since we actually return a copy); otherwise, insert the
639 * new entry at the end.
642 for (dst = 0; dst < num; ++dst)
644 if (aclitem_match(mod_aip, old_aip + dst))
646 /* found a match, so modify existing item */
647 new_acl = allocacl(num);
648 new_aip = ACL_DAT(new_acl);
649 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
656 /* need to append a new item */
657 new_acl = allocacl(num + 1);
658 new_aip = ACL_DAT(new_acl);
659 memcpy(new_aip, old_aip, num * sizeof(AclItem));
661 /* initialize the new entry with no permissions */
662 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
663 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
664 ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
665 ACL_NO_RIGHTS, ACL_NO_RIGHTS,
666 ACLITEM_GET_IDTYPE(*mod_aip));
667 num++; /* set num to the size of new_acl */
670 old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
671 old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
673 /* apply the specified permissions change */
676 case ACL_MODECHG_ADD:
677 ACLITEM_SET_RIGHTS(new_aip[dst],
678 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
680 case ACL_MODECHG_DEL:
681 ACLITEM_SET_RIGHTS(new_aip[dst],
682 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
684 case ACL_MODECHG_EQL:
685 ACLITEM_SET_RIGHTS(new_aip[dst],
686 ACLITEM_GET_RIGHTS(*mod_aip));
690 new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
691 new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
694 * If the adjusted entry has no permissions, delete it from the list.
696 if (new_rights == ACL_NO_RIGHTS)
698 memmove(new_aip + dst,
700 (num - dst - 1) * sizeof(AclItem));
701 ARR_DIMS(new_acl)[0] = num - 1;
702 ARR_SIZE(new_acl) -= sizeof(AclItem);
706 * Remove abandoned privileges (cascading revoke). Currently we can
707 * only handle this when the grantee is a user.
709 if ((old_goptions & ~new_goptions) != 0)
711 Assert(ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID);
712 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
713 (old_goptions & ~new_goptions),
721 * Update an ACL array to reflect a change of owner to the parent object
723 * old_acl: the input ACL array (must not be NULL)
724 * oldownerid: AclId of the old object owner
725 * newownerid: AclId of the new object owner
727 * The result is a modified copy; the input object is not changed.
729 * NB: caller is responsible for having detoasted the input ACL, if needed.
732 aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid)
740 bool newpresent = false;
747 * Make a copy of the given ACL, substituting new owner ID for old
748 * wherever it appears as either grantor or grantee. Also note if the
749 * new owner ID is already present.
751 num = ACL_NUM(old_acl);
752 old_aip = ACL_DAT(old_acl);
753 new_acl = allocacl(num);
754 new_aip = ACL_DAT(new_acl);
755 memcpy(new_aip, old_aip, num * sizeof(AclItem));
756 for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
758 /* grantor is always a UID, but grantee might not be */
759 if (dst_aip->ai_grantor == oldownerid)
760 dst_aip->ai_grantor = newownerid;
761 else if (dst_aip->ai_grantor == newownerid)
763 if (ACLITEM_GET_IDTYPE(*dst_aip) == ACL_IDTYPE_UID)
765 if (dst_aip->ai_grantee == oldownerid)
766 dst_aip->ai_grantee = newownerid;
767 else if (dst_aip->ai_grantee == newownerid)
773 * If the old ACL contained any references to the new owner, then we
774 * may now have generated an ACL containing duplicate entries. Find
775 * them and merge them so that there are not duplicates. (This is
776 * relatively expensive since we use a stupid O(N^2) algorithm, but
777 * it's unlikely to be the normal case.)
779 * To simplify deletion of duplicate entries, we temporarily leave them
780 * in the array but set their privilege masks to zero; when we reach
781 * such an entry it's just skipped. (Thus, a side effect of this code
782 * will be to remove privilege-free entries, should there be any in
783 * the input.) dst is the next output slot, targ is the currently
784 * considered input slot (always >= dst), and src scans entries to the
785 * right of targ looking for duplicates. Once an entry has been
786 * emitted to dst it is known duplicate-free and need not be
787 * considered anymore.
792 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
794 /* ignore if deleted in an earlier pass */
795 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
797 /* find and merge any duplicates */
798 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
801 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
803 if (aclitem_match(targ_aip, src_aip))
805 ACLITEM_SET_RIGHTS(*targ_aip,
806 ACLITEM_GET_RIGHTS(*targ_aip) |
807 ACLITEM_GET_RIGHTS(*src_aip));
808 /* mark the duplicate deleted */
809 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
812 /* and emit to output */
813 new_aip[dst] = *targ_aip;
816 /* Adjust array size to be 'dst' items */
817 ARR_DIMS(new_acl)[0] = dst;
818 ARR_SIZE(new_acl) = ACL_N_SIZE(dst);
826 * When granting grant options, we must disallow attempts to set up circular
827 * chains of grant options. Suppose A (the object owner) grants B some
828 * privileges with grant option, and B re-grants them to C. If C could
829 * grant the privileges to B as well, then A would be unable to effectively
830 * revoke the privileges from B, since recursive_revoke would consider that
831 * B still has 'em from C.
833 * We check for this by recursively deleting all grant options belonging to
834 * the target grantee, and then seeing if the would-be grantor still has the
835 * grant option or not.
838 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
848 * For now, grant options can only be granted to users, not groups or
849 * PUBLIC. Otherwise we'd have to work a bit harder here.
851 Assert(ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID);
853 /* The owner always has grant options, no need to check */
854 if (mod_aip->ai_grantor == ownerid)
857 /* Make a working copy */
858 acl = allocacl(ACL_NUM(old_acl));
859 memcpy(acl, old_acl, ACL_SIZE(old_acl));
861 /* Zap all grant options of target grantee, plus what depends on 'em */
865 for (i = 0; i < num; i++)
867 if (ACLITEM_GET_IDTYPE(aip[i]) == ACL_IDTYPE_UID &&
868 aip[i].ai_grantee == mod_aip->ai_grantee &&
869 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
873 /* We'll actually zap ordinary privs too, but no matter */
874 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
875 ownerid, DROP_CASCADE);
884 /* Now we can compute grantor's independently-derived privileges */
885 own_privs = aclmask(acl,
888 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
890 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
892 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
894 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
895 errmsg("grant options cannot be granted back to your own grantor")));
902 * Ensure that no privilege is "abandoned". A privilege is abandoned
903 * if the user that granted the privilege loses the grant option. (So
904 * the chain through which it was granted is broken.) Either the
905 * abandoned privileges are revoked as well, or an error message is
906 * printed, depending on the drop behavior option.
908 * acl: the input ACL list
909 * grantee: the user from whom some grant options have been revoked
910 * revoke_privs: the grant options being revoked
911 * ownerid: AclId of object owner
912 * behavior: RESTRICT or CASCADE behavior for recursive removal
914 * The input Acl object is pfree'd if replaced.
917 recursive_revoke(Acl *acl,
919 AclMode revoke_privs,
921 DropBehavior behavior)
928 /* The owner can never truly lose grant options, so short-circuit */
929 if (grantee == ownerid)
932 /* The grantee might still have the privileges via another grantor */
933 still_has = aclmask(acl, grantee, ownerid,
934 ACL_GRANT_OPTION_FOR(revoke_privs),
936 revoke_privs &= ~still_has;
937 if (revoke_privs == ACL_NO_RIGHTS)
943 for (i = 0; i < num; i++)
945 if (aip[i].ai_grantor == grantee
946 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
951 if (behavior == DROP_RESTRICT)
953 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
954 errmsg("dependent privileges exist"),
955 errhint("Use CASCADE to revoke them too.")));
957 mod_acl.ai_grantor = grantee;
958 mod_acl.ai_grantee = aip[i].ai_grantee;
959 ACLITEM_SET_PRIVS_IDTYPE(mod_acl,
962 ACLITEM_GET_IDTYPE(aip[i]));
964 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
979 * aclmask --- compute bitmask of all privileges held by userid.
981 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
982 * held by the given userid according to the given ACL list, ANDed
983 * with 'mask'. (The point of passing 'mask' is to let the routine
984 * exit early if all privileges of interest have been found.)
986 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
987 * is known true. (This lets us exit soonest in cases where the
988 * caller is only going to test for zero or nonzero result.)
992 * To see if any of a set of privileges are held:
993 * if (aclmask(acl, userid, ownerid, privs, ACLMASK_ANY) != 0)
995 * To see if all of a set of privileges are held:
996 * if (aclmask(acl, userid, ownerid, privs, ACLMASK_ALL) == privs)
998 * To determine exactly which of a set of privileges are held:
999 * heldprivs = aclmask(acl, userid, ownerid, privs, ACLMASK_ALL);
1002 aclmask(const Acl *acl, AclId userid, AclId ownerid,
1003 AclMode mask, AclMaskHow how)
1012 * Null ACL should not happen, since caller should have inserted
1013 * appropriate default
1016 elog(ERROR, "null ACL");
1018 /* Quick exit for mask == 0 */
1024 /* Owner always implicitly has all grant options */
1025 if (userid == ownerid)
1027 result = mask & ACLITEM_ALL_GOPTION_BITS;
1033 aidat = ACL_DAT(acl);
1036 * Check privileges granted directly to user or to public
1038 for (i = 0; i < num; i++)
1040 AclItem *aidata = &aidat[i];
1042 if (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_WORLD
1043 || (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_UID
1044 && aidata->ai_grantee == userid))
1046 result |= (aidata->ai_privs & mask);
1047 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1053 * Check privileges granted via groups. We do this in a separate pass
1054 * to minimize expensive lookups in pg_group.
1056 remaining = (mask & ~result);
1057 for (i = 0; i < num; i++)
1059 AclItem *aidata = &aidat[i];
1061 if (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_GID
1062 && (aidata->ai_privs & remaining)
1063 && in_group(userid, aidata->ai_grantee))
1065 result |= (aidata->ai_privs & mask);
1066 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1068 remaining = (mask & ~result);
1077 * Is user a member of group?
1080 in_group(AclId uid, AclId gid)
1082 bool result = false;
1091 tuple = SearchSysCache(GROSYSID,
1092 ObjectIdGetDatum(gid),
1094 if (HeapTupleIsValid(tuple))
1096 att = SysCacheGetAttr(GROSYSID,
1098 Anum_pg_group_grolist,
1102 /* be sure the IdList is not toasted */
1103 glist = DatumGetIdListP(att);
1105 num = IDLIST_NUM(glist);
1106 aidp = IDLIST_DAT(glist);
1107 for (i = 0; i < num; ++i)
1115 /* if IdList was toasted, free detoasted copy */
1116 if ((Pointer) glist != DatumGetPointer(att))
1119 ReleaseSysCache(tuple);
1123 (errcode(ERRCODE_UNDEFINED_OBJECT),
1124 errmsg("group with ID %u does not exist", gid)));
1130 * aclinsert (exported function)
1133 aclinsert(PG_FUNCTION_ARGS)
1136 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1137 errmsg("aclinsert is no longer supported")));
1139 PG_RETURN_NULL(); /* keep compiler quiet */
1143 aclremove(PG_FUNCTION_ARGS)
1146 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1147 errmsg("aclremove is no longer supported")));
1149 PG_RETURN_NULL(); /* keep compiler quiet */
1153 aclcontains(PG_FUNCTION_ARGS)
1155 Acl *acl = PG_GETARG_ACL_P(0);
1156 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1162 aidat = ACL_DAT(acl);
1163 for (i = 0; i < num; ++i)
1165 if (aip->ai_grantee == aidat[i].ai_grantee
1166 && ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i])
1167 && aip->ai_grantor == aidat[i].ai_grantor
1168 && (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1169 PG_RETURN_BOOL(true);
1171 PG_RETURN_BOOL(false);
1175 makeaclitem(PG_FUNCTION_ARGS)
1177 int32 u_grantee = PG_GETARG_INT32(0);
1178 int32 g_grantee = PG_GETARG_INT32(1);
1179 int32 grantor = PG_GETARG_INT32(2);
1180 text *privtext = PG_GETARG_TEXT_P(3);
1181 bool goption = PG_GETARG_BOOL(4);
1185 priv = convert_priv_string(privtext);
1187 aclitem = (AclItem *) palloc(sizeof(*aclitem));
1189 if (u_grantee == 0 && g_grantee == 0)
1191 aclitem ->ai_grantee = ACL_ID_WORLD;
1193 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
1195 else if (u_grantee != 0 && g_grantee != 0)
1198 (errcode(ERRCODE_DATA_EXCEPTION),
1199 errmsg("cannot specify both user and group")));
1201 else if (u_grantee != 0)
1203 aclitem ->ai_grantee = u_grantee;
1205 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
1208 /* (g_grantee != 0) */
1210 aclitem ->ai_grantee = g_grantee;
1212 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
1215 aclitem ->ai_grantor = grantor;
1217 ACLITEM_SET_PRIVS(*aclitem, priv);
1219 ACLITEM_SET_GOPTIONS(*aclitem, priv);
1221 ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS);
1223 PG_RETURN_ACLITEM_P(aclitem);
1227 convert_priv_string(text *priv_type_text)
1231 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1232 PointerGetDatum(priv_type_text)));
1234 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1236 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1238 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1240 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1242 if (pg_strcasecmp(priv_type, "RULE") == 0)
1244 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1245 return ACL_REFERENCES;
1246 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1248 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1250 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1252 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1254 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1255 return ACL_CREATE_TEMP;
1256 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1257 return ACL_CREATE_TEMP;
1260 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1261 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1262 return ACL_NO_RIGHTS; /* keep compiler quiet */
1267 * has_table_privilege variants
1268 * These are all named "has_table_privilege" at the SQL level.
1269 * They take various combinations of relation name, relation OID,
1270 * user name, user sysid, or implicit user = current_user.
1272 * The result is a boolean value: true if user has the indicated
1273 * privilege, false if not.
1277 * has_table_privilege_name_name
1278 * Check user privileges on a table given
1279 * name username, text tablename, and text priv name.
1282 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1284 Name username = PG_GETARG_NAME(0);
1285 text *tablename = PG_GETARG_TEXT_P(1);
1286 text *priv_type_text = PG_GETARG_TEXT_P(2);
1290 AclResult aclresult;
1292 usesysid = get_usesysid(NameStr(*username));
1293 tableoid = convert_table_name(tablename);
1294 mode = convert_table_priv_string(priv_type_text);
1296 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1298 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1302 * has_table_privilege_name
1303 * Check user privileges on a table given
1304 * text tablename and text priv name.
1305 * current_user is assumed
1308 has_table_privilege_name(PG_FUNCTION_ARGS)
1310 text *tablename = PG_GETARG_TEXT_P(0);
1311 text *priv_type_text = PG_GETARG_TEXT_P(1);
1315 AclResult aclresult;
1317 usesysid = GetUserId();
1318 tableoid = convert_table_name(tablename);
1319 mode = convert_table_priv_string(priv_type_text);
1321 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1323 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1327 * has_table_privilege_name_id
1328 * Check user privileges on a table given
1329 * name usename, table oid, and text priv name.
1332 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1334 Name username = PG_GETARG_NAME(0);
1335 Oid tableoid = PG_GETARG_OID(1);
1336 text *priv_type_text = PG_GETARG_TEXT_P(2);
1339 AclResult aclresult;
1341 usesysid = get_usesysid(NameStr(*username));
1342 mode = convert_table_priv_string(priv_type_text);
1344 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1346 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1350 * has_table_privilege_id
1351 * Check user privileges on a table given
1352 * table oid, and text priv name.
1353 * current_user is assumed
1356 has_table_privilege_id(PG_FUNCTION_ARGS)
1358 Oid tableoid = PG_GETARG_OID(0);
1359 text *priv_type_text = PG_GETARG_TEXT_P(1);
1362 AclResult aclresult;
1364 usesysid = GetUserId();
1365 mode = convert_table_priv_string(priv_type_text);
1367 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1369 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1373 * has_table_privilege_id_name
1374 * Check user privileges on a table given
1375 * usesysid, text tablename, and text priv name.
1378 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1380 int32 usesysid = PG_GETARG_INT32(0);
1381 text *tablename = PG_GETARG_TEXT_P(1);
1382 text *priv_type_text = PG_GETARG_TEXT_P(2);
1385 AclResult aclresult;
1387 tableoid = convert_table_name(tablename);
1388 mode = convert_table_priv_string(priv_type_text);
1390 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1392 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1396 * has_table_privilege_id_id
1397 * Check user privileges on a table given
1398 * usesysid, table oid, and text priv name.
1401 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1403 int32 usesysid = PG_GETARG_INT32(0);
1404 Oid tableoid = PG_GETARG_OID(1);
1405 text *priv_type_text = PG_GETARG_TEXT_P(2);
1407 AclResult aclresult;
1409 mode = convert_table_priv_string(priv_type_text);
1411 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1413 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1417 * Support routines for has_table_privilege family.
1421 * Given a table name expressed as a string, look it up and return Oid
1424 convert_table_name(text *tablename)
1428 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename,
1429 "has_table_privilege"));
1431 return RangeVarGetRelid(relrv, false);
1435 * convert_table_priv_string
1436 * Convert text string to AclMode value.
1439 convert_table_priv_string(text *priv_type_text)
1443 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1444 PointerGetDatum(priv_type_text)));
1447 * Return mode from priv_type string
1449 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1451 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1452 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1454 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1456 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1457 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1459 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1461 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1462 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1464 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1466 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1467 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1469 if (pg_strcasecmp(priv_type, "RULE") == 0)
1471 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1472 return ACL_GRANT_OPTION_FOR(ACL_RULE);
1474 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1475 return ACL_REFERENCES;
1476 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1477 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1479 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1481 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1482 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1485 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1486 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1487 return ACL_NO_RIGHTS; /* keep compiler quiet */
1492 * has_database_privilege variants
1493 * These are all named "has_database_privilege" at the SQL level.
1494 * They take various combinations of database name, database OID,
1495 * user name, user sysid, or implicit user = current_user.
1497 * The result is a boolean value: true if user has the indicated
1498 * privilege, false if not.
1502 * has_database_privilege_name_name
1503 * Check user privileges on a database given
1504 * name username, text databasename, and text priv name.
1507 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1509 Name username = PG_GETARG_NAME(0);
1510 text *databasename = PG_GETARG_TEXT_P(1);
1511 text *priv_type_text = PG_GETARG_TEXT_P(2);
1515 AclResult aclresult;
1517 usesysid = get_usesysid(NameStr(*username));
1518 databaseoid = convert_database_name(databasename);
1519 mode = convert_database_priv_string(priv_type_text);
1521 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1523 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1527 * has_database_privilege_name
1528 * Check user privileges on a database given
1529 * text databasename and text priv name.
1530 * current_user is assumed
1533 has_database_privilege_name(PG_FUNCTION_ARGS)
1535 text *databasename = PG_GETARG_TEXT_P(0);
1536 text *priv_type_text = PG_GETARG_TEXT_P(1);
1540 AclResult aclresult;
1542 usesysid = GetUserId();
1543 databaseoid = convert_database_name(databasename);
1544 mode = convert_database_priv_string(priv_type_text);
1546 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1548 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1552 * has_database_privilege_name_id
1553 * Check user privileges on a database given
1554 * name usename, database oid, and text priv name.
1557 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1559 Name username = PG_GETARG_NAME(0);
1560 Oid databaseoid = PG_GETARG_OID(1);
1561 text *priv_type_text = PG_GETARG_TEXT_P(2);
1564 AclResult aclresult;
1566 usesysid = get_usesysid(NameStr(*username));
1567 mode = convert_database_priv_string(priv_type_text);
1569 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1571 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1575 * has_database_privilege_id
1576 * Check user privileges on a database given
1577 * database oid, and text priv name.
1578 * current_user is assumed
1581 has_database_privilege_id(PG_FUNCTION_ARGS)
1583 Oid databaseoid = PG_GETARG_OID(0);
1584 text *priv_type_text = PG_GETARG_TEXT_P(1);
1587 AclResult aclresult;
1589 usesysid = GetUserId();
1590 mode = convert_database_priv_string(priv_type_text);
1592 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1594 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1598 * has_database_privilege_id_name
1599 * Check user privileges on a database given
1600 * usesysid, text databasename, and text priv name.
1603 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1605 int32 usesysid = PG_GETARG_INT32(0);
1606 text *databasename = PG_GETARG_TEXT_P(1);
1607 text *priv_type_text = PG_GETARG_TEXT_P(2);
1610 AclResult aclresult;
1612 databaseoid = convert_database_name(databasename);
1613 mode = convert_database_priv_string(priv_type_text);
1615 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1617 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1621 * has_database_privilege_id_id
1622 * Check user privileges on a database given
1623 * usesysid, database oid, and text priv name.
1626 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1628 int32 usesysid = PG_GETARG_INT32(0);
1629 Oid databaseoid = PG_GETARG_OID(1);
1630 text *priv_type_text = PG_GETARG_TEXT_P(2);
1632 AclResult aclresult;
1634 mode = convert_database_priv_string(priv_type_text);
1636 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1638 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1642 * Support routines for has_database_privilege family.
1646 * Given a database name expressed as a string, look it up and return Oid
1649 convert_database_name(text *databasename)
1654 dbname = DatumGetCString(DirectFunctionCall1(textout,
1655 PointerGetDatum(databasename)));
1657 oid = get_database_oid(dbname);
1658 if (!OidIsValid(oid))
1660 (errcode(ERRCODE_UNDEFINED_DATABASE),
1661 errmsg("database \"%s\" does not exist", dbname)));
1667 * convert_database_priv_string
1668 * Convert text string to AclMode value.
1671 convert_database_priv_string(text *priv_type_text)
1675 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1676 PointerGetDatum(priv_type_text)));
1679 * Return mode from priv_type string
1681 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1683 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1684 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1686 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1687 return ACL_CREATE_TEMP;
1688 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1689 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1691 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1692 return ACL_CREATE_TEMP;
1693 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1694 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1697 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1698 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1699 return ACL_NO_RIGHTS; /* keep compiler quiet */
1704 * has_function_privilege variants
1705 * These are all named "has_function_privilege" at the SQL level.
1706 * They take various combinations of function name, function OID,
1707 * user name, user sysid, or implicit user = current_user.
1709 * The result is a boolean value: true if user has the indicated
1710 * privilege, false if not.
1714 * has_function_privilege_name_name
1715 * Check user privileges on a function given
1716 * name username, text functionname, and text priv name.
1719 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1721 Name username = PG_GETARG_NAME(0);
1722 text *functionname = PG_GETARG_TEXT_P(1);
1723 text *priv_type_text = PG_GETARG_TEXT_P(2);
1727 AclResult aclresult;
1729 usesysid = get_usesysid(NameStr(*username));
1730 functionoid = convert_function_name(functionname);
1731 mode = convert_function_priv_string(priv_type_text);
1733 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1735 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1739 * has_function_privilege_name
1740 * Check user privileges on a function given
1741 * text functionname and text priv name.
1742 * current_user is assumed
1745 has_function_privilege_name(PG_FUNCTION_ARGS)
1747 text *functionname = PG_GETARG_TEXT_P(0);
1748 text *priv_type_text = PG_GETARG_TEXT_P(1);
1752 AclResult aclresult;
1754 usesysid = GetUserId();
1755 functionoid = convert_function_name(functionname);
1756 mode = convert_function_priv_string(priv_type_text);
1758 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1760 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1764 * has_function_privilege_name_id
1765 * Check user privileges on a function given
1766 * name usename, function oid, and text priv name.
1769 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1771 Name username = PG_GETARG_NAME(0);
1772 Oid functionoid = PG_GETARG_OID(1);
1773 text *priv_type_text = PG_GETARG_TEXT_P(2);
1776 AclResult aclresult;
1778 usesysid = get_usesysid(NameStr(*username));
1779 mode = convert_function_priv_string(priv_type_text);
1781 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1783 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1787 * has_function_privilege_id
1788 * Check user privileges on a function given
1789 * function oid, and text priv name.
1790 * current_user is assumed
1793 has_function_privilege_id(PG_FUNCTION_ARGS)
1795 Oid functionoid = PG_GETARG_OID(0);
1796 text *priv_type_text = PG_GETARG_TEXT_P(1);
1799 AclResult aclresult;
1801 usesysid = GetUserId();
1802 mode = convert_function_priv_string(priv_type_text);
1804 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1806 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1810 * has_function_privilege_id_name
1811 * Check user privileges on a function given
1812 * usesysid, text functionname, and text priv name.
1815 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1817 int32 usesysid = PG_GETARG_INT32(0);
1818 text *functionname = PG_GETARG_TEXT_P(1);
1819 text *priv_type_text = PG_GETARG_TEXT_P(2);
1822 AclResult aclresult;
1824 functionoid = convert_function_name(functionname);
1825 mode = convert_function_priv_string(priv_type_text);
1827 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1829 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1833 * has_function_privilege_id_id
1834 * Check user privileges on a function given
1835 * usesysid, function oid, and text priv name.
1838 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1840 int32 usesysid = PG_GETARG_INT32(0);
1841 Oid functionoid = PG_GETARG_OID(1);
1842 text *priv_type_text = PG_GETARG_TEXT_P(2);
1844 AclResult aclresult;
1846 mode = convert_function_priv_string(priv_type_text);
1848 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1850 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1854 * Support routines for has_function_privilege family.
1858 * Given a function name expressed as a string, look it up and return Oid
1861 convert_function_name(text *functionname)
1866 funcname = DatumGetCString(DirectFunctionCall1(textout,
1867 PointerGetDatum(functionname)));
1869 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1870 CStringGetDatum(funcname)));
1872 if (!OidIsValid(oid))
1874 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1875 errmsg("function \"%s\" does not exist", funcname)));
1881 * convert_function_priv_string
1882 * Convert text string to AclMode value.
1885 convert_function_priv_string(text *priv_type_text)
1889 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1890 PointerGetDatum(priv_type_text)));
1893 * Return mode from priv_type string
1895 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1897 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1898 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1901 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1902 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1903 return ACL_NO_RIGHTS; /* keep compiler quiet */
1908 * has_language_privilege variants
1909 * These are all named "has_language_privilege" at the SQL level.
1910 * They take various combinations of language name, language OID,
1911 * user name, user sysid, or implicit user = current_user.
1913 * The result is a boolean value: true if user has the indicated
1914 * privilege, false if not.
1918 * has_language_privilege_name_name
1919 * Check user privileges on a language given
1920 * name username, text languagename, and text priv name.
1923 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1925 Name username = PG_GETARG_NAME(0);
1926 text *languagename = PG_GETARG_TEXT_P(1);
1927 text *priv_type_text = PG_GETARG_TEXT_P(2);
1931 AclResult aclresult;
1933 usesysid = get_usesysid(NameStr(*username));
1934 languageoid = convert_language_name(languagename);
1935 mode = convert_language_priv_string(priv_type_text);
1937 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1939 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1943 * has_language_privilege_name
1944 * Check user privileges on a language given
1945 * text languagename and text priv name.
1946 * current_user is assumed
1949 has_language_privilege_name(PG_FUNCTION_ARGS)
1951 text *languagename = PG_GETARG_TEXT_P(0);
1952 text *priv_type_text = PG_GETARG_TEXT_P(1);
1956 AclResult aclresult;
1958 usesysid = GetUserId();
1959 languageoid = convert_language_name(languagename);
1960 mode = convert_language_priv_string(priv_type_text);
1962 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1964 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1968 * has_language_privilege_name_id
1969 * Check user privileges on a language given
1970 * name usename, language oid, and text priv name.
1973 has_language_privilege_name_id(PG_FUNCTION_ARGS)
1975 Name username = PG_GETARG_NAME(0);
1976 Oid languageoid = PG_GETARG_OID(1);
1977 text *priv_type_text = PG_GETARG_TEXT_P(2);
1980 AclResult aclresult;
1982 usesysid = get_usesysid(NameStr(*username));
1983 mode = convert_language_priv_string(priv_type_text);
1985 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1987 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1991 * has_language_privilege_id
1992 * Check user privileges on a language given
1993 * language oid, and text priv name.
1994 * current_user is assumed
1997 has_language_privilege_id(PG_FUNCTION_ARGS)
1999 Oid languageoid = PG_GETARG_OID(0);
2000 text *priv_type_text = PG_GETARG_TEXT_P(1);
2003 AclResult aclresult;
2005 usesysid = GetUserId();
2006 mode = convert_language_priv_string(priv_type_text);
2008 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
2010 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2014 * has_language_privilege_id_name
2015 * Check user privileges on a language given
2016 * usesysid, text languagename, and text priv name.
2019 has_language_privilege_id_name(PG_FUNCTION_ARGS)
2021 int32 usesysid = PG_GETARG_INT32(0);
2022 text *languagename = PG_GETARG_TEXT_P(1);
2023 text *priv_type_text = PG_GETARG_TEXT_P(2);
2026 AclResult aclresult;
2028 languageoid = convert_language_name(languagename);
2029 mode = convert_language_priv_string(priv_type_text);
2031 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
2033 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2037 * has_language_privilege_id_id
2038 * Check user privileges on a language given
2039 * usesysid, language oid, and text priv name.
2042 has_language_privilege_id_id(PG_FUNCTION_ARGS)
2044 int32 usesysid = PG_GETARG_INT32(0);
2045 Oid languageoid = PG_GETARG_OID(1);
2046 text *priv_type_text = PG_GETARG_TEXT_P(2);
2048 AclResult aclresult;
2050 mode = convert_language_priv_string(priv_type_text);
2052 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
2054 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2058 * Support routines for has_language_privilege family.
2062 * Given a language name expressed as a string, look it up and return Oid
2065 convert_language_name(text *languagename)
2070 langname = DatumGetCString(DirectFunctionCall1(textout,
2071 PointerGetDatum(languagename)));
2073 oid = GetSysCacheOid(LANGNAME,
2074 CStringGetDatum(langname),
2076 if (!OidIsValid(oid))
2078 (errcode(ERRCODE_UNDEFINED_OBJECT),
2079 errmsg("language \"%s\" does not exist", langname)));
2085 * convert_language_priv_string
2086 * Convert text string to AclMode value.
2089 convert_language_priv_string(text *priv_type_text)
2093 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2094 PointerGetDatum(priv_type_text)));
2097 * Return mode from priv_type string
2099 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2101 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2102 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2105 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2106 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2107 return ACL_NO_RIGHTS; /* keep compiler quiet */
2112 * has_schema_privilege variants
2113 * These are all named "has_schema_privilege" at the SQL level.
2114 * They take various combinations of schema name, schema OID,
2115 * user name, user sysid, or implicit user = current_user.
2117 * The result is a boolean value: true if user has the indicated
2118 * privilege, false if not.
2122 * has_schema_privilege_name_name
2123 * Check user privileges on a schema given
2124 * name username, text schemaname, and text priv name.
2127 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2129 Name username = PG_GETARG_NAME(0);
2130 text *schemaname = PG_GETARG_TEXT_P(1);
2131 text *priv_type_text = PG_GETARG_TEXT_P(2);
2135 AclResult aclresult;
2137 usesysid = get_usesysid(NameStr(*username));
2138 schemaoid = convert_schema_name(schemaname);
2139 mode = convert_schema_priv_string(priv_type_text);
2141 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2143 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2147 * has_schema_privilege_name
2148 * Check user privileges on a schema given
2149 * text schemaname and text priv name.
2150 * current_user is assumed
2153 has_schema_privilege_name(PG_FUNCTION_ARGS)
2155 text *schemaname = PG_GETARG_TEXT_P(0);
2156 text *priv_type_text = PG_GETARG_TEXT_P(1);
2160 AclResult aclresult;
2162 usesysid = GetUserId();
2163 schemaoid = convert_schema_name(schemaname);
2164 mode = convert_schema_priv_string(priv_type_text);
2166 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2168 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2172 * has_schema_privilege_name_id
2173 * Check user privileges on a schema given
2174 * name usename, schema oid, and text priv name.
2177 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2179 Name username = PG_GETARG_NAME(0);
2180 Oid schemaoid = PG_GETARG_OID(1);
2181 text *priv_type_text = PG_GETARG_TEXT_P(2);
2184 AclResult aclresult;
2186 usesysid = get_usesysid(NameStr(*username));
2187 mode = convert_schema_priv_string(priv_type_text);
2189 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2191 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2195 * has_schema_privilege_id
2196 * Check user privileges on a schema given
2197 * schema oid, and text priv name.
2198 * current_user is assumed
2201 has_schema_privilege_id(PG_FUNCTION_ARGS)
2203 Oid schemaoid = PG_GETARG_OID(0);
2204 text *priv_type_text = PG_GETARG_TEXT_P(1);
2207 AclResult aclresult;
2209 usesysid = GetUserId();
2210 mode = convert_schema_priv_string(priv_type_text);
2212 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2214 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2218 * has_schema_privilege_id_name
2219 * Check user privileges on a schema given
2220 * usesysid, text schemaname, and text priv name.
2223 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2225 int32 usesysid = PG_GETARG_INT32(0);
2226 text *schemaname = PG_GETARG_TEXT_P(1);
2227 text *priv_type_text = PG_GETARG_TEXT_P(2);
2230 AclResult aclresult;
2232 schemaoid = convert_schema_name(schemaname);
2233 mode = convert_schema_priv_string(priv_type_text);
2235 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2237 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2241 * has_schema_privilege_id_id
2242 * Check user privileges on a schema given
2243 * usesysid, schema oid, and text priv name.
2246 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2248 int32 usesysid = PG_GETARG_INT32(0);
2249 Oid schemaoid = PG_GETARG_OID(1);
2250 text *priv_type_text = PG_GETARG_TEXT_P(2);
2252 AclResult aclresult;
2254 mode = convert_schema_priv_string(priv_type_text);
2256 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2258 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2262 * Support routines for has_schema_privilege family.
2266 * Given a schema name expressed as a string, look it up and return Oid
2269 convert_schema_name(text *schemaname)
2274 nspname = DatumGetCString(DirectFunctionCall1(textout,
2275 PointerGetDatum(schemaname)));
2277 oid = GetSysCacheOid(NAMESPACENAME,
2278 CStringGetDatum(nspname),
2280 if (!OidIsValid(oid))
2282 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2283 errmsg("schema \"%s\" does not exist", nspname)));
2289 * convert_schema_priv_string
2290 * Convert text string to AclMode value.
2293 convert_schema_priv_string(text *priv_type_text)
2297 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2298 PointerGetDatum(priv_type_text)));
2301 * Return mode from priv_type string
2303 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2305 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2306 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2308 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2310 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2311 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2314 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2315 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2316 return ACL_NO_RIGHTS; /* keep compiler quiet */
2320 * has_tablespace_privilege variants
2321 * These are all named "has_tablespace_privilege" at the SQL level.
2322 * They take various combinations of tablespace name, tablespace OID,
2323 * user name, user sysid, or implicit user = current_user.
2325 * The result is a boolean value: true if user has the indicated
2326 * privilege, false if not.
2330 * has_tablespace_privilege_name_name
2331 * Check user privileges on a tablespace given
2332 * name username, text tablespacename, and text priv name.
2335 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2337 Name username = PG_GETARG_NAME(0);
2338 text *tablespacename = PG_GETARG_TEXT_P(1);
2339 text *priv_type_text = PG_GETARG_TEXT_P(2);
2343 AclResult aclresult;
2345 usesysid = get_usesysid(NameStr(*username));
2346 tablespaceoid = convert_tablespace_name(tablespacename);
2347 mode = convert_tablespace_priv_string(priv_type_text);
2349 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2351 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2355 * has_tablespace_privilege_name
2356 * Check user privileges on a tablespace given
2357 * text tablespacename and text priv name.
2358 * current_user is assumed
2361 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2363 text *tablespacename = PG_GETARG_TEXT_P(0);
2364 text *priv_type_text = PG_GETARG_TEXT_P(1);
2368 AclResult aclresult;
2370 usesysid = GetUserId();
2371 tablespaceoid = convert_tablespace_name(tablespacename);
2372 mode = convert_tablespace_priv_string(priv_type_text);
2374 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2376 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2380 * has_tablespace_privilege_name_id
2381 * Check user privileges on a tablespace given
2382 * name usename, tablespace oid, and text priv name.
2385 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2387 Name username = PG_GETARG_NAME(0);
2388 Oid tablespaceoid = PG_GETARG_OID(1);
2389 text *priv_type_text = PG_GETARG_TEXT_P(2);
2392 AclResult aclresult;
2394 usesysid = get_usesysid(NameStr(*username));
2395 mode = convert_tablespace_priv_string(priv_type_text);
2397 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2399 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2403 * has_tablespace_privilege_id
2404 * Check user privileges on a tablespace given
2405 * tablespace oid, and text priv name.
2406 * current_user is assumed
2409 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2411 Oid tablespaceoid = PG_GETARG_OID(0);
2412 text *priv_type_text = PG_GETARG_TEXT_P(1);
2415 AclResult aclresult;
2417 usesysid = GetUserId();
2418 mode = convert_tablespace_priv_string(priv_type_text);
2420 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2422 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2426 * has_tablespace_privilege_id_name
2427 * Check user privileges on a tablespace given
2428 * usesysid, text tablespacename, and text priv name.
2431 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2433 int32 usesysid = PG_GETARG_INT32(0);
2434 text *tablespacename = PG_GETARG_TEXT_P(1);
2435 text *priv_type_text = PG_GETARG_TEXT_P(2);
2438 AclResult aclresult;
2440 tablespaceoid = convert_tablespace_name(tablespacename);
2441 mode = convert_tablespace_priv_string(priv_type_text);
2443 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2445 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2449 * has_tablespace_privilege_id_id
2450 * Check user privileges on a tablespace given
2451 * usesysid, tablespace oid, and text priv name.
2454 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2456 int32 usesysid = PG_GETARG_INT32(0);
2457 Oid tablespaceoid = PG_GETARG_OID(1);
2458 text *priv_type_text = PG_GETARG_TEXT_P(2);
2460 AclResult aclresult;
2462 mode = convert_tablespace_priv_string(priv_type_text);
2464 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2466 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2470 * Support routines for has_tablespace_privilege family.
2474 * Given a tablespace name expressed as a string, look it up and return Oid
2477 convert_tablespace_name(text *tablespacename)
2482 spcname = DatumGetCString(DirectFunctionCall1(textout,
2483 PointerGetDatum(tablespacename)));
2484 oid = get_tablespace_oid(spcname);
2486 if (!OidIsValid(oid))
2488 (errcode(ERRCODE_UNDEFINED_OBJECT),
2489 errmsg("tablespace \"%s\" does not exist", spcname)));
2495 * convert_tablespace_priv_string
2496 * Convert text string to AclMode value.
2499 convert_tablespace_priv_string(text *priv_type_text)
2503 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2504 PointerGetDatum(priv_type_text)));
2507 * Return mode from priv_type string
2509 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2511 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2512 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2515 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2516 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2517 return ACL_NO_RIGHTS; /* keep compiler quiet */