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.78 2002/09/03 22:17:35 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 Acl *makeacl(int n);
35 static const char *aclparse(const char *s, AclItem *aip, unsigned *modechg);
36 static bool aclitemeq(const AclItem *a1, const AclItem *a2);
37 static bool aclitemgt(const AclItem *a1, const AclItem *a2);
39 static Oid convert_table_name(text *tablename);
40 static AclMode convert_table_priv_string(text *priv_type_text);
41 static Oid convert_database_name(text *databasename);
42 static AclMode convert_database_priv_string(text *priv_type_text);
43 static Oid convert_function_name(text *functionname);
44 static AclMode convert_function_priv_string(text *priv_type_text);
45 static Oid convert_language_name(text *languagename);
46 static AclMode convert_language_priv_string(text *priv_type_text);
47 static Oid convert_schema_name(text *schemaname);
48 static AclMode convert_schema_priv_string(text *priv_type_text);
53 * Consumes the first alphanumeric string (identifier) found in string
54 * 's', ignoring any leading white space. If it finds a double quote
55 * it returns the word inside the quotes.
58 * the string position in 's' that points to the next non-space character
59 * in 's', after any quotes. Also:
60 * - loads the identifier into 'name'. (If no identifier is found, 'name'
61 * contains an empty string.) name must be NAMEDATALEN bytes.
64 getid(const char *s, char *n)
72 while (isspace((unsigned char) *s))
82 isalnum((unsigned char) *s) || *s == '_' || in_quotes;
85 if (in_quotes && *s == '"')
91 if (len >= NAMEDATALEN)
92 elog(ERROR, "getid: identifier must be <%d characters",
97 while (isspace((unsigned char) *s))
104 * Consumes and parses an ACL specification of the form:
105 * [group|user] [A-Za-z0-9]*[+-=][rwaR]*
106 * from string 's', ignoring any leading white space or white space
107 * between the optional id type keyword (group|user) and the actual
110 * This routine is called by the parser as well as aclitemin(), hence
111 * the added generality.
114 * the string position in 's' immediately following the ACL
115 * specification. Also:
116 * - loads the structure pointed to by 'aip' with the appropriate
117 * UID/GID, id type identifier and mode type values.
118 * - loads 'modechg' with the mode change flag.
121 aclparse(const char *s, AclItem *aip, unsigned *modechg)
125 char name[NAMEDATALEN];
127 Assert(s && aip && modechg);
130 elog(LOG, "aclparse: input = '%s'", s);
132 idtype = ACL_IDTYPE_UID;
134 if (*s != ACL_MODECHG_ADD_CHR &&
135 *s != ACL_MODECHG_DEL_CHR &&
136 *s != ACL_MODECHG_EQL_CHR)
138 /* we just read a keyword, not a name */
139 if (strncmp(name, ACL_IDTYPE_GID_KEYWORD, sizeof(name)) == 0)
140 idtype = ACL_IDTYPE_GID;
141 else if (strncmp(name, ACL_IDTYPE_UID_KEYWORD, sizeof(name)) != 0)
142 elog(ERROR, "aclparse: bad keyword, must be [group|user]");
143 s = getid(s, name); /* move s to the name beyond the keyword */
145 elog(ERROR, "aclparse: a name must follow the [group|user] keyword");
148 idtype = ACL_IDTYPE_WORLD;
152 case ACL_MODECHG_ADD_CHR:
153 *modechg = ACL_MODECHG_ADD;
155 case ACL_MODECHG_DEL_CHR:
156 *modechg = ACL_MODECHG_DEL;
158 case ACL_MODECHG_EQL_CHR:
159 *modechg = ACL_MODECHG_EQL;
162 elog(ERROR, "aclparse: mode change flag must use \"%c%c%c\"",
165 ACL_MODECHG_EQL_CHR);
168 privs = ACL_NO_RIGHTS;
170 while (isalpha((unsigned char) *++s))
189 case ACL_REFERENCES_CHR:
190 privs |= ACL_REFERENCES;
192 case ACL_TRIGGER_CHR:
193 privs |= ACL_TRIGGER;
195 case ACL_EXECUTE_CHR:
196 privs |= ACL_EXECUTE;
204 case ACL_CREATE_TEMP_CHR:
205 privs |= ACL_CREATE_TEMP;
208 elog(ERROR, "aclparse: mode flags must use \"%s\"",
216 aip->ai_id = get_usesysid(name);
219 aip->ai_id = get_grosysid(name);
221 case ACL_IDTYPE_WORLD:
222 aip->ai_id = ACL_ID_WORLD;
226 ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, idtype);
229 elog(LOG, "aclparse: correctly read [%x %d %x], modechg=%x",
230 idtype, aip->ai_id, privs, *modechg);
237 * Allocates storage for a new Acl with 'n' entries.
249 elog(ERROR, "makeacl: invalid size: %d", n);
250 size = ACL_N_SIZE(n);
251 new_acl = (Acl *) palloc(size);
252 MemSet((char *) new_acl, 0, size);
253 new_acl->size = size;
256 new_acl->elemtype = ACLITEMOID;
257 ARR_LBOUND(new_acl)[0] = 0;
258 ARR_DIMS(new_acl)[0] = n;
264 * Allocates storage for, and fills in, a new AclItem given a string
265 * 's' that contains an ACL specification. See aclparse for details.
271 aclitemin(PG_FUNCTION_ARGS)
273 const char *s = PG_GETARG_CSTRING(0);
277 aip = (AclItem *) palloc(sizeof(AclItem));
278 s = aclparse(s, aip, &modechg);
279 if (modechg != ACL_MODECHG_EQL)
280 elog(ERROR, "aclitemin: cannot accept anything but = ACLs");
281 while (isspace((unsigned char) *s))
284 elog(ERROR, "aclitemin: extra garbage at end of specification");
285 PG_RETURN_ACLITEM_P(aip);
290 * Allocates storage for, and fills in, a new null-delimited string
291 * containing a formatted ACL specification. See aclparse for details.
297 aclitemout(PG_FUNCTION_ARGS)
299 AclItem *aip = PG_GETARG_ACLITEM_P(0);
306 p = out = palloc(strlen("group = ") + N_ACL_RIGHTS + NAMEDATALEN + 1);
309 switch (ACLITEM_GET_IDTYPE(*aip))
312 htup = SearchSysCache(SHADOWSYSID,
313 ObjectIdGetDatum(aip->ai_id),
315 if (HeapTupleIsValid(htup))
318 NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename),
320 ReleaseSysCache(htup);
324 /* Generate numeric UID if we don't find an entry */
327 tmp = DatumGetCString(DirectFunctionCall1(int4out,
328 Int32GetDatum((int32) aip->ai_id)));
335 tmpname = get_groname(aip->ai_id);
337 strncat(p, tmpname, NAMEDATALEN);
340 /* Generate numeric GID if we don't find an entry */
343 tmp = DatumGetCString(DirectFunctionCall1(int4out,
344 Int32GetDatum((int32) aip->ai_id)));
349 case ACL_IDTYPE_WORLD:
352 elog(ERROR, "aclitemout: bad idtype: %d",
353 ACLITEM_GET_IDTYPE(*aip));
359 for (i = 0; i < N_ACL_RIGHTS; ++i)
360 if (aip->ai_privs & (1 << i))
361 *p++ = ACL_ALL_RIGHTS_STR[i];
364 PG_RETURN_CSTRING(out);
370 * AclItem equality and greater-than comparison routines.
371 * Two AclItems are considered equal iff they have the same
372 * identifier (and identifier type); the privileges are ignored.
373 * Note that these routines are really only useful for sorting
374 * AclItems into identifier order.
377 * a boolean value indicating = or >
380 aclitemeq(const AclItem *a1, const AclItem *a2)
382 return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
383 a1->ai_id == a2->ai_id;
387 aclitemgt(const AclItem *a1, const AclItem *a2)
389 return ((ACLITEM_GET_IDTYPE(*a1) > ACLITEM_GET_IDTYPE(*a2)) ||
390 (ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
391 a1->ai_id > a2->ai_id));
396 * acldefault() --- create an ACL describing default access permissions
398 * Change this routine if you want to alter the default access policy for
399 * newly-created objects (or any object with a NULL acl entry).
402 acldefault(GrantObjectType objtype, AclId ownerid)
404 AclMode world_default;
405 AclMode owner_default;
411 case ACL_OBJECT_RELATION:
412 world_default = ACL_NO_RIGHTS;
413 owner_default = ACL_ALL_RIGHTS_RELATION;
415 case ACL_OBJECT_DATABASE:
416 world_default = ACL_CREATE_TEMP; /* not NO_RIGHTS! */
417 owner_default = ACL_ALL_RIGHTS_DATABASE;
419 case ACL_OBJECT_FUNCTION:
420 world_default = ACL_NO_RIGHTS;
421 owner_default = ACL_ALL_RIGHTS_FUNCTION;
423 case ACL_OBJECT_LANGUAGE:
424 world_default = ACL_NO_RIGHTS;
425 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
427 case ACL_OBJECT_NAMESPACE:
428 world_default = ACL_NO_RIGHTS;
429 owner_default = ACL_ALL_RIGHTS_NAMESPACE;
432 elog(ERROR, "acldefault: bogus objtype %d", (int) objtype);
433 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
434 owner_default = ACL_NO_RIGHTS;
438 acl = makeacl(ownerid ? 2 : 1);
441 aip[0].ai_id = ACL_ID_WORLD;
442 ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_IDTYPE_WORLD);
445 aip[1].ai_id = ownerid;
446 ACLITEM_SET_PRIVS_IDTYPE(aip[1], owner_default, ACL_IDTYPE_UID);
454 * Add or replace an item in an ACL array. The result is a modified copy;
455 * the input object is not changed.
457 * NB: caller is responsible for having detoasted the input ACL, if needed.
460 aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
468 /* These checks for null input are probably dead code, but... */
469 if (!old_acl || ACL_NUM(old_acl) < 1)
470 old_acl = makeacl(1);
473 new_acl = makeacl(ACL_NUM(old_acl));
474 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
478 num = ACL_NUM(old_acl);
479 old_aip = ACL_DAT(old_acl);
482 * Search the ACL for an existing entry for 'id'. If one exists, just
483 * modify the entry in-place (well, in the same position, since we
484 * actually return a copy); otherwise, insert the new entry in
487 /* find the first element not less than the element to be inserted */
488 for (dst = 0; dst < num && aclitemgt(mod_aip, old_aip + dst); ++dst)
491 if (dst < num && aclitemeq(mod_aip, old_aip + dst))
493 /* found a match, so modify existing item */
494 new_acl = makeacl(num);
495 new_aip = ACL_DAT(new_acl);
496 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
500 /* need to insert a new item */
501 new_acl = makeacl(num + 1);
502 new_aip = ACL_DAT(new_acl);
505 elog(ERROR, "aclinsert3: insertion before world ACL??");
509 memcpy((char *) new_aip,
511 num * sizeof(AclItem));
515 memcpy((char *) new_aip,
517 dst * sizeof(AclItem));
518 memcpy((char *) (new_aip + dst + 1),
519 (char *) (old_aip + dst),
520 (num - dst) * sizeof(AclItem));
522 /* initialize the new entry with no permissions */
523 new_aip[dst].ai_id = mod_aip->ai_id;
524 ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACL_NO_RIGHTS,
525 ACLITEM_GET_IDTYPE(*mod_aip));
526 num++; /* set num to the size of new_acl */
529 /* apply the permissions mod */
532 case ACL_MODECHG_ADD:
533 new_aip[dst].ai_privs |= ACLITEM_GET_PRIVS(*mod_aip);
535 case ACL_MODECHG_DEL:
536 new_aip[dst].ai_privs &= ~ACLITEM_GET_PRIVS(*mod_aip);
538 case ACL_MODECHG_EQL:
539 ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
540 ACLITEM_GET_PRIVS(*mod_aip),
541 ACLITEM_GET_IDTYPE(new_aip[dst]));
546 * if the adjusted entry has no permissions, delete it from the list.
547 * For example, this helps in removing entries for users who no longer
548 * exist. EXCEPTION: never remove the world entry.
550 if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS && dst > 0)
552 memmove((char *) (new_aip + dst),
553 (char *) (new_aip + dst + 1),
554 (num - dst - 1) * sizeof(AclItem));
555 ARR_DIMS(new_acl)[0] = num - 1;
556 ARR_SIZE(new_acl) -= sizeof(AclItem);
563 * aclinsert (exported function)
566 aclinsert(PG_FUNCTION_ARGS)
568 Acl *old_acl = PG_GETARG_ACL_P(0);
569 AclItem *mod_aip = PG_GETARG_ACLITEM_P(1);
571 PG_RETURN_ACL_P(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL));
575 aclremove(PG_FUNCTION_ARGS)
577 Acl *old_acl = PG_GETARG_ACL_P(0);
578 AclItem *mod_aip = PG_GETARG_ACLITEM_P(1);
586 /* These checks for null input should be dead code, but... */
587 if (!old_acl || ACL_NUM(old_acl) < 1)
588 old_acl = makeacl(1);
591 new_acl = makeacl(ACL_NUM(old_acl));
592 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
593 PG_RETURN_ACL_P(new_acl);
596 old_num = ACL_NUM(old_acl);
597 old_aip = ACL_DAT(old_acl);
599 /* Search for the matching entry */
600 for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip + dst); ++dst)
605 /* Not found, so return copy of source ACL */
606 new_acl = makeacl(old_num);
607 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
611 new_num = old_num - 1;
612 new_acl = makeacl(new_num);
613 new_aip = ACL_DAT(new_acl);
616 elog(ERROR, "aclremove: removal of the world ACL??");
618 else if (dst == old_num - 1)
620 memcpy((char *) new_aip,
622 new_num * sizeof(AclItem));
626 memcpy((char *) new_aip,
628 dst * sizeof(AclItem));
629 memcpy((char *) (new_aip + dst),
630 (char *) (old_aip + dst + 1),
631 (new_num - dst) * sizeof(AclItem));
635 PG_RETURN_ACL_P(new_acl);
639 aclcontains(PG_FUNCTION_ARGS)
641 Acl *acl = PG_GETARG_ACL_P(0);
642 AclItem *aip = PG_GETARG_ACLITEM_P(1);
648 aidat = ACL_DAT(acl);
649 for (i = 0; i < num; ++i)
651 if (aip->ai_id == aidat[i].ai_id &&
652 aip->ai_privs == aidat[i].ai_privs)
653 PG_RETURN_BOOL(true);
655 PG_RETURN_BOOL(false);
660 * has_table_privilege variants
661 * These are all named "has_table_privilege" at the SQL level.
662 * They take various combinations of relation name, relation OID,
663 * user name, user sysid, or implicit user = current_user.
665 * The result is a boolean value: true if user has the indicated
666 * privilege, false if not.
670 * has_table_privilege_name_name
671 * Check user privileges on a table given
672 * name username, text tablename, and text priv name.
675 has_table_privilege_name_name(PG_FUNCTION_ARGS)
677 Name username = PG_GETARG_NAME(0);
678 text *tablename = PG_GETARG_TEXT_P(1);
679 text *priv_type_text = PG_GETARG_TEXT_P(2);
685 usesysid = get_usesysid(NameStr(*username));
686 tableoid = convert_table_name(tablename);
687 mode = convert_table_priv_string(priv_type_text);
689 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
691 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
695 * has_table_privilege_name
696 * Check user privileges on a table given
697 * text tablename and text priv name.
698 * current_user is assumed
701 has_table_privilege_name(PG_FUNCTION_ARGS)
703 text *tablename = PG_GETARG_TEXT_P(0);
704 text *priv_type_text = PG_GETARG_TEXT_P(1);
710 usesysid = GetUserId();
711 tableoid = convert_table_name(tablename);
712 mode = convert_table_priv_string(priv_type_text);
714 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
716 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
720 * has_table_privilege_name_id
721 * Check user privileges on a table given
722 * name usename, table oid, and text priv name.
725 has_table_privilege_name_id(PG_FUNCTION_ARGS)
727 Name username = PG_GETARG_NAME(0);
728 Oid tableoid = PG_GETARG_OID(1);
729 text *priv_type_text = PG_GETARG_TEXT_P(2);
734 usesysid = get_usesysid(NameStr(*username));
735 mode = convert_table_priv_string(priv_type_text);
737 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
739 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
743 * has_table_privilege_id
744 * Check user privileges on a table given
745 * table oid, and text priv name.
746 * current_user is assumed
749 has_table_privilege_id(PG_FUNCTION_ARGS)
751 Oid tableoid = PG_GETARG_OID(0);
752 text *priv_type_text = PG_GETARG_TEXT_P(1);
757 usesysid = GetUserId();
758 mode = convert_table_priv_string(priv_type_text);
760 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
762 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
766 * has_table_privilege_id_name
767 * Check user privileges on a table given
768 * usesysid, text tablename, and text priv name.
771 has_table_privilege_id_name(PG_FUNCTION_ARGS)
773 int32 usesysid = PG_GETARG_INT32(0);
774 text *tablename = PG_GETARG_TEXT_P(1);
775 text *priv_type_text = PG_GETARG_TEXT_P(2);
780 tableoid = convert_table_name(tablename);
781 mode = convert_table_priv_string(priv_type_text);
783 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
785 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
789 * has_table_privilege_id_id
790 * Check user privileges on a table given
791 * usesysid, table oid, and text priv name.
794 has_table_privilege_id_id(PG_FUNCTION_ARGS)
796 int32 usesysid = PG_GETARG_INT32(0);
797 Oid tableoid = PG_GETARG_OID(1);
798 text *priv_type_text = PG_GETARG_TEXT_P(2);
802 mode = convert_table_priv_string(priv_type_text);
804 aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
806 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
810 * Support routines for has_table_privilege family.
814 * Given a table name expressed as a string, look it up and return Oid
817 convert_table_name(text *tablename)
821 relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename,
822 "has_table_privilege"));
824 return RangeVarGetRelid(relrv, false);
828 * convert_table_priv_string
829 * Convert text string to AclMode value.
832 convert_table_priv_string(text *priv_type_text)
836 priv_type = DatumGetCString(DirectFunctionCall1(textout,
837 PointerGetDatum(priv_type_text)));
840 * Return mode from priv_type string
842 if (strcasecmp(priv_type, "SELECT") == 0)
845 if (strcasecmp(priv_type, "INSERT") == 0)
848 if (strcasecmp(priv_type, "UPDATE") == 0)
851 if (strcasecmp(priv_type, "DELETE") == 0)
854 if (strcasecmp(priv_type, "RULE") == 0)
857 if (strcasecmp(priv_type, "REFERENCES") == 0)
858 return ACL_REFERENCES;
860 if (strcasecmp(priv_type, "TRIGGER") == 0)
863 elog(ERROR, "has_table_privilege: invalid privilege type %s",
865 return ACL_NO_RIGHTS; /* keep compiler quiet */
870 * has_database_privilege variants
871 * These are all named "has_database_privilege" at the SQL level.
872 * They take various combinations of database name, database OID,
873 * user name, user sysid, or implicit user = current_user.
875 * The result is a boolean value: true if user has the indicated
876 * privilege, false if not.
880 * has_database_privilege_name_name
881 * Check user privileges on a database given
882 * name username, text databasename, and text priv name.
885 has_database_privilege_name_name(PG_FUNCTION_ARGS)
887 Name username = PG_GETARG_NAME(0);
888 text *databasename = PG_GETARG_TEXT_P(1);
889 text *priv_type_text = PG_GETARG_TEXT_P(2);
895 usesysid = get_usesysid(NameStr(*username));
896 databaseoid = convert_database_name(databasename);
897 mode = convert_database_priv_string(priv_type_text);
899 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
901 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
905 * has_database_privilege_name
906 * Check user privileges on a database given
907 * text databasename and text priv name.
908 * current_user is assumed
911 has_database_privilege_name(PG_FUNCTION_ARGS)
913 text *databasename = PG_GETARG_TEXT_P(0);
914 text *priv_type_text = PG_GETARG_TEXT_P(1);
920 usesysid = GetUserId();
921 databaseoid = convert_database_name(databasename);
922 mode = convert_database_priv_string(priv_type_text);
924 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
926 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
930 * has_database_privilege_name_id
931 * Check user privileges on a database given
932 * name usename, database oid, and text priv name.
935 has_database_privilege_name_id(PG_FUNCTION_ARGS)
937 Name username = PG_GETARG_NAME(0);
938 Oid databaseoid = PG_GETARG_OID(1);
939 text *priv_type_text = PG_GETARG_TEXT_P(2);
944 usesysid = get_usesysid(NameStr(*username));
945 mode = convert_database_priv_string(priv_type_text);
947 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
949 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
953 * has_database_privilege_id
954 * Check user privileges on a database given
955 * database oid, and text priv name.
956 * current_user is assumed
959 has_database_privilege_id(PG_FUNCTION_ARGS)
961 Oid databaseoid = PG_GETARG_OID(0);
962 text *priv_type_text = PG_GETARG_TEXT_P(1);
967 usesysid = GetUserId();
968 mode = convert_database_priv_string(priv_type_text);
970 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
972 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
976 * has_database_privilege_id_name
977 * Check user privileges on a database given
978 * usesysid, text databasename, and text priv name.
981 has_database_privilege_id_name(PG_FUNCTION_ARGS)
983 int32 usesysid = PG_GETARG_INT32(0);
984 text *databasename = PG_GETARG_TEXT_P(1);
985 text *priv_type_text = PG_GETARG_TEXT_P(2);
990 databaseoid = convert_database_name(databasename);
991 mode = convert_database_priv_string(priv_type_text);
993 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
995 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
999 * has_database_privilege_id_id
1000 * Check user privileges on a database given
1001 * usesysid, database oid, and text priv name.
1004 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1006 int32 usesysid = PG_GETARG_INT32(0);
1007 Oid databaseoid = PG_GETARG_OID(1);
1008 text *priv_type_text = PG_GETARG_TEXT_P(2);
1010 AclResult aclresult;
1012 mode = convert_database_priv_string(priv_type_text);
1014 aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1016 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1020 * Support routines for has_database_privilege family.
1024 * Given a database name expressed as a string, look it up and return Oid
1027 convert_database_name(text *databasename)
1032 dbname = DatumGetCString(DirectFunctionCall1(textout,
1033 PointerGetDatum(databasename)));
1035 oid = get_database_oid(dbname);
1036 if (!OidIsValid(oid))
1037 elog(ERROR, "database \"%s\" does not exist", dbname);
1043 * convert_database_priv_string
1044 * Convert text string to AclMode value.
1047 convert_database_priv_string(text *priv_type_text)
1051 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1052 PointerGetDatum(priv_type_text)));
1055 * Return mode from priv_type string
1057 if (strcasecmp(priv_type, "CREATE") == 0)
1060 if (strcasecmp(priv_type, "TEMPORARY") == 0)
1061 return ACL_CREATE_TEMP;
1063 if (strcasecmp(priv_type, "TEMP") == 0)
1064 return ACL_CREATE_TEMP;
1066 elog(ERROR, "has_database_privilege: invalid privilege type %s",
1068 return ACL_NO_RIGHTS; /* keep compiler quiet */
1073 * has_function_privilege variants
1074 * These are all named "has_function_privilege" at the SQL level.
1075 * They take various combinations of function name, function OID,
1076 * user name, user sysid, or implicit user = current_user.
1078 * The result is a boolean value: true if user has the indicated
1079 * privilege, false if not.
1083 * has_function_privilege_name_name
1084 * Check user privileges on a function given
1085 * name username, text functionname, and text priv name.
1088 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1090 Name username = PG_GETARG_NAME(0);
1091 text *functionname = PG_GETARG_TEXT_P(1);
1092 text *priv_type_text = PG_GETARG_TEXT_P(2);
1096 AclResult aclresult;
1098 usesysid = get_usesysid(NameStr(*username));
1099 functionoid = convert_function_name(functionname);
1100 mode = convert_function_priv_string(priv_type_text);
1102 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1104 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1108 * has_function_privilege_name
1109 * Check user privileges on a function given
1110 * text functionname and text priv name.
1111 * current_user is assumed
1114 has_function_privilege_name(PG_FUNCTION_ARGS)
1116 text *functionname = PG_GETARG_TEXT_P(0);
1117 text *priv_type_text = PG_GETARG_TEXT_P(1);
1121 AclResult aclresult;
1123 usesysid = GetUserId();
1124 functionoid = convert_function_name(functionname);
1125 mode = convert_function_priv_string(priv_type_text);
1127 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1129 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1133 * has_function_privilege_name_id
1134 * Check user privileges on a function given
1135 * name usename, function oid, and text priv name.
1138 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1140 Name username = PG_GETARG_NAME(0);
1141 Oid functionoid = PG_GETARG_OID(1);
1142 text *priv_type_text = PG_GETARG_TEXT_P(2);
1145 AclResult aclresult;
1147 usesysid = get_usesysid(NameStr(*username));
1148 mode = convert_function_priv_string(priv_type_text);
1150 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1152 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1156 * has_function_privilege_id
1157 * Check user privileges on a function given
1158 * function oid, and text priv name.
1159 * current_user is assumed
1162 has_function_privilege_id(PG_FUNCTION_ARGS)
1164 Oid functionoid = PG_GETARG_OID(0);
1165 text *priv_type_text = PG_GETARG_TEXT_P(1);
1168 AclResult aclresult;
1170 usesysid = GetUserId();
1171 mode = convert_function_priv_string(priv_type_text);
1173 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1175 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1179 * has_function_privilege_id_name
1180 * Check user privileges on a function given
1181 * usesysid, text functionname, and text priv name.
1184 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1186 int32 usesysid = PG_GETARG_INT32(0);
1187 text *functionname = PG_GETARG_TEXT_P(1);
1188 text *priv_type_text = PG_GETARG_TEXT_P(2);
1191 AclResult aclresult;
1193 functionoid = convert_function_name(functionname);
1194 mode = convert_function_priv_string(priv_type_text);
1196 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1198 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1202 * has_function_privilege_id_id
1203 * Check user privileges on a function given
1204 * usesysid, function oid, and text priv name.
1207 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1209 int32 usesysid = PG_GETARG_INT32(0);
1210 Oid functionoid = PG_GETARG_OID(1);
1211 text *priv_type_text = PG_GETARG_TEXT_P(2);
1213 AclResult aclresult;
1215 mode = convert_function_priv_string(priv_type_text);
1217 aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1219 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1223 * Support routines for has_function_privilege family.
1227 * Given a function name expressed as a string, look it up and return Oid
1230 convert_function_name(text *functionname)
1235 funcname = DatumGetCString(DirectFunctionCall1(textout,
1236 PointerGetDatum(functionname)));
1238 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1239 CStringGetDatum(funcname)));
1241 if (!OidIsValid(oid))
1242 elog(ERROR, "function \"%s\" does not exist", funcname);
1248 * convert_function_priv_string
1249 * Convert text string to AclMode value.
1252 convert_function_priv_string(text *priv_type_text)
1256 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1257 PointerGetDatum(priv_type_text)));
1260 * Return mode from priv_type string
1262 if (strcasecmp(priv_type, "EXECUTE") == 0)
1265 elog(ERROR, "has_function_privilege: invalid privilege type %s",
1267 return ACL_NO_RIGHTS; /* keep compiler quiet */
1272 * has_language_privilege variants
1273 * These are all named "has_language_privilege" at the SQL level.
1274 * They take various combinations of language name, language OID,
1275 * user name, user sysid, or implicit user = current_user.
1277 * The result is a boolean value: true if user has the indicated
1278 * privilege, false if not.
1282 * has_language_privilege_name_name
1283 * Check user privileges on a language given
1284 * name username, text languagename, and text priv name.
1287 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1289 Name username = PG_GETARG_NAME(0);
1290 text *languagename = PG_GETARG_TEXT_P(1);
1291 text *priv_type_text = PG_GETARG_TEXT_P(2);
1295 AclResult aclresult;
1297 usesysid = get_usesysid(NameStr(*username));
1298 languageoid = convert_language_name(languagename);
1299 mode = convert_language_priv_string(priv_type_text);
1301 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1303 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1307 * has_language_privilege_name
1308 * Check user privileges on a language given
1309 * text languagename and text priv name.
1310 * current_user is assumed
1313 has_language_privilege_name(PG_FUNCTION_ARGS)
1315 text *languagename = PG_GETARG_TEXT_P(0);
1316 text *priv_type_text = PG_GETARG_TEXT_P(1);
1320 AclResult aclresult;
1322 usesysid = GetUserId();
1323 languageoid = convert_language_name(languagename);
1324 mode = convert_language_priv_string(priv_type_text);
1326 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1328 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1332 * has_language_privilege_name_id
1333 * Check user privileges on a language given
1334 * name usename, language oid, and text priv name.
1337 has_language_privilege_name_id(PG_FUNCTION_ARGS)
1339 Name username = PG_GETARG_NAME(0);
1340 Oid languageoid = PG_GETARG_OID(1);
1341 text *priv_type_text = PG_GETARG_TEXT_P(2);
1344 AclResult aclresult;
1346 usesysid = get_usesysid(NameStr(*username));
1347 mode = convert_language_priv_string(priv_type_text);
1349 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1351 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1355 * has_language_privilege_id
1356 * Check user privileges on a language given
1357 * language oid, and text priv name.
1358 * current_user is assumed
1361 has_language_privilege_id(PG_FUNCTION_ARGS)
1363 Oid languageoid = PG_GETARG_OID(0);
1364 text *priv_type_text = PG_GETARG_TEXT_P(1);
1367 AclResult aclresult;
1369 usesysid = GetUserId();
1370 mode = convert_language_priv_string(priv_type_text);
1372 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1374 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1378 * has_language_privilege_id_name
1379 * Check user privileges on a language given
1380 * usesysid, text languagename, and text priv name.
1383 has_language_privilege_id_name(PG_FUNCTION_ARGS)
1385 int32 usesysid = PG_GETARG_INT32(0);
1386 text *languagename = PG_GETARG_TEXT_P(1);
1387 text *priv_type_text = PG_GETARG_TEXT_P(2);
1390 AclResult aclresult;
1392 languageoid = convert_language_name(languagename);
1393 mode = convert_language_priv_string(priv_type_text);
1395 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1397 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1401 * has_language_privilege_id_id
1402 * Check user privileges on a language given
1403 * usesysid, language oid, and text priv name.
1406 has_language_privilege_id_id(PG_FUNCTION_ARGS)
1408 int32 usesysid = PG_GETARG_INT32(0);
1409 Oid languageoid = PG_GETARG_OID(1);
1410 text *priv_type_text = PG_GETARG_TEXT_P(2);
1412 AclResult aclresult;
1414 mode = convert_language_priv_string(priv_type_text);
1416 aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1418 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1422 * Support routines for has_language_privilege family.
1426 * Given a language name expressed as a string, look it up and return Oid
1429 convert_language_name(text *languagename)
1434 langname = DatumGetCString(DirectFunctionCall1(textout,
1435 PointerGetDatum(languagename)));
1437 oid = GetSysCacheOid(LANGNAME,
1438 CStringGetDatum(langname),
1440 if (!OidIsValid(oid))
1441 elog(ERROR, "language \"%s\" does not exist", langname);
1447 * convert_language_priv_string
1448 * Convert text string to AclMode value.
1451 convert_language_priv_string(text *priv_type_text)
1455 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1456 PointerGetDatum(priv_type_text)));
1459 * Return mode from priv_type string
1461 if (strcasecmp(priv_type, "USAGE") == 0)
1464 elog(ERROR, "has_language_privilege: invalid privilege type %s",
1466 return ACL_NO_RIGHTS; /* keep compiler quiet */
1471 * has_schema_privilege variants
1472 * These are all named "has_schema_privilege" at the SQL level.
1473 * They take various combinations of schema name, schema OID,
1474 * user name, user sysid, or implicit user = current_user.
1476 * The result is a boolean value: true if user has the indicated
1477 * privilege, false if not.
1481 * has_schema_privilege_name_name
1482 * Check user privileges on a schema given
1483 * name username, text schemaname, and text priv name.
1486 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
1488 Name username = PG_GETARG_NAME(0);
1489 text *schemaname = PG_GETARG_TEXT_P(1);
1490 text *priv_type_text = PG_GETARG_TEXT_P(2);
1494 AclResult aclresult;
1496 usesysid = get_usesysid(NameStr(*username));
1497 schemaoid = convert_schema_name(schemaname);
1498 mode = convert_schema_priv_string(priv_type_text);
1500 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1502 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1506 * has_schema_privilege_name
1507 * Check user privileges on a schema given
1508 * text schemaname and text priv name.
1509 * current_user is assumed
1512 has_schema_privilege_name(PG_FUNCTION_ARGS)
1514 text *schemaname = PG_GETARG_TEXT_P(0);
1515 text *priv_type_text = PG_GETARG_TEXT_P(1);
1519 AclResult aclresult;
1521 usesysid = GetUserId();
1522 schemaoid = convert_schema_name(schemaname);
1523 mode = convert_schema_priv_string(priv_type_text);
1525 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1527 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1531 * has_schema_privilege_name_id
1532 * Check user privileges on a schema given
1533 * name usename, schema oid, and text priv name.
1536 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
1538 Name username = PG_GETARG_NAME(0);
1539 Oid schemaoid = PG_GETARG_OID(1);
1540 text *priv_type_text = PG_GETARG_TEXT_P(2);
1543 AclResult aclresult;
1545 usesysid = get_usesysid(NameStr(*username));
1546 mode = convert_schema_priv_string(priv_type_text);
1548 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1550 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1554 * has_schema_privilege_id
1555 * Check user privileges on a schema given
1556 * schema oid, and text priv name.
1557 * current_user is assumed
1560 has_schema_privilege_id(PG_FUNCTION_ARGS)
1562 Oid schemaoid = PG_GETARG_OID(0);
1563 text *priv_type_text = PG_GETARG_TEXT_P(1);
1566 AclResult aclresult;
1568 usesysid = GetUserId();
1569 mode = convert_schema_priv_string(priv_type_text);
1571 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1573 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1577 * has_schema_privilege_id_name
1578 * Check user privileges on a schema given
1579 * usesysid, text schemaname, and text priv name.
1582 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
1584 int32 usesysid = PG_GETARG_INT32(0);
1585 text *schemaname = PG_GETARG_TEXT_P(1);
1586 text *priv_type_text = PG_GETARG_TEXT_P(2);
1589 AclResult aclresult;
1591 schemaoid = convert_schema_name(schemaname);
1592 mode = convert_schema_priv_string(priv_type_text);
1594 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1596 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1600 * has_schema_privilege_id_id
1601 * Check user privileges on a schema given
1602 * usesysid, schema oid, and text priv name.
1605 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
1607 int32 usesysid = PG_GETARG_INT32(0);
1608 Oid schemaoid = PG_GETARG_OID(1);
1609 text *priv_type_text = PG_GETARG_TEXT_P(2);
1611 AclResult aclresult;
1613 mode = convert_schema_priv_string(priv_type_text);
1615 aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1617 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1621 * Support routines for has_schema_privilege family.
1625 * Given a schema name expressed as a string, look it up and return Oid
1628 convert_schema_name(text *schemaname)
1633 nspname = DatumGetCString(DirectFunctionCall1(textout,
1634 PointerGetDatum(schemaname)));
1636 oid = GetSysCacheOid(NAMESPACENAME,
1637 CStringGetDatum(nspname),
1639 if (!OidIsValid(oid))
1640 elog(ERROR, "schema \"%s\" does not exist", nspname);
1646 * convert_schema_priv_string
1647 * Convert text string to AclMode value.
1650 convert_schema_priv_string(text *priv_type_text)
1654 priv_type = DatumGetCString(DirectFunctionCall1(textout,
1655 PointerGetDatum(priv_type_text)));
1658 * Return mode from priv_type string
1660 if (strcasecmp(priv_type, "CREATE") == 0)
1663 if (strcasecmp(priv_type, "USAGE") == 0)
1666 elog(ERROR, "has_schema_privilege: invalid privilege type %s",
1668 return ACL_NO_RIGHTS; /* keep compiler quiet */