1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.87 2003/06/02 19:00:29 tgl Exp $
13 *-------------------------------------------------------------------------
19 #include "catalog/namespace.h"
20 #include "catalog/pg_shadow.h"
21 #include "catalog/pg_type.h"
22 #include "commands/dbcommands.h"
23 #include "miscadmin.h"
24 #include "utils/acl.h"
25 #include "utils/builtins.h"
26 #include "utils/lsyscache.h"
27 #include "utils/syscache.h"
30 #define ACL_IDTYPE_GID_KEYWORD "group"
31 #define ACL_IDTYPE_UID_KEYWORD "user"
33 static const char *getid(const char *s, char *n);
34 static void putid(char *p, const char *s);
35 static Acl *makeacl(int n);
36 static const char *aclparse(const char *s, AclItem *aip);
37 static bool aclitemeq(const AclItem *a1, const AclItem *a2);
38 static Acl *recursive_revoke(Acl *acl, AclId grantee,
39 AclMode revoke_privs, DropBehavior behavior);
41 static Oid convert_table_name(text *tablename);
42 static AclMode convert_table_priv_string(text *priv_type_text);
43 static Oid convert_database_name(text *databasename);
44 static AclMode convert_database_priv_string(text *priv_type_text);
45 static Oid convert_function_name(text *functionname);
46 static AclMode convert_function_priv_string(text *priv_type_text);
47 static Oid convert_language_name(text *languagename);
48 static AclMode convert_language_priv_string(text *priv_type_text);
49 static Oid convert_schema_name(text *schemaname);
50 static AclMode convert_schema_priv_string(text *priv_type_text);
55 * Consumes the first alphanumeric string (identifier) found in string
56 * 's', ignoring any leading white space. If it finds a double quote
57 * it returns the word inside the quotes.
60 * the string position in 's' that points to the next non-space character
61 * in 's', after any quotes. Also:
62 * - loads the identifier into 'name'. (If no identifier is found, 'name'
63 * contains an empty string.) name must be NAMEDATALEN bytes.
66 getid(const char *s, char *n)
69 bool in_quotes = false;
73 while (isspace((unsigned char) *s))
75 /* This test had better match what putid() does, below */
78 (isalnum((unsigned char) *s) ||
86 in_quotes = !in_quotes;
90 if (len >= NAMEDATALEN-1)
91 elog(ERROR, "identifier must be less than %d characters",
97 while (isspace((unsigned char) *s))
103 * Write a user or group Name at *p, surrounding it with double quotes if
104 * needed. There must be at least NAMEDATALEN+2 bytes available at *p.
107 putid(char *p, const char *s)
112 for (src = s; *src; src++)
114 /* This test had better match what getid() does, above */
115 if (!isalnum((unsigned char) *src) && *src != '_')
123 for (src = s; *src; src++)
132 * Consumes and parses an ACL specification of the form:
133 * [group|user] [A-Za-z0-9]*=[rwaR]*
134 * from string 's', ignoring any leading white space or white space
135 * between the optional id type keyword (group|user) and the actual
138 * This routine is called by the parser as well as aclitemin(), hence
139 * the added generality.
142 * the string position in 's' immediately following the ACL
143 * specification. Also:
144 * - loads the structure pointed to by 'aip' with the appropriate
145 * UID/GID, id type identifier and mode type values.
148 aclparse(const char *s, AclItem *aip)
150 AclMode privs, goption, read;
152 char name[NAMEDATALEN];
153 char name2[NAMEDATALEN];
158 elog(LOG, "aclparse: input = '%s'", s);
160 idtype = ACL_IDTYPE_UID;
164 /* we just read a keyword, not a name */
165 if (strncmp(name, ACL_IDTYPE_GID_KEYWORD, sizeof(name)) == 0)
166 idtype = ACL_IDTYPE_GID;
167 else if (strncmp(name, ACL_IDTYPE_UID_KEYWORD, sizeof(name)) != 0)
168 elog(ERROR, "aclparse: bad keyword, must be [group|user]");
169 s = getid(s, name); /* move s to the name beyond the keyword */
171 elog(ERROR, "aclparse: a name must follow the [group|user] keyword");
174 idtype = ACL_IDTYPE_WORLD;
177 elog(ERROR, "aclparse: expecting \"=\" sign");
179 privs = goption = ACL_NO_RIGHTS;
181 for (++s, read=0; isalpha((unsigned char) *s) || *s == '*'; s++)
203 case ACL_REFERENCES_CHR:
204 read = ACL_REFERENCES;
206 case ACL_TRIGGER_CHR:
209 case ACL_EXECUTE_CHR:
218 case ACL_CREATE_TEMP_CHR:
219 read = ACL_CREATE_TEMP;
222 elog(ERROR, "aclparse: mode flags must use \"%s\"",
232 aip->ai_grantee = get_usesysid(name);
235 aip->ai_grantee = get_grosysid(name);
237 case ACL_IDTYPE_WORLD:
238 aip->ai_grantee = ACL_ID_WORLD;
242 /* XXX Allow a degree of backward compatibility by defaulting the
243 * grantor to the superuser. */
246 s = getid(s + 1, name2);
247 if (name2[0] == '\0')
248 elog(ERROR, "aclparse: a name must follow the \"/\" sign");
250 aip->ai_grantor = get_usesysid(name2);
254 aip->ai_grantor = BOOTSTRAP_USESYSID;
255 elog(WARNING, "defaulting grantor to %u", BOOTSTRAP_USESYSID);
258 ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, goption, idtype);
261 elog(LOG, "aclparse: correctly read [%x %d %x]",
262 idtype, aip->ai_grantee, privs);
269 * Allocates storage for a new Acl with 'n' entries.
281 elog(ERROR, "makeacl: invalid size: %d", n);
282 size = ACL_N_SIZE(n);
283 new_acl = (Acl *) palloc0(size);
284 new_acl->size = size;
287 new_acl->elemtype = ACLITEMOID;
288 ARR_LBOUND(new_acl)[0] = 0;
289 ARR_DIMS(new_acl)[0] = n;
295 * Allocates storage for, and fills in, a new AclItem given a string
296 * 's' that contains an ACL specification. See aclparse for details.
302 aclitemin(PG_FUNCTION_ARGS)
304 const char *s = PG_GETARG_CSTRING(0);
307 aip = (AclItem *) palloc(sizeof(AclItem));
308 s = aclparse(s, aip);
309 while (isspace((unsigned char) *s))
312 elog(ERROR, "aclitemin: extra garbage at end of specification");
313 PG_RETURN_ACLITEM_P(aip);
318 * Allocates storage for, and fills in, a new null-delimited string
319 * containing a formatted ACL specification. See aclparse for details.
325 aclitemout(PG_FUNCTION_ARGS)
327 AclItem *aip = PG_GETARG_ACLITEM_P(0);
334 out = palloc(strlen("group =/") +
336 2 * (NAMEDATALEN+2) +
342 switch (ACLITEM_GET_IDTYPE(*aip))
345 htup = SearchSysCache(SHADOWSYSID,
346 ObjectIdGetDatum(aip->ai_grantee),
348 if (HeapTupleIsValid(htup))
350 putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename));
351 ReleaseSysCache(htup);
355 /* Generate numeric UID if we don't find an entry */
356 sprintf(p, "%d", aip->ai_grantee);
362 tmpname = get_groname(aip->ai_grantee);
367 /* Generate numeric GID if we don't find an entry */
368 sprintf(p, "%d", aip->ai_grantee);
371 case ACL_IDTYPE_WORLD:
374 elog(ERROR, "aclitemout: bad idtype: %d",
375 ACLITEM_GET_IDTYPE(*aip));
383 for (i = 0; i < N_ACL_RIGHTS; ++i)
385 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
386 *p++ = ACL_ALL_RIGHTS_STR[i];
387 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
394 htup = SearchSysCache(SHADOWSYSID,
395 ObjectIdGetDatum(aip->ai_grantor),
397 if (HeapTupleIsValid(htup))
399 putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename));
400 ReleaseSysCache(htup);
404 /* Generate numeric UID if we don't find an entry */
405 sprintf(p, "%d", aip->ai_grantor);
412 PG_RETURN_CSTRING(out);
417 * Two AclItems are considered equal iff they have the same
418 * grantee and grantor; the privileges are ignored.
421 aclitemeq(const AclItem *a1, const AclItem *a2)
423 return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
424 a1->ai_grantee == a2->ai_grantee &&
425 a1->ai_grantor == a2->ai_grantor;
430 * acldefault() --- create an ACL describing default access permissions
432 * Change this routine if you want to alter the default access policy for
433 * newly-created objects (or any object with a NULL acl entry).
436 acldefault(GrantObjectType objtype, AclId ownerid)
438 AclMode world_default;
439 AclMode owner_default;
445 case ACL_OBJECT_RELATION:
446 world_default = ACL_NO_RIGHTS;
447 owner_default = ACL_ALL_RIGHTS_RELATION;
449 case ACL_OBJECT_DATABASE:
450 world_default = ACL_CREATE_TEMP; /* not NO_RIGHTS! */
451 owner_default = ACL_ALL_RIGHTS_DATABASE;
453 case ACL_OBJECT_FUNCTION:
454 /* Grant EXECUTE by default, for now */
455 world_default = ACL_EXECUTE;
456 owner_default = ACL_ALL_RIGHTS_FUNCTION;
458 case ACL_OBJECT_LANGUAGE:
459 /* Grant USAGE by default, for now */
460 world_default = ACL_USAGE;
461 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
463 case ACL_OBJECT_NAMESPACE:
464 world_default = ACL_NO_RIGHTS;
465 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
468 elog(ERROR, "acldefault: bogus objtype %d", (int) objtype);
469 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
470 owner_default = ACL_NO_RIGHTS;
474 acl = makeacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
475 + (ownerid ? 1 : 0));
478 if (world_default != ACL_NO_RIGHTS)
480 aip[0].ai_grantee = ACL_ID_WORLD;
481 aip[0].ai_grantor = ownerid;
482 ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_NO_RIGHTS, ACL_IDTYPE_WORLD);
487 int index = (world_default != ACL_NO_RIGHTS ? 1: 0);
489 aip[index].ai_grantee = ownerid;
490 aip[index].ai_grantor = ownerid;
491 /* owner gets default privileges with grant option */
492 ACLITEM_SET_PRIVS_IDTYPE(aip[index], owner_default, owner_default, ACL_IDTYPE_UID);
500 * Add or replace an item in an ACL array. The result is a modified copy;
501 * the input object is not changed.
503 * NB: caller is responsible for having detoasted the input ACL, if needed.
506 aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBehavior behavior)
514 /* These checks for null input are probably dead code, but... */
515 if (!old_acl || ACL_NUM(old_acl) < 1)
516 old_acl = makeacl(1);
519 new_acl = makeacl(ACL_NUM(old_acl));
520 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
524 num = ACL_NUM(old_acl);
525 old_aip = ACL_DAT(old_acl);
528 * Search the ACL for an existing entry for this grantee and
529 * grantor. If one exists, just modify the entry in-place (well,
530 * in the same position, since we actually return a copy);
531 * otherwise, insert the new entry at the end.
534 for (dst = 0; dst < num; ++dst)
536 if (aclitemeq(mod_aip, old_aip + dst))
538 /* found a match, so modify existing item */
539 new_acl = makeacl(num);
540 new_aip = ACL_DAT(new_acl);
541 memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
548 /* need to append a new item */
549 new_acl = makeacl(num + 1);
550 new_aip = ACL_DAT(new_acl);
551 memcpy(new_aip, old_aip, num * sizeof(AclItem));
553 /* initialize the new entry with no permissions */
554 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
555 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
556 ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACL_NO_RIGHTS, ACL_NO_RIGHTS,
557 ACLITEM_GET_IDTYPE(*mod_aip));
558 num++; /* set num to the size of new_acl */
561 /* apply the permissions mod */
564 case ACL_MODECHG_ADD:
565 ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) | ACLITEM_GET_PRIVS(*mod_aip));
566 ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) | ACLITEM_GET_GOPTIONS(*mod_aip));
568 case ACL_MODECHG_DEL:
569 ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) & ~ACLITEM_GET_PRIVS(*mod_aip));
570 ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) & ~ACLITEM_GET_GOPTIONS(*mod_aip));
572 case ACL_MODECHG_EQL:
573 ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
574 ACLITEM_GET_PRIVS(*mod_aip),
575 ACLITEM_GET_GOPTIONS(*mod_aip),
576 ACLITEM_GET_IDTYPE(new_aip[dst]));
581 * If the adjusted entry has no permissions, delete it from the list.
583 if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS)
585 memmove(new_aip + dst,
587 (num - dst - 1) * sizeof(AclItem));
588 ARR_DIMS(new_acl)[0] = num - 1;
589 ARR_SIZE(new_acl) -= sizeof(AclItem);
593 * Remove abandoned privileges (cascading revoke)
595 if (modechg != ACL_MODECHG_ADD
596 && ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID
597 && ACLITEM_GET_GOPTIONS(*mod_aip))
598 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee, ACLITEM_GET_GOPTIONS(*mod_aip), behavior);
605 * Ensure that no privilege is "abandoned". A privilege is abandoned
606 * if the user that granted the privilege loses the grant option. (So
607 * the chain through which it was granted is broken.) Either the
608 * abandoned privileges are revoked as well, or an error message is
609 * printed, depending on the drop behavior option.
612 recursive_revoke(Acl *acl,
614 AclMode revoke_privs,
615 DropBehavior behavior)
620 for (i = 0; i < ACL_NUM(acl); i++)
622 AclItem *aip = ACL_DAT(acl);
624 if (aip[i].ai_grantor == grantee
625 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
629 if (behavior == DROP_RESTRICT)
630 elog(ERROR, "dependent privileges exist (use CASCADE to revoke them too)");
632 mod_acl.ai_grantor = grantee;
633 mod_acl.ai_grantee = aip[i].ai_grantee;
634 ACLITEM_SET_PRIVS_IDTYPE(mod_acl,
637 ACLITEM_GET_IDTYPE(aip[i]));
639 acl = aclinsert3(acl, &mod_acl, ACL_MODECHG_DEL, behavior);
649 * aclinsert (exported function)
652 aclinsert(PG_FUNCTION_ARGS)
654 Acl *old_acl = PG_GETARG_ACL_P(0);
655 AclItem *mod_aip = PG_GETARG_ACLITEM_P(1);
657 PG_RETURN_ACL_P(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL, DROP_CASCADE));
661 aclremove(PG_FUNCTION_ARGS)
663 Acl *old_acl = PG_GETARG_ACL_P(0);
664 AclItem *mod_aip = PG_GETARG_ACLITEM_P(1);
672 /* These checks for null input should be dead code, but... */
673 if (!old_acl || ACL_NUM(old_acl) < 1)
674 old_acl = makeacl(1);
677 new_acl = makeacl(ACL_NUM(old_acl));
678 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
679 PG_RETURN_ACL_P(new_acl);
682 old_num = ACL_NUM(old_acl);
683 old_aip = ACL_DAT(old_acl);
685 /* Search for the matching entry */
686 for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip + dst); ++dst)
691 /* Not found, so return copy of source ACL */
692 new_acl = makeacl(old_num);
693 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
697 new_num = old_num - 1;
698 new_acl = makeacl(new_num);
699 new_aip = ACL_DAT(new_acl);
702 elog(ERROR, "aclremove: removal of the world ACL??");
704 else if (dst == old_num - 1)
706 memcpy((char *) new_aip,
708 new_num * sizeof(AclItem));
712 memcpy((char *) new_aip,
714 dst * sizeof(AclItem));
715 memcpy((char *) (new_aip + dst),
716 (char *) (old_aip + dst + 1),
717 (new_num - dst) * sizeof(AclItem));
721 PG_RETURN_ACL_P(new_acl);
725 aclcontains(PG_FUNCTION_ARGS)
727 Acl *acl = PG_GETARG_ACL_P(0);
728 AclItem *aip = PG_GETARG_ACLITEM_P(1);
734 aidat = ACL_DAT(acl);
735 for (i = 0; i < num; ++i)
737 if (aip->ai_grantee == aidat[i].ai_grantee &&
738 aip->ai_privs == aidat[i].ai_privs)
739 PG_RETURN_BOOL(true);
741 PG_RETURN_BOOL(false);
746 * has_table_privilege variants
747 * These are all named "has_table_privilege" at the SQL level.
748 * They take various combinations of relation name, relation OID,
749 * user name, user sysid, or implicit user = current_user.
751 * The result is a boolean value: true if user has the indicated
752 * privilege, false if not.
756 * has_table_privilege_name_name
757 * Check user privileges on a table given
758 * name username, text tablename, and text priv name.
761 has_table_privilege_name_name(PG_FUNCTION_ARGS)
763 Name username = PG_GETARG_NAME(0);
764 text *tablename = PG_GETARG_TEXT_P(1);
765 text *priv_type_text = PG_GETARG_TEXT_P(2);
771 usesysid = get_usesysid(NameStr(*username));
772 tableoid = convert_table_name(tablename);
773 mode = convert_table_priv_string(priv_type_text);
775 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
777 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
781 * has_table_privilege_name
782 * Check user privileges on a table given
783 * text tablename and text priv name.
784 * current_user is assumed
787 has_table_privilege_name(PG_FUNCTION_ARGS)
789 text *tablename = PG_GETARG_TEXT_P(0);
790 text *priv_type_text = PG_GETARG_TEXT_P(1);
796 usesysid = GetUserId();
797 tableoid = convert_table_name(tablename);
798 mode = convert_table_priv_string(priv_type_text);
800 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
802 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
806 * has_table_privilege_name_id
807 * Check user privileges on a table given
808 * name usename, table oid, and text priv name.
811 has_table_privilege_name_id(PG_FUNCTION_ARGS)
813 Name username = PG_GETARG_NAME(0);
814 Oid tableoid = PG_GETARG_OID(1);
815 text *priv_type_text = PG_GETARG_TEXT_P(2);
820 usesysid = get_usesysid(NameStr(*username));
821 mode = convert_table_priv_string(priv_type_text);
823 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
825 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
829 * has_table_privilege_id
830 * Check user privileges on a table given
831 * table oid, and text priv name.
832 * current_user is assumed
835 has_table_privilege_id(PG_FUNCTION_ARGS)
837 Oid tableoid = PG_GETARG_OID(0);
838 text *priv_type_text = PG_GETARG_TEXT_P(1);
843 usesysid = GetUserId();
844 mode = convert_table_priv_string(priv_type_text);
846 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
848 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
852 * has_table_privilege_id_name
853 * Check user privileges on a table given
854 * usesysid, text tablename, and text priv name.
857 has_table_privilege_id_name(PG_FUNCTION_ARGS)
859 int32 usesysid = PG_GETARG_INT32(0);
860 text *tablename = PG_GETARG_TEXT_P(1);
861 text *priv_type_text = PG_GETARG_TEXT_P(2);
866 tableoid = convert_table_name(tablename);
867 mode = convert_table_priv_string(priv_type_text);
869 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
871 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
875 * has_table_privilege_id_id
876 * Check user privileges on a table given
877 * usesysid, table oid, and text priv name.
880 has_table_privilege_id_id(PG_FUNCTION_ARGS)
882 int32 usesysid = PG_GETARG_INT32(0);
883 Oid tableoid = PG_GETARG_OID(1);
884 text *priv_type_text = PG_GETARG_TEXT_P(2);
888 mode = convert_table_priv_string(priv_type_text);
890 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
892 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
896 * Support routines for has_table_privilege family.
900 * Given a table name expressed as a string, look it up and return Oid
903 convert_table_name(text *tablename)
907 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename,
908 "has_table_privilege"));
910 return RangeVarGetRelid(relrv, false);
914 * convert_table_priv_string
915 * Convert text string to AclMode value.
918 convert_table_priv_string(text *priv_type_text)
922 priv_type = DatumGetCString(DirectFunctionCall1(textout,
923 PointerGetDatum(priv_type_text)));
926 * Return mode from priv_type string
928 if (strcasecmp(priv_type, "SELECT") == 0)
930 if (strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
931 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
933 if (strcasecmp(priv_type, "INSERT") == 0)
935 if (strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
936 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
938 if (strcasecmp(priv_type, "UPDATE") == 0)
940 if (strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
941 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
943 if (strcasecmp(priv_type, "DELETE") == 0)
945 if (strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
946 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
948 if (strcasecmp(priv_type, "RULE") == 0)
950 if (strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
951 return ACL_GRANT_OPTION_FOR(ACL_RULE);
953 if (strcasecmp(priv_type, "REFERENCES") == 0)
954 return ACL_REFERENCES;
955 if (strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
956 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
958 if (strcasecmp(priv_type, "TRIGGER") == 0)
960 if (strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
961 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
963 elog(ERROR, "has_table_privilege: invalid privilege type %s",
965 return ACL_NO_RIGHTS; /* keep compiler quiet */
970 * has_database_privilege variants
971 * These are all named "has_database_privilege" at the SQL level.
972 * They take various combinations of database name, database OID,
973 * user name, user sysid, or implicit user = current_user.
975 * The result is a boolean value: true if user has the indicated
976 * privilege, false if not.
980 * has_database_privilege_name_name
981 * Check user privileges on a database given
982 * name username, text databasename, and text priv name.
985 has_database_privilege_name_name(PG_FUNCTION_ARGS)
987 Name username = PG_GETARG_NAME(0);
988 text *databasename = PG_GETARG_TEXT_P(1);
989 text *priv_type_text = PG_GETARG_TEXT_P(2);
995 usesysid = get_usesysid(NameStr(*username));
996 databaseoid = convert_database_name(databasename);
997 mode = convert_database_priv_string(priv_type_text);
999 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1001 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1005 * has_database_privilege_name
1006 * Check user privileges on a database given
1007 * text databasename and text priv name.
1008 * current_user is assumed
1011 has_database_privilege_name(PG_FUNCTION_ARGS)
1013 text *databasename = PG_GETARG_TEXT_P(0);
1014 text *priv_type_text = PG_GETARG_TEXT_P(1);
1018 AclResult aclresult;
1020 usesysid = GetUserId();
1021 databaseoid = convert_database_name(databasename);
1022 mode = convert_database_priv_string(priv_type_text);
1024 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1026 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1030 * has_database_privilege_name_id
1031 * Check user privileges on a database given
1032 * name usename, database oid, and text priv name.
1035 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1037 Name username = PG_GETARG_NAME(0);
1038 Oid databaseoid = PG_GETARG_OID(1);
1039 text *priv_type_text = PG_GETARG_TEXT_P(2);
1042 AclResult aclresult;
1044 usesysid = get_usesysid(NameStr(*username));
1045 mode = convert_database_priv_string(priv_type_text);
1047 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1049 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1053 * has_database_privilege_id
1054 * Check user privileges on a database given
1055 * database oid, and text priv name.
1056 * current_user is assumed
1059 has_database_privilege_id(PG_FUNCTION_ARGS)
1061 Oid databaseoid = PG_GETARG_OID(0);
1062 text *priv_type_text = PG_GETARG_TEXT_P(1);
1065 AclResult aclresult;
1067 usesysid = GetUserId();
1068 mode = convert_database_priv_string(priv_type_text);
1070 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1072 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1076 * has_database_privilege_id_name
1077 * Check user privileges on a database given
1078 * usesysid, text databasename, and text priv name.
1081 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1083 int32 usesysid = PG_GETARG_INT32(0);
1084 text *databasename = PG_GETARG_TEXT_P(1);
1085 text *priv_type_text = PG_GETARG_TEXT_P(2);
1088 AclResult aclresult;
1090 databaseoid = convert_database_name(databasename);
1091 mode = convert_database_priv_string(priv_type_text);
1093 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1095 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1099 * has_database_privilege_id_id
1100 * Check user privileges on a database given
1101 * usesysid, database oid, and text priv name.
1104 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1106 int32 usesysid = PG_GETARG_INT32(0);
1107 Oid databaseoid = PG_GETARG_OID(1);
1108 text *priv_type_text = PG_GETARG_TEXT_P(2);
1110 AclResult aclresult;
1112 mode = convert_database_priv_string(priv_type_text);
1114 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1116 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1120 * Support routines for has_database_privilege family.
1124 * Given a database name expressed as a string, look it up and return Oid
1127 convert_database_name(text *databasename)
1132 dbname = DatumGetCString(DirectFunctionCall1(textout,
1133 PointerGetDatum(databasename)));
1135 oid = get_database_oid(dbname);
1136 if (!OidIsValid(oid))
1137 elog(ERROR, "database \"%s\" does not exist", dbname);
1143 * convert_database_priv_string
1144 * Convert text string to AclMode value.
1147 convert_database_priv_string(text *priv_type_text)
1151 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1152 PointerGetDatum(priv_type_text)));
1155 * Return mode from priv_type string
1157 if (strcasecmp(priv_type, "CREATE") == 0)
1159 if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1160 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1162 if (strcasecmp(priv_type, "TEMPORARY") == 0)
1163 return ACL_CREATE_TEMP;
1164 if (strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1165 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1167 if (strcasecmp(priv_type, "TEMP") == 0)
1168 return ACL_CREATE_TEMP;
1169 if (strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1170 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1172 elog(ERROR, "has_database_privilege: invalid privilege type %s",
1174 return ACL_NO_RIGHTS; /* keep compiler quiet */
1179 * has_function_privilege variants
1180 * These are all named "has_function_privilege" at the SQL level.
1181 * They take various combinations of function name, function OID,
1182 * user name, user sysid, or implicit user = current_user.
1184 * The result is a boolean value: true if user has the indicated
1185 * privilege, false if not.
1189 * has_function_privilege_name_name
1190 * Check user privileges on a function given
1191 * name username, text functionname, and text priv name.
1194 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1196 Name username = PG_GETARG_NAME(0);
1197 text *functionname = PG_GETARG_TEXT_P(1);
1198 text *priv_type_text = PG_GETARG_TEXT_P(2);
1202 AclResult aclresult;
1204 usesysid = get_usesysid(NameStr(*username));
1205 functionoid = convert_function_name(functionname);
1206 mode = convert_function_priv_string(priv_type_text);
1208 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1210 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1214 * has_function_privilege_name
1215 * Check user privileges on a function given
1216 * text functionname and text priv name.
1217 * current_user is assumed
1220 has_function_privilege_name(PG_FUNCTION_ARGS)
1222 text *functionname = PG_GETARG_TEXT_P(0);
1223 text *priv_type_text = PG_GETARG_TEXT_P(1);
1227 AclResult aclresult;
1229 usesysid = GetUserId();
1230 functionoid = convert_function_name(functionname);
1231 mode = convert_function_priv_string(priv_type_text);
1233 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1235 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1239 * has_function_privilege_name_id
1240 * Check user privileges on a function given
1241 * name usename, function oid, and text priv name.
1244 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1246 Name username = PG_GETARG_NAME(0);
1247 Oid functionoid = PG_GETARG_OID(1);
1248 text *priv_type_text = PG_GETARG_TEXT_P(2);
1251 AclResult aclresult;
1253 usesysid = get_usesysid(NameStr(*username));
1254 mode = convert_function_priv_string(priv_type_text);
1256 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1258 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1262 * has_function_privilege_id
1263 * Check user privileges on a function given
1264 * function oid, and text priv name.
1265 * current_user is assumed
1268 has_function_privilege_id(PG_FUNCTION_ARGS)
1270 Oid functionoid = PG_GETARG_OID(0);
1271 text *priv_type_text = PG_GETARG_TEXT_P(1);
1274 AclResult aclresult;
1276 usesysid = GetUserId();
1277 mode = convert_function_priv_string(priv_type_text);
1279 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1281 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1285 * has_function_privilege_id_name
1286 * Check user privileges on a function given
1287 * usesysid, text functionname, and text priv name.
1290 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1292 int32 usesysid = PG_GETARG_INT32(0);
1293 text *functionname = PG_GETARG_TEXT_P(1);
1294 text *priv_type_text = PG_GETARG_TEXT_P(2);
1297 AclResult aclresult;
1299 functionoid = convert_function_name(functionname);
1300 mode = convert_function_priv_string(priv_type_text);
1302 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1304 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1308 * has_function_privilege_id_id
1309 * Check user privileges on a function given
1310 * usesysid, function oid, and text priv name.
1313 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1315 int32 usesysid = PG_GETARG_INT32(0);
1316 Oid functionoid = PG_GETARG_OID(1);
1317 text *priv_type_text = PG_GETARG_TEXT_P(2);
1319 AclResult aclresult;
1321 mode = convert_function_priv_string(priv_type_text);
1323 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1325 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1329 * Support routines for has_function_privilege family.
1333 * Given a function name expressed as a string, look it up and return Oid
1336 convert_function_name(text *functionname)
1341 funcname = DatumGetCString(DirectFunctionCall1(textout,
1342 PointerGetDatum(functionname)));
1344 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1345 CStringGetDatum(funcname)));
1347 if (!OidIsValid(oid))
1348 elog(ERROR, "function \"%s\" does not exist", funcname);
1354 * convert_function_priv_string
1355 * Convert text string to AclMode value.
1358 convert_function_priv_string(text *priv_type_text)
1362 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1363 PointerGetDatum(priv_type_text)));
1366 * Return mode from priv_type string
1368 if (strcasecmp(priv_type, "EXECUTE") == 0)
1370 if (strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1371 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1373 elog(ERROR, "has_function_privilege: invalid privilege type %s",
1375 return ACL_NO_RIGHTS; /* keep compiler quiet */
1380 * has_language_privilege variants
1381 * These are all named "has_language_privilege" at the SQL level.
1382 * They take various combinations of language name, language OID,
1383 * user name, user sysid, or implicit user = current_user.
1385 * The result is a boolean value: true if user has the indicated
1386 * privilege, false if not.
1390 * has_language_privilege_name_name
1391 * Check user privileges on a language given
1392 * name username, text languagename, and text priv name.
1395 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1397 Name username = PG_GETARG_NAME(0);
1398 text *languagename = PG_GETARG_TEXT_P(1);
1399 text *priv_type_text = PG_GETARG_TEXT_P(2);
1403 AclResult aclresult;
1405 usesysid = get_usesysid(NameStr(*username));
1406 languageoid = convert_language_name(languagename);
1407 mode = convert_language_priv_string(priv_type_text);
1409 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1411 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1415 * has_language_privilege_name
1416 * Check user privileges on a language given
1417 * text languagename and text priv name.
1418 * current_user is assumed
1421 has_language_privilege_name(PG_FUNCTION_ARGS)
1423 text *languagename = PG_GETARG_TEXT_P(0);
1424 text *priv_type_text = PG_GETARG_TEXT_P(1);
1428 AclResult aclresult;
1430 usesysid = GetUserId();
1431 languageoid = convert_language_name(languagename);
1432 mode = convert_language_priv_string(priv_type_text);
1434 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1436 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1440 * has_language_privilege_name_id
1441 * Check user privileges on a language given
1442 * name usename, language oid, and text priv name.
1445 has_language_privilege_name_id(PG_FUNCTION_ARGS)
1447 Name username = PG_GETARG_NAME(0);
1448 Oid languageoid = PG_GETARG_OID(1);
1449 text *priv_type_text = PG_GETARG_TEXT_P(2);
1452 AclResult aclresult;
1454 usesysid = get_usesysid(NameStr(*username));
1455 mode = convert_language_priv_string(priv_type_text);
1457 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1459 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1463 * has_language_privilege_id
1464 * Check user privileges on a language given
1465 * language oid, and text priv name.
1466 * current_user is assumed
1469 has_language_privilege_id(PG_FUNCTION_ARGS)
1471 Oid languageoid = PG_GETARG_OID(0);
1472 text *priv_type_text = PG_GETARG_TEXT_P(1);
1475 AclResult aclresult;
1477 usesysid = GetUserId();
1478 mode = convert_language_priv_string(priv_type_text);
1480 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1482 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1486 * has_language_privilege_id_name
1487 * Check user privileges on a language given
1488 * usesysid, text languagename, and text priv name.
1491 has_language_privilege_id_name(PG_FUNCTION_ARGS)
1493 int32 usesysid = PG_GETARG_INT32(0);
1494 text *languagename = PG_GETARG_TEXT_P(1);
1495 text *priv_type_text = PG_GETARG_TEXT_P(2);
1498 AclResult aclresult;
1500 languageoid = convert_language_name(languagename);
1501 mode = convert_language_priv_string(priv_type_text);
1503 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1505 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1509 * has_language_privilege_id_id
1510 * Check user privileges on a language given
1511 * usesysid, language oid, and text priv name.
1514 has_language_privilege_id_id(PG_FUNCTION_ARGS)
1516 int32 usesysid = PG_GETARG_INT32(0);
1517 Oid languageoid = PG_GETARG_OID(1);
1518 text *priv_type_text = PG_GETARG_TEXT_P(2);
1520 AclResult aclresult;
1522 mode = convert_language_priv_string(priv_type_text);
1524 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1526 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1530 * Support routines for has_language_privilege family.
1534 * Given a language name expressed as a string, look it up and return Oid
1537 convert_language_name(text *languagename)
1542 langname = DatumGetCString(DirectFunctionCall1(textout,
1543 PointerGetDatum(languagename)));
1545 oid = GetSysCacheOid(LANGNAME,
1546 CStringGetDatum(langname),
1548 if (!OidIsValid(oid))
1549 elog(ERROR, "language \"%s\" does not exist", langname);
1555 * convert_language_priv_string
1556 * Convert text string to AclMode value.
1559 convert_language_priv_string(text *priv_type_text)
1563 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1564 PointerGetDatum(priv_type_text)));
1567 * Return mode from priv_type string
1569 if (strcasecmp(priv_type, "USAGE") == 0)
1571 if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1572 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
1574 elog(ERROR, "has_language_privilege: invalid privilege type %s",
1576 return ACL_NO_RIGHTS; /* keep compiler quiet */
1581 * has_schema_privilege variants
1582 * These are all named "has_schema_privilege" at the SQL level.
1583 * They take various combinations of schema name, schema OID,
1584 * user name, user sysid, or implicit user = current_user.
1586 * The result is a boolean value: true if user has the indicated
1587 * privilege, false if not.
1591 * has_schema_privilege_name_name
1592 * Check user privileges on a schema given
1593 * name username, text schemaname, and text priv name.
1596 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
1598 Name username = PG_GETARG_NAME(0);
1599 text *schemaname = PG_GETARG_TEXT_P(1);
1600 text *priv_type_text = PG_GETARG_TEXT_P(2);
1604 AclResult aclresult;
1606 usesysid = get_usesysid(NameStr(*username));
1607 schemaoid = convert_schema_name(schemaname);
1608 mode = convert_schema_priv_string(priv_type_text);
1610 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1612 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1616 * has_schema_privilege_name
1617 * Check user privileges on a schema given
1618 * text schemaname and text priv name.
1619 * current_user is assumed
1622 has_schema_privilege_name(PG_FUNCTION_ARGS)
1624 text *schemaname = PG_GETARG_TEXT_P(0);
1625 text *priv_type_text = PG_GETARG_TEXT_P(1);
1629 AclResult aclresult;
1631 usesysid = GetUserId();
1632 schemaoid = convert_schema_name(schemaname);
1633 mode = convert_schema_priv_string(priv_type_text);
1635 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1637 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1641 * has_schema_privilege_name_id
1642 * Check user privileges on a schema given
1643 * name usename, schema oid, and text priv name.
1646 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
1648 Name username = PG_GETARG_NAME(0);
1649 Oid schemaoid = PG_GETARG_OID(1);
1650 text *priv_type_text = PG_GETARG_TEXT_P(2);
1653 AclResult aclresult;
1655 usesysid = get_usesysid(NameStr(*username));
1656 mode = convert_schema_priv_string(priv_type_text);
1658 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1660 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1664 * has_schema_privilege_id
1665 * Check user privileges on a schema given
1666 * schema oid, and text priv name.
1667 * current_user is assumed
1670 has_schema_privilege_id(PG_FUNCTION_ARGS)
1672 Oid schemaoid = PG_GETARG_OID(0);
1673 text *priv_type_text = PG_GETARG_TEXT_P(1);
1676 AclResult aclresult;
1678 usesysid = GetUserId();
1679 mode = convert_schema_priv_string(priv_type_text);
1681 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1683 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1687 * has_schema_privilege_id_name
1688 * Check user privileges on a schema given
1689 * usesysid, text schemaname, and text priv name.
1692 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
1694 int32 usesysid = PG_GETARG_INT32(0);
1695 text *schemaname = PG_GETARG_TEXT_P(1);
1696 text *priv_type_text = PG_GETARG_TEXT_P(2);
1699 AclResult aclresult;
1701 schemaoid = convert_schema_name(schemaname);
1702 mode = convert_schema_priv_string(priv_type_text);
1704 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1706 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1710 * has_schema_privilege_id_id
1711 * Check user privileges on a schema given
1712 * usesysid, schema oid, and text priv name.
1715 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
1717 int32 usesysid = PG_GETARG_INT32(0);
1718 Oid schemaoid = PG_GETARG_OID(1);
1719 text *priv_type_text = PG_GETARG_TEXT_P(2);
1721 AclResult aclresult;
1723 mode = convert_schema_priv_string(priv_type_text);
1725 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1727 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1731 * Support routines for has_schema_privilege family.
1735 * Given a schema name expressed as a string, look it up and return Oid
1738 convert_schema_name(text *schemaname)
1743 nspname = DatumGetCString(DirectFunctionCall1(textout,
1744 PointerGetDatum(schemaname)));
1746 oid = GetSysCacheOid(NAMESPACENAME,
1747 CStringGetDatum(nspname),
1749 if (!OidIsValid(oid))
1750 elog(ERROR, "schema \"%s\" does not exist", nspname);
1756 * convert_schema_priv_string
1757 * Convert text string to AclMode value.
1760 convert_schema_priv_string(text *priv_type_text)
1764 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1765 PointerGetDatum(priv_type_text)));
1768 * Return mode from priv_type string
1770 if (strcasecmp(priv_type, "CREATE") == 0)
1772 if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1773 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1775 if (strcasecmp(priv_type, "USAGE") == 0)
1777 if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1778 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
1780 elog(ERROR, "has_schema_privilege: invalid privilege type %s",
1782 return ACL_NO_RIGHTS; /* keep compiler quiet */