1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2003, 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.109 2004/08/06 18:05:48 tgl 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
572 * the 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
707 * can 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
749 * the 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 the
783 * input.) dst is the next output slot, targ is the currently considered
784 * input slot (always >= dst), and src scans entries to the right of targ
785 * looking for duplicates. Once an entry has been emitted to dst it is
786 * known duplicate-free and need not be considered anymore.
791 for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
793 /* ignore if deleted in an earlier pass */
794 if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
796 /* find and merge any duplicates */
797 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
800 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
802 if (aclitem_match(targ_aip, src_aip))
804 ACLITEM_SET_RIGHTS(*targ_aip,
805 ACLITEM_GET_RIGHTS(*targ_aip) |
806 ACLITEM_GET_RIGHTS(*src_aip));
807 /* mark the duplicate deleted */
808 ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
811 /* and emit to output */
812 new_aip[dst] = *targ_aip;
815 /* Adjust array size to be 'dst' items */
816 ARR_DIMS(new_acl)[0] = dst;
817 ARR_SIZE(new_acl) = ACL_N_SIZE(dst);
825 * When granting grant options, we must disallow attempts to set up circular
826 * chains of grant options. Suppose A (the object owner) grants B some
827 * privileges with grant option, and B re-grants them to C. If C could
828 * grant the privileges to B as well, then A would be unable to effectively
829 * revoke the privileges from B, since recursive_revoke would consider that
830 * B still has 'em from C.
832 * We check for this by recursively deleting all grant options belonging to
833 * the target grantee, and then seeing if the would-be grantor still has the
834 * grant option or not.
837 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
847 * For now, grant options can only be granted to users, not groups or
848 * PUBLIC. Otherwise we'd have to work a bit harder here.
850 Assert(ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID);
852 /* The owner always has grant options, no need to check */
853 if (mod_aip->ai_grantor == ownerid)
856 /* Make a working copy */
857 acl = allocacl(ACL_NUM(old_acl));
858 memcpy(acl, old_acl, ACL_SIZE(old_acl));
860 /* Zap all grant options of target grantee, plus what depends on 'em */
864 for (i = 0; i < num; i++)
866 if (ACLITEM_GET_IDTYPE(aip[i]) == ACL_IDTYPE_UID &&
867 aip[i].ai_grantee == mod_aip->ai_grantee &&
868 ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
872 /* We'll actually zap ordinary privs too, but no matter */
873 new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
874 ownerid, DROP_CASCADE);
883 /* Now we can compute grantor's independently-derived privileges */
884 own_privs = aclmask(acl,
887 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
889 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
891 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
893 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
894 errmsg("grant options cannot be granted back to your own grantor")));
901 * Ensure that no privilege is "abandoned". A privilege is abandoned
902 * if the user that granted the privilege loses the grant option. (So
903 * the chain through which it was granted is broken.) Either the
904 * abandoned privileges are revoked as well, or an error message is
905 * printed, depending on the drop behavior option.
907 * acl: the input ACL list
908 * grantee: the user from whom some grant options have been revoked
909 * revoke_privs: the grant options being revoked
910 * ownerid: AclId of object owner
911 * behavior: RESTRICT or CASCADE behavior for recursive removal
913 * The input Acl object is pfree'd if replaced.
916 recursive_revoke(Acl *acl,
918 AclMode revoke_privs,
920 DropBehavior behavior)
927 /* The owner can never truly lose grant options, so short-circuit */
928 if (grantee == ownerid)
931 /* The grantee might still have the privileges via another grantor */
932 still_has = aclmask(acl, grantee, ownerid,
933 ACL_GRANT_OPTION_FOR(revoke_privs),
935 revoke_privs &= ~still_has;
936 if (revoke_privs == ACL_NO_RIGHTS)
942 for (i = 0; i < num; i++)
944 if (aip[i].ai_grantor == grantee
945 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
950 if (behavior == DROP_RESTRICT)
952 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
953 errmsg("dependent privileges exist"),
954 errhint("Use CASCADE to revoke them too.")));
956 mod_acl.ai_grantor = grantee;
957 mod_acl.ai_grantee = aip[i].ai_grantee;
958 ACLITEM_SET_PRIVS_IDTYPE(mod_acl,
961 ACLITEM_GET_IDTYPE(aip[i]));
963 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
978 * aclmask --- compute bitmask of all privileges held by userid.
980 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
981 * held by the given userid according to the given ACL list, ANDed
982 * with 'mask'. (The point of passing 'mask' is to let the routine
983 * exit early if all privileges of interest have been found.)
985 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
986 * is known true. (This lets us exit soonest in cases where the
987 * caller is only going to test for zero or nonzero result.)
991 * To see if any of a set of privileges are held:
992 * if (aclmask(acl, userid, ownerid, privs, ACLMASK_ANY) != 0)
994 * To see if all of a set of privileges are held:
995 * if (aclmask(acl, userid, ownerid, privs, ACLMASK_ALL) == privs)
997 * To determine exactly which of a set of privileges are held:
998 * heldprivs = aclmask(acl, userid, ownerid, privs, ACLMASK_ALL);
1001 aclmask(const Acl *acl, AclId userid, AclId ownerid,
1002 AclMode mask, AclMaskHow how)
1011 * Null ACL should not happen, since caller should have inserted
1012 * appropriate default
1015 elog(ERROR, "null ACL");
1017 /* Quick exit for mask == 0 */
1023 /* Owner always implicitly has all grant options */
1024 if (userid == ownerid)
1026 result = mask & ACLITEM_ALL_GOPTION_BITS;
1032 aidat = ACL_DAT(acl);
1035 * Check privileges granted directly to user or to public
1037 for (i = 0; i < num; i++)
1039 AclItem *aidata = &aidat[i];
1041 if (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_WORLD
1042 || (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_UID
1043 && aidata->ai_grantee == userid))
1045 result |= (aidata->ai_privs & mask);
1046 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1052 * Check privileges granted via groups. We do this in a separate
1053 * pass to minimize expensive lookups in pg_group.
1055 remaining = (mask & ~result);
1056 for (i = 0; i < num; i++)
1058 AclItem *aidata = &aidat[i];
1060 if (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_GID
1061 && (aidata->ai_privs & remaining)
1062 && in_group(userid, aidata->ai_grantee))
1064 result |= (aidata->ai_privs & mask);
1065 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1067 remaining = (mask & ~result);
1076 * Is user a member of group?
1079 in_group(AclId uid, AclId gid)
1081 bool result = false;
1090 tuple = SearchSysCache(GROSYSID,
1091 ObjectIdGetDatum(gid),
1093 if (HeapTupleIsValid(tuple))
1095 att = SysCacheGetAttr(GROSYSID,
1097 Anum_pg_group_grolist,
1101 /* be sure the IdList is not toasted */
1102 glist = DatumGetIdListP(att);
1104 num = IDLIST_NUM(glist);
1105 aidp = IDLIST_DAT(glist);
1106 for (i = 0; i < num; ++i)
1114 /* if IdList was toasted, free detoasted copy */
1115 if ((Pointer) glist != DatumGetPointer(att))
1118 ReleaseSysCache(tuple);
1122 (errcode(ERRCODE_UNDEFINED_OBJECT),
1123 errmsg("group with ID %u does not exist", gid)));
1129 * aclinsert (exported function)
1132 aclinsert(PG_FUNCTION_ARGS)
1135 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1136 errmsg("aclinsert is no longer supported")));
1138 PG_RETURN_NULL(); /* keep compiler quiet */
1142 aclremove(PG_FUNCTION_ARGS)
1145 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1146 errmsg("aclremove is no longer supported")));
1148 PG_RETURN_NULL(); /* keep compiler quiet */
1152 aclcontains(PG_FUNCTION_ARGS)
1154 Acl *acl = PG_GETARG_ACL_P(0);
1155 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1161 aidat = ACL_DAT(acl);
1162 for (i = 0; i < num; ++i)
1164 if (aip->ai_grantee == aidat[i].ai_grantee
1165 && ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i])
1166 && aip->ai_grantor == aidat[i].ai_grantor
1167 && (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1168 PG_RETURN_BOOL(true);
1170 PG_RETURN_BOOL(false);
1174 makeaclitem(PG_FUNCTION_ARGS)
1176 int32 u_grantee = PG_GETARG_INT32(0);
1177 int32 g_grantee = PG_GETARG_INT32(1);
1178 int32 grantor = PG_GETARG_INT32(2);
1179 text *privtext = PG_GETARG_TEXT_P(3);
1180 bool goption = PG_GETARG_BOOL(4);
1184 priv = convert_priv_string(privtext);
1186 aclitem = (AclItem *) palloc(sizeof(*aclitem));
1188 if (u_grantee == 0 && g_grantee == 0)
1190 aclitem->ai_grantee = ACL_ID_WORLD;
1192 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
1194 else if (u_grantee != 0 && g_grantee != 0)
1197 (errcode(ERRCODE_DATA_EXCEPTION),
1198 errmsg("cannot specify both user and group")));
1200 else if (u_grantee != 0)
1202 aclitem->ai_grantee = u_grantee;
1204 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
1206 else /* (g_grantee != 0) */
1208 aclitem->ai_grantee = g_grantee;
1210 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
1213 aclitem->ai_grantor = grantor;
1215 ACLITEM_SET_PRIVS(*aclitem, priv);
1217 ACLITEM_SET_GOPTIONS(*aclitem, priv);
1219 ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS);
1221 PG_RETURN_ACLITEM_P(aclitem);
1225 convert_priv_string(text *priv_type_text)
1229 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1230 PointerGetDatum(priv_type_text)));
1232 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1234 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1236 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1238 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1240 if (pg_strcasecmp(priv_type, "RULE") == 0)
1242 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1243 return ACL_REFERENCES;
1244 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1246 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1248 if (pg_strcasecmp(priv_type, "USAGE") == 0)
1250 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1252 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1253 return ACL_CREATE_TEMP;
1254 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1255 return ACL_CREATE_TEMP;
1258 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1259 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1260 return ACL_NO_RIGHTS; /* keep compiler quiet */
1265 * has_table_privilege variants
1266 * These are all named "has_table_privilege" at the SQL level.
1267 * They take various combinations of relation name, relation OID,
1268 * user name, user sysid, or implicit user = current_user.
1270 * The result is a boolean value: true if user has the indicated
1271 * privilege, false if not.
1275 * has_table_privilege_name_name
1276 * Check user privileges on a table given
1277 * name username, text tablename, and text priv name.
1280 has_table_privilege_name_name(PG_FUNCTION_ARGS)
1282 Name username = PG_GETARG_NAME(0);
1283 text *tablename = PG_GETARG_TEXT_P(1);
1284 text *priv_type_text = PG_GETARG_TEXT_P(2);
1288 AclResult aclresult;
1290 usesysid = get_usesysid(NameStr(*username));
1291 tableoid = convert_table_name(tablename);
1292 mode = convert_table_priv_string(priv_type_text);
1294 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1296 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1300 * has_table_privilege_name
1301 * Check user privileges on a table given
1302 * text tablename and text priv name.
1303 * current_user is assumed
1306 has_table_privilege_name(PG_FUNCTION_ARGS)
1308 text *tablename = PG_GETARG_TEXT_P(0);
1309 text *priv_type_text = PG_GETARG_TEXT_P(1);
1313 AclResult aclresult;
1315 usesysid = GetUserId();
1316 tableoid = convert_table_name(tablename);
1317 mode = convert_table_priv_string(priv_type_text);
1319 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1321 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1325 * has_table_privilege_name_id
1326 * Check user privileges on a table given
1327 * name usename, table oid, and text priv name.
1330 has_table_privilege_name_id(PG_FUNCTION_ARGS)
1332 Name username = PG_GETARG_NAME(0);
1333 Oid tableoid = PG_GETARG_OID(1);
1334 text *priv_type_text = PG_GETARG_TEXT_P(2);
1337 AclResult aclresult;
1339 usesysid = get_usesysid(NameStr(*username));
1340 mode = convert_table_priv_string(priv_type_text);
1342 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1344 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1348 * has_table_privilege_id
1349 * Check user privileges on a table given
1350 * table oid, and text priv name.
1351 * current_user is assumed
1354 has_table_privilege_id(PG_FUNCTION_ARGS)
1356 Oid tableoid = PG_GETARG_OID(0);
1357 text *priv_type_text = PG_GETARG_TEXT_P(1);
1360 AclResult aclresult;
1362 usesysid = GetUserId();
1363 mode = convert_table_priv_string(priv_type_text);
1365 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1367 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1371 * has_table_privilege_id_name
1372 * Check user privileges on a table given
1373 * usesysid, text tablename, and text priv name.
1376 has_table_privilege_id_name(PG_FUNCTION_ARGS)
1378 int32 usesysid = PG_GETARG_INT32(0);
1379 text *tablename = PG_GETARG_TEXT_P(1);
1380 text *priv_type_text = PG_GETARG_TEXT_P(2);
1383 AclResult aclresult;
1385 tableoid = convert_table_name(tablename);
1386 mode = convert_table_priv_string(priv_type_text);
1388 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1390 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1394 * has_table_privilege_id_id
1395 * Check user privileges on a table given
1396 * usesysid, table oid, and text priv name.
1399 has_table_privilege_id_id(PG_FUNCTION_ARGS)
1401 int32 usesysid = PG_GETARG_INT32(0);
1402 Oid tableoid = PG_GETARG_OID(1);
1403 text *priv_type_text = PG_GETARG_TEXT_P(2);
1405 AclResult aclresult;
1407 mode = convert_table_priv_string(priv_type_text);
1409 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
1411 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1415 * Support routines for has_table_privilege family.
1419 * Given a table name expressed as a string, look it up and return Oid
1422 convert_table_name(text *tablename)
1426 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename,
1427 "has_table_privilege"));
1429 return RangeVarGetRelid(relrv, false);
1433 * convert_table_priv_string
1434 * Convert text string to AclMode value.
1437 convert_table_priv_string(text *priv_type_text)
1441 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1442 PointerGetDatum(priv_type_text)));
1445 * Return mode from priv_type string
1447 if (pg_strcasecmp(priv_type, "SELECT") == 0)
1449 if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1450 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1452 if (pg_strcasecmp(priv_type, "INSERT") == 0)
1454 if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1455 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1457 if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1459 if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1460 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1462 if (pg_strcasecmp(priv_type, "DELETE") == 0)
1464 if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1465 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1467 if (pg_strcasecmp(priv_type, "RULE") == 0)
1469 if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1470 return ACL_GRANT_OPTION_FOR(ACL_RULE);
1472 if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
1473 return ACL_REFERENCES;
1474 if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1475 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1477 if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
1479 if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1480 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1483 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1484 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1485 return ACL_NO_RIGHTS; /* keep compiler quiet */
1490 * has_database_privilege variants
1491 * These are all named "has_database_privilege" at the SQL level.
1492 * They take various combinations of database name, database OID,
1493 * user name, user sysid, or implicit user = current_user.
1495 * The result is a boolean value: true if user has the indicated
1496 * privilege, false if not.
1500 * has_database_privilege_name_name
1501 * Check user privileges on a database given
1502 * name username, text databasename, and text priv name.
1505 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1507 Name username = PG_GETARG_NAME(0);
1508 text *databasename = PG_GETARG_TEXT_P(1);
1509 text *priv_type_text = PG_GETARG_TEXT_P(2);
1513 AclResult aclresult;
1515 usesysid = get_usesysid(NameStr(*username));
1516 databaseoid = convert_database_name(databasename);
1517 mode = convert_database_priv_string(priv_type_text);
1519 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1521 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1525 * has_database_privilege_name
1526 * Check user privileges on a database given
1527 * text databasename and text priv name.
1528 * current_user is assumed
1531 has_database_privilege_name(PG_FUNCTION_ARGS)
1533 text *databasename = PG_GETARG_TEXT_P(0);
1534 text *priv_type_text = PG_GETARG_TEXT_P(1);
1538 AclResult aclresult;
1540 usesysid = GetUserId();
1541 databaseoid = convert_database_name(databasename);
1542 mode = convert_database_priv_string(priv_type_text);
1544 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1546 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1550 * has_database_privilege_name_id
1551 * Check user privileges on a database given
1552 * name usename, database oid, and text priv name.
1555 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1557 Name username = PG_GETARG_NAME(0);
1558 Oid databaseoid = PG_GETARG_OID(1);
1559 text *priv_type_text = PG_GETARG_TEXT_P(2);
1562 AclResult aclresult;
1564 usesysid = get_usesysid(NameStr(*username));
1565 mode = convert_database_priv_string(priv_type_text);
1567 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1569 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1573 * has_database_privilege_id
1574 * Check user privileges on a database given
1575 * database oid, and text priv name.
1576 * current_user is assumed
1579 has_database_privilege_id(PG_FUNCTION_ARGS)
1581 Oid databaseoid = PG_GETARG_OID(0);
1582 text *priv_type_text = PG_GETARG_TEXT_P(1);
1585 AclResult aclresult;
1587 usesysid = GetUserId();
1588 mode = convert_database_priv_string(priv_type_text);
1590 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1592 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1596 * has_database_privilege_id_name
1597 * Check user privileges on a database given
1598 * usesysid, text databasename, and text priv name.
1601 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1603 int32 usesysid = PG_GETARG_INT32(0);
1604 text *databasename = PG_GETARG_TEXT_P(1);
1605 text *priv_type_text = PG_GETARG_TEXT_P(2);
1608 AclResult aclresult;
1610 databaseoid = convert_database_name(databasename);
1611 mode = convert_database_priv_string(priv_type_text);
1613 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1615 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1619 * has_database_privilege_id_id
1620 * Check user privileges on a database given
1621 * usesysid, database oid, and text priv name.
1624 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1626 int32 usesysid = PG_GETARG_INT32(0);
1627 Oid databaseoid = PG_GETARG_OID(1);
1628 text *priv_type_text = PG_GETARG_TEXT_P(2);
1630 AclResult aclresult;
1632 mode = convert_database_priv_string(priv_type_text);
1634 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1636 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1640 * Support routines for has_database_privilege family.
1644 * Given a database name expressed as a string, look it up and return Oid
1647 convert_database_name(text *databasename)
1652 dbname = DatumGetCString(DirectFunctionCall1(textout,
1653 PointerGetDatum(databasename)));
1655 oid = get_database_oid(dbname);
1656 if (!OidIsValid(oid))
1658 (errcode(ERRCODE_UNDEFINED_DATABASE),
1659 errmsg("database \"%s\" does not exist", dbname)));
1665 * convert_database_priv_string
1666 * Convert text string to AclMode value.
1669 convert_database_priv_string(text *priv_type_text)
1673 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1674 PointerGetDatum(priv_type_text)));
1677 * Return mode from priv_type string
1679 if (pg_strcasecmp(priv_type, "CREATE") == 0)
1681 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1682 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1684 if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
1685 return ACL_CREATE_TEMP;
1686 if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1687 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1689 if (pg_strcasecmp(priv_type, "TEMP") == 0)
1690 return ACL_CREATE_TEMP;
1691 if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1692 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1695 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1696 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1697 return ACL_NO_RIGHTS; /* keep compiler quiet */
1702 * has_function_privilege variants
1703 * These are all named "has_function_privilege" at the SQL level.
1704 * They take various combinations of function name, function OID,
1705 * user name, user sysid, or implicit user = current_user.
1707 * The result is a boolean value: true if user has the indicated
1708 * privilege, false if not.
1712 * has_function_privilege_name_name
1713 * Check user privileges on a function given
1714 * name username, text functionname, and text priv name.
1717 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1719 Name username = PG_GETARG_NAME(0);
1720 text *functionname = PG_GETARG_TEXT_P(1);
1721 text *priv_type_text = PG_GETARG_TEXT_P(2);
1725 AclResult aclresult;
1727 usesysid = get_usesysid(NameStr(*username));
1728 functionoid = convert_function_name(functionname);
1729 mode = convert_function_priv_string(priv_type_text);
1731 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1733 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1737 * has_function_privilege_name
1738 * Check user privileges on a function given
1739 * text functionname and text priv name.
1740 * current_user is assumed
1743 has_function_privilege_name(PG_FUNCTION_ARGS)
1745 text *functionname = PG_GETARG_TEXT_P(0);
1746 text *priv_type_text = PG_GETARG_TEXT_P(1);
1750 AclResult aclresult;
1752 usesysid = GetUserId();
1753 functionoid = convert_function_name(functionname);
1754 mode = convert_function_priv_string(priv_type_text);
1756 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1758 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1762 * has_function_privilege_name_id
1763 * Check user privileges on a function given
1764 * name usename, function oid, and text priv name.
1767 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1769 Name username = PG_GETARG_NAME(0);
1770 Oid functionoid = PG_GETARG_OID(1);
1771 text *priv_type_text = PG_GETARG_TEXT_P(2);
1774 AclResult aclresult;
1776 usesysid = get_usesysid(NameStr(*username));
1777 mode = convert_function_priv_string(priv_type_text);
1779 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1781 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1785 * has_function_privilege_id
1786 * Check user privileges on a function given
1787 * function oid, and text priv name.
1788 * current_user is assumed
1791 has_function_privilege_id(PG_FUNCTION_ARGS)
1793 Oid functionoid = PG_GETARG_OID(0);
1794 text *priv_type_text = PG_GETARG_TEXT_P(1);
1797 AclResult aclresult;
1799 usesysid = GetUserId();
1800 mode = convert_function_priv_string(priv_type_text);
1802 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1804 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1808 * has_function_privilege_id_name
1809 * Check user privileges on a function given
1810 * usesysid, text functionname, and text priv name.
1813 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1815 int32 usesysid = PG_GETARG_INT32(0);
1816 text *functionname = PG_GETARG_TEXT_P(1);
1817 text *priv_type_text = PG_GETARG_TEXT_P(2);
1820 AclResult aclresult;
1822 functionoid = convert_function_name(functionname);
1823 mode = convert_function_priv_string(priv_type_text);
1825 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1827 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1831 * has_function_privilege_id_id
1832 * Check user privileges on a function given
1833 * usesysid, function oid, and text priv name.
1836 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1838 int32 usesysid = PG_GETARG_INT32(0);
1839 Oid functionoid = PG_GETARG_OID(1);
1840 text *priv_type_text = PG_GETARG_TEXT_P(2);
1842 AclResult aclresult;
1844 mode = convert_function_priv_string(priv_type_text);
1846 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1848 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1852 * Support routines for has_function_privilege family.
1856 * Given a function name expressed as a string, look it up and return Oid
1859 convert_function_name(text *functionname)
1864 funcname = DatumGetCString(DirectFunctionCall1(textout,
1865 PointerGetDatum(functionname)));
1867 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1868 CStringGetDatum(funcname)));
1870 if (!OidIsValid(oid))
1872 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1873 errmsg("function \"%s\" does not exist", funcname)));
1879 * convert_function_priv_string
1880 * Convert text string to AclMode value.
1883 convert_function_priv_string(text *priv_type_text)
1887 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1888 PointerGetDatum(priv_type_text)));
1891 * Return mode from priv_type string
1893 if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1895 if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1896 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1899 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1900 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1901 return ACL_NO_RIGHTS; /* keep compiler quiet */
1906 * has_language_privilege variants
1907 * These are all named "has_language_privilege" at the SQL level.
1908 * They take various combinations of language name, language OID,
1909 * user name, user sysid, or implicit user = current_user.
1911 * The result is a boolean value: true if user has the indicated
1912 * privilege, false if not.
1916 * has_language_privilege_name_name
1917 * Check user privileges on a language given
1918 * name username, text languagename, and text priv name.
1921 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1923 Name username = PG_GETARG_NAME(0);
1924 text *languagename = PG_GETARG_TEXT_P(1);
1925 text *priv_type_text = PG_GETARG_TEXT_P(2);
1929 AclResult aclresult;
1931 usesysid = get_usesysid(NameStr(*username));
1932 languageoid = convert_language_name(languagename);
1933 mode = convert_language_priv_string(priv_type_text);
1935 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1937 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1941 * has_language_privilege_name
1942 * Check user privileges on a language given
1943 * text languagename and text priv name.
1944 * current_user is assumed
1947 has_language_privilege_name(PG_FUNCTION_ARGS)
1949 text *languagename = PG_GETARG_TEXT_P(0);
1950 text *priv_type_text = PG_GETARG_TEXT_P(1);
1954 AclResult aclresult;
1956 usesysid = GetUserId();
1957 languageoid = convert_language_name(languagename);
1958 mode = convert_language_priv_string(priv_type_text);
1960 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1962 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1966 * has_language_privilege_name_id
1967 * Check user privileges on a language given
1968 * name usename, language oid, and text priv name.
1971 has_language_privilege_name_id(PG_FUNCTION_ARGS)
1973 Name username = PG_GETARG_NAME(0);
1974 Oid languageoid = PG_GETARG_OID(1);
1975 text *priv_type_text = PG_GETARG_TEXT_P(2);
1978 AclResult aclresult;
1980 usesysid = get_usesysid(NameStr(*username));
1981 mode = convert_language_priv_string(priv_type_text);
1983 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1985 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1989 * has_language_privilege_id
1990 * Check user privileges on a language given
1991 * language oid, and text priv name.
1992 * current_user is assumed
1995 has_language_privilege_id(PG_FUNCTION_ARGS)
1997 Oid languageoid = PG_GETARG_OID(0);
1998 text *priv_type_text = PG_GETARG_TEXT_P(1);
2001 AclResult aclresult;
2003 usesysid = GetUserId();
2004 mode = convert_language_priv_string(priv_type_text);
2006 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
2008 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2012 * has_language_privilege_id_name
2013 * Check user privileges on a language given
2014 * usesysid, text languagename, and text priv name.
2017 has_language_privilege_id_name(PG_FUNCTION_ARGS)
2019 int32 usesysid = PG_GETARG_INT32(0);
2020 text *languagename = PG_GETARG_TEXT_P(1);
2021 text *priv_type_text = PG_GETARG_TEXT_P(2);
2024 AclResult aclresult;
2026 languageoid = convert_language_name(languagename);
2027 mode = convert_language_priv_string(priv_type_text);
2029 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
2031 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2035 * has_language_privilege_id_id
2036 * Check user privileges on a language given
2037 * usesysid, language oid, and text priv name.
2040 has_language_privilege_id_id(PG_FUNCTION_ARGS)
2042 int32 usesysid = PG_GETARG_INT32(0);
2043 Oid languageoid = PG_GETARG_OID(1);
2044 text *priv_type_text = PG_GETARG_TEXT_P(2);
2046 AclResult aclresult;
2048 mode = convert_language_priv_string(priv_type_text);
2050 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
2052 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2056 * Support routines for has_language_privilege family.
2060 * Given a language name expressed as a string, look it up and return Oid
2063 convert_language_name(text *languagename)
2068 langname = DatumGetCString(DirectFunctionCall1(textout,
2069 PointerGetDatum(languagename)));
2071 oid = GetSysCacheOid(LANGNAME,
2072 CStringGetDatum(langname),
2074 if (!OidIsValid(oid))
2076 (errcode(ERRCODE_UNDEFINED_OBJECT),
2077 errmsg("language \"%s\" does not exist", langname)));
2083 * convert_language_priv_string
2084 * Convert text string to AclMode value.
2087 convert_language_priv_string(text *priv_type_text)
2091 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2092 PointerGetDatum(priv_type_text)));
2095 * Return mode from priv_type string
2097 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2099 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2100 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2103 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2104 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2105 return ACL_NO_RIGHTS; /* keep compiler quiet */
2110 * has_schema_privilege variants
2111 * These are all named "has_schema_privilege" at the SQL level.
2112 * They take various combinations of schema name, schema OID,
2113 * user name, user sysid, or implicit user = current_user.
2115 * The result is a boolean value: true if user has the indicated
2116 * privilege, false if not.
2120 * has_schema_privilege_name_name
2121 * Check user privileges on a schema given
2122 * name username, text schemaname, and text priv name.
2125 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
2127 Name username = PG_GETARG_NAME(0);
2128 text *schemaname = PG_GETARG_TEXT_P(1);
2129 text *priv_type_text = PG_GETARG_TEXT_P(2);
2133 AclResult aclresult;
2135 usesysid = get_usesysid(NameStr(*username));
2136 schemaoid = convert_schema_name(schemaname);
2137 mode = convert_schema_priv_string(priv_type_text);
2139 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2141 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2145 * has_schema_privilege_name
2146 * Check user privileges on a schema given
2147 * text schemaname and text priv name.
2148 * current_user is assumed
2151 has_schema_privilege_name(PG_FUNCTION_ARGS)
2153 text *schemaname = PG_GETARG_TEXT_P(0);
2154 text *priv_type_text = PG_GETARG_TEXT_P(1);
2158 AclResult aclresult;
2160 usesysid = GetUserId();
2161 schemaoid = convert_schema_name(schemaname);
2162 mode = convert_schema_priv_string(priv_type_text);
2164 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2166 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2170 * has_schema_privilege_name_id
2171 * Check user privileges on a schema given
2172 * name usename, schema oid, and text priv name.
2175 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
2177 Name username = PG_GETARG_NAME(0);
2178 Oid schemaoid = PG_GETARG_OID(1);
2179 text *priv_type_text = PG_GETARG_TEXT_P(2);
2182 AclResult aclresult;
2184 usesysid = get_usesysid(NameStr(*username));
2185 mode = convert_schema_priv_string(priv_type_text);
2187 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2189 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2193 * has_schema_privilege_id
2194 * Check user privileges on a schema given
2195 * schema oid, and text priv name.
2196 * current_user is assumed
2199 has_schema_privilege_id(PG_FUNCTION_ARGS)
2201 Oid schemaoid = PG_GETARG_OID(0);
2202 text *priv_type_text = PG_GETARG_TEXT_P(1);
2205 AclResult aclresult;
2207 usesysid = GetUserId();
2208 mode = convert_schema_priv_string(priv_type_text);
2210 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2212 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2216 * has_schema_privilege_id_name
2217 * Check user privileges on a schema given
2218 * usesysid, text schemaname, and text priv name.
2221 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
2223 int32 usesysid = PG_GETARG_INT32(0);
2224 text *schemaname = PG_GETARG_TEXT_P(1);
2225 text *priv_type_text = PG_GETARG_TEXT_P(2);
2228 AclResult aclresult;
2230 schemaoid = convert_schema_name(schemaname);
2231 mode = convert_schema_priv_string(priv_type_text);
2233 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2235 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2239 * has_schema_privilege_id_id
2240 * Check user privileges on a schema given
2241 * usesysid, schema oid, and text priv name.
2244 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
2246 int32 usesysid = PG_GETARG_INT32(0);
2247 Oid schemaoid = PG_GETARG_OID(1);
2248 text *priv_type_text = PG_GETARG_TEXT_P(2);
2250 AclResult aclresult;
2252 mode = convert_schema_priv_string(priv_type_text);
2254 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
2256 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2260 * Support routines for has_schema_privilege family.
2264 * Given a schema name expressed as a string, look it up and return Oid
2267 convert_schema_name(text *schemaname)
2272 nspname = DatumGetCString(DirectFunctionCall1(textout,
2273 PointerGetDatum(schemaname)));
2275 oid = GetSysCacheOid(NAMESPACENAME,
2276 CStringGetDatum(nspname),
2278 if (!OidIsValid(oid))
2280 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2281 errmsg("schema \"%s\" does not exist", nspname)));
2287 * convert_schema_priv_string
2288 * Convert text string to AclMode value.
2291 convert_schema_priv_string(text *priv_type_text)
2295 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2296 PointerGetDatum(priv_type_text)));
2299 * Return mode from priv_type string
2301 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2303 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2304 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2306 if (pg_strcasecmp(priv_type, "USAGE") == 0)
2308 if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
2309 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
2312 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2313 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2314 return ACL_NO_RIGHTS; /* keep compiler quiet */
2318 * has_tablespace_privilege variants
2319 * These are all named "has_tablespace_privilege" at the SQL level.
2320 * They take various combinations of tablespace name, tablespace OID,
2321 * user name, user sysid, or implicit user = current_user.
2323 * The result is a boolean value: true if user has the indicated
2324 * privilege, false if not.
2328 * has_tablespace_privilege_name_name
2329 * Check user privileges on a tablespace given
2330 * name username, text tablespacename, and text priv name.
2333 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
2335 Name username = PG_GETARG_NAME(0);
2336 text *tablespacename = PG_GETARG_TEXT_P(1);
2337 text *priv_type_text = PG_GETARG_TEXT_P(2);
2341 AclResult aclresult;
2343 usesysid = get_usesysid(NameStr(*username));
2344 tablespaceoid = convert_tablespace_name(tablespacename);
2345 mode = convert_tablespace_priv_string(priv_type_text);
2347 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2349 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2353 * has_tablespace_privilege_name
2354 * Check user privileges on a tablespace given
2355 * text tablespacename and text priv name.
2356 * current_user is assumed
2359 has_tablespace_privilege_name(PG_FUNCTION_ARGS)
2361 text *tablespacename = PG_GETARG_TEXT_P(0);
2362 text *priv_type_text = PG_GETARG_TEXT_P(1);
2366 AclResult aclresult;
2368 usesysid = GetUserId();
2369 tablespaceoid = convert_tablespace_name(tablespacename);
2370 mode = convert_tablespace_priv_string(priv_type_text);
2372 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2374 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2378 * has_tablespace_privilege_name_id
2379 * Check user privileges on a tablespace given
2380 * name usename, tablespace oid, and text priv name.
2383 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
2385 Name username = PG_GETARG_NAME(0);
2386 Oid tablespaceoid = PG_GETARG_OID(1);
2387 text *priv_type_text = PG_GETARG_TEXT_P(2);
2390 AclResult aclresult;
2392 usesysid = get_usesysid(NameStr(*username));
2393 mode = convert_tablespace_priv_string(priv_type_text);
2395 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2397 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2401 * has_tablespace_privilege_id
2402 * Check user privileges on a tablespace given
2403 * tablespace oid, and text priv name.
2404 * current_user is assumed
2407 has_tablespace_privilege_id(PG_FUNCTION_ARGS)
2409 Oid tablespaceoid = PG_GETARG_OID(0);
2410 text *priv_type_text = PG_GETARG_TEXT_P(1);
2413 AclResult aclresult;
2415 usesysid = GetUserId();
2416 mode = convert_tablespace_priv_string(priv_type_text);
2418 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2420 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2424 * has_tablespace_privilege_id_name
2425 * Check user privileges on a tablespace given
2426 * usesysid, text tablespacename, and text priv name.
2429 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
2431 int32 usesysid = PG_GETARG_INT32(0);
2432 text *tablespacename = PG_GETARG_TEXT_P(1);
2433 text *priv_type_text = PG_GETARG_TEXT_P(2);
2436 AclResult aclresult;
2438 tablespaceoid = convert_tablespace_name(tablespacename);
2439 mode = convert_tablespace_priv_string(priv_type_text);
2441 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2443 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2447 * has_tablespace_privilege_id_id
2448 * Check user privileges on a tablespace given
2449 * usesysid, tablespace oid, and text priv name.
2452 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
2454 int32 usesysid = PG_GETARG_INT32(0);
2455 Oid tablespaceoid = PG_GETARG_OID(1);
2456 text *priv_type_text = PG_GETARG_TEXT_P(2);
2458 AclResult aclresult;
2460 mode = convert_tablespace_priv_string(priv_type_text);
2462 aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode);
2464 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2468 * Support routines for has_tablespace_privilege family.
2472 * Given a tablespace name expressed as a string, look it up and return Oid
2475 convert_tablespace_name(text *tablespacename)
2480 spcname = DatumGetCString(DirectFunctionCall1(textout,
2481 PointerGetDatum(tablespacename)));
2482 oid = get_tablespace_oid(spcname);
2484 if (!OidIsValid(oid))
2486 (errcode(ERRCODE_UNDEFINED_OBJECT),
2487 errmsg("tablespace \"%s\" does not exist", spcname)));
2493 * convert_tablespace_priv_string
2494 * Convert text string to AclMode value.
2497 convert_tablespace_priv_string(text *priv_type_text)
2501 priv_type = DatumGetCString(DirectFunctionCall1(textout,
2502 PointerGetDatum(priv_type_text)));
2505 * Return mode from priv_type string
2507 if (pg_strcasecmp(priv_type, "CREATE") == 0)
2509 if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
2510 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
2513 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2514 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
2515 return ACL_NO_RIGHTS; /* keep compiler quiet */