1 /*-------------------------------------------------------------------------
4 * Basic access control list data structures manipulation routines.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/acl.c
13 *-------------------------------------------------------------------------
19 #include "access/htup_details.h"
20 #include "catalog/catalog.h"
21 #include "catalog/namespace.h"
22 #include "catalog/pg_auth_members.h"
23 #include "catalog/pg_authid.h"
24 #include "catalog/pg_class.h"
25 #include "catalog/pg_database.h"
26 #include "catalog/pg_foreign_data_wrapper.h"
27 #include "catalog/pg_foreign_server.h"
28 #include "catalog/pg_language.h"
29 #include "catalog/pg_largeobject.h"
30 #include "catalog/pg_namespace.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_tablespace.h"
33 #include "catalog/pg_type.h"
34 #include "commands/dbcommands.h"
35 #include "commands/proclang.h"
36 #include "commands/tablespace.h"
37 #include "common/hashfn.h"
38 #include "foreign/foreign.h"
40 #include "lib/bloomfilter.h"
41 #include "lib/qunique.h"
42 #include "miscadmin.h"
43 #include "storage/large_object.h"
44 #include "utils/acl.h"
45 #include "utils/array.h"
46 #include "utils/builtins.h"
47 #include "utils/catcache.h"
48 #include "utils/inval.h"
49 #include "utils/lsyscache.h"
50 #include "utils/memutils.h"
51 #include "utils/snapmgr.h"
52 #include "utils/syscache.h"
53 #include "utils/varlena.h"
62 * We frequently need to test whether a given role is a member of some other
63 * role. In most of these tests the "given role" is the same, namely the
64 * active current user. So we can optimize it by keeping cached lists of all
65 * the roles the "given role" is a member of, directly or indirectly.
67 * Possibly this mechanism should be generalized to allow caching membership
68 * info for multiple roles?
70 * Each element of cached_roles is an OID list of constituent roles for the
71 * corresponding element of cached_role (always including the cached_role
72 * itself). There's a separate cache for each RoleRecurseType, with the
73 * corresponding semantics.
77 ROLERECURSE_MEMBERS
= 0, /* recurse unconditionally */
78 ROLERECURSE_PRIVS
= 1, /* recurse through inheritable grants */
79 ROLERECURSE_SETROLE
= 2 /* recurse through grants with set_option */
81 static Oid cached_role
[] = {InvalidOid
, InvalidOid
, InvalidOid
};
82 static List
*cached_roles
[] = {NIL
, NIL
, NIL
};
83 static uint32 cached_db_hash
;
86 * If the list of roles gathered by roles_is_member_of() grows larger than the
87 * below threshold, a Bloom filter is created to speed up list membership
88 * checks. This threshold is set arbitrarily high to avoid the overhead of
89 * creating the Bloom filter until it seems likely to provide a net benefit.
91 #define ROLES_LIST_BLOOM_THRESHOLD 1024
93 static const char *getid(const char *s
, char *n
, Node
*escontext
);
94 static void putid(char *p
, const char *s
);
95 static Acl
*allocacl(int n
);
96 static void check_acl(const Acl
*acl
);
97 static const char *aclparse(const char *s
, AclItem
*aip
, Node
*escontext
);
98 static bool aclitem_match(const AclItem
*a1
, const AclItem
*a2
);
99 static int aclitemComparator(const void *arg1
, const void *arg2
);
100 static void check_circularity(const Acl
*old_acl
, const AclItem
*mod_aip
,
102 static Acl
*recursive_revoke(Acl
*acl
, Oid grantee
, AclMode revoke_privs
,
103 Oid ownerId
, DropBehavior behavior
);
105 static AclMode
convert_any_priv_string(text
*priv_type_text
,
106 const priv_map
*privileges
);
108 static Oid
convert_table_name(text
*tablename
);
109 static AclMode
convert_table_priv_string(text
*priv_type_text
);
110 static AclMode
convert_sequence_priv_string(text
*priv_type_text
);
111 static AttrNumber
convert_column_name(Oid tableoid
, text
*column
);
112 static AclMode
convert_column_priv_string(text
*priv_type_text
);
113 static Oid
convert_database_name(text
*databasename
);
114 static AclMode
convert_database_priv_string(text
*priv_type_text
);
115 static Oid
convert_foreign_data_wrapper_name(text
*fdwname
);
116 static AclMode
convert_foreign_data_wrapper_priv_string(text
*priv_type_text
);
117 static Oid
convert_function_name(text
*functionname
);
118 static AclMode
convert_function_priv_string(text
*priv_type_text
);
119 static Oid
convert_language_name(text
*languagename
);
120 static AclMode
convert_language_priv_string(text
*priv_type_text
);
121 static Oid
convert_schema_name(text
*schemaname
);
122 static AclMode
convert_schema_priv_string(text
*priv_type_text
);
123 static Oid
convert_server_name(text
*servername
);
124 static AclMode
convert_server_priv_string(text
*priv_type_text
);
125 static Oid
convert_tablespace_name(text
*tablespacename
);
126 static AclMode
convert_tablespace_priv_string(text
*priv_type_text
);
127 static Oid
convert_type_name(text
*typename
);
128 static AclMode
convert_type_priv_string(text
*priv_type_text
);
129 static AclMode
convert_parameter_priv_string(text
*priv_text
);
130 static AclMode
convert_largeobject_priv_string(text
*priv_text
);
131 static AclMode
convert_role_priv_string(text
*priv_type_text
);
132 static AclResult
pg_role_aclcheck(Oid role_oid
, Oid roleid
, AclMode mode
);
134 static void RoleMembershipCacheCallback(Datum arg
, int cacheid
, uint32 hashvalue
);
139 * Consumes the first alphanumeric string (identifier) found in string
140 * 's', ignoring any leading white space. If it finds a double quote
141 * it returns the word inside the quotes.
144 * the string position in 's' that points to the next non-space character
145 * in 's', after any quotes. Also:
146 * - loads the identifier into 'n'. (If no identifier is found, 'n'
147 * contains an empty string.) 'n' must be NAMEDATALEN bytes.
149 * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
150 * in which case we log the error there and return NULL.
153 getid(const char *s
, char *n
, Node
*escontext
)
156 bool in_quotes
= false;
160 while (isspace((unsigned char) *s
))
162 /* This code had better match what putid() does, below */
165 (isalnum((unsigned char) *s
) ||
173 /* safe to look at next char (could be '\0' though) */
176 in_quotes
= !in_quotes
;
179 /* it's an escaped double quote; skip the escaping char */
183 /* Add the character to the string */
184 if (len
>= NAMEDATALEN
- 1)
185 ereturn(escontext
, NULL
,
186 (errcode(ERRCODE_NAME_TOO_LONG
),
187 errmsg("identifier too long"),
188 errdetail("Identifier must be less than %d characters.",
194 while (isspace((unsigned char) *s
))
200 * Write a role name at *p, adding double quotes if needed.
201 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
202 * This needs to be kept in sync with dequoteAclUserName in pg_dump/dumputils.c
205 putid(char *p
, const char *s
)
210 for (src
= s
; *src
; src
++)
212 /* This test had better match what getid() does, above */
213 if (!isalnum((unsigned char) *src
) && *src
!= '_')
221 for (src
= s
; *src
; src
++)
223 /* A double quote character in a username is encoded as "" */
235 * Consumes and parses an ACL specification of the form:
236 * [group|user] [A-Za-z0-9]*=[rwaR]*
237 * from string 's', ignoring any leading white space or white space
238 * between the optional id type keyword (group|user) and the actual
241 * The group|user decoration is unnecessary in the roles world,
242 * but we still accept it for backward compatibility.
244 * This routine is called by the parser as well as aclitemin(), hence
245 * the added generality.
248 * the string position in 's' immediately following the ACL
249 * specification. Also:
250 * - loads the structure pointed to by 'aip' with the appropriate
251 * UID/GID, id type identifier and mode type values.
253 * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
254 * in which case we log the error there and return NULL.
257 aclparse(const char *s
, AclItem
*aip
, Node
*escontext
)
262 char name
[NAMEDATALEN
];
263 char name2
[NAMEDATALEN
];
267 s
= getid(s
, name
, escontext
);
272 /* we just read a keyword, not a name */
273 if (strcmp(name
, "group") != 0 && strcmp(name
, "user") != 0)
274 ereturn(escontext
, NULL
,
275 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
276 errmsg("unrecognized key word: \"%s\"", name
),
277 errhint("ACL key word must be \"group\" or \"user\".")));
278 /* move s to the name beyond the keyword */
279 s
= getid(s
, name
, escontext
);
283 ereturn(escontext
, NULL
,
284 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
285 errmsg("missing name"),
286 errhint("A name must follow the \"group\" or \"user\" key word.")));
290 ereturn(escontext
, NULL
,
291 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
292 errmsg("missing \"=\" sign")));
294 privs
= goption
= ACL_NO_RIGHTS
;
296 for (++s
, read
= 0; isalpha((unsigned char) *s
) || *s
== '*'; s
++)
315 case ACL_TRUNCATE_CHR
:
318 case ACL_REFERENCES_CHR
:
319 read
= ACL_REFERENCES
;
321 case ACL_TRIGGER_CHR
:
324 case ACL_EXECUTE_CHR
:
333 case ACL_CREATE_TEMP_CHR
:
334 read
= ACL_CREATE_TEMP
;
336 case ACL_CONNECT_CHR
:
342 case ACL_ALTER_SYSTEM_CHR
:
343 read
= ACL_ALTER_SYSTEM
;
345 case ACL_MAINTAIN_CHR
:
349 ereturn(escontext
, NULL
,
350 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
351 errmsg("invalid mode character: must be one of \"%s\"",
352 ACL_ALL_RIGHTS_STR
)));
359 aip
->ai_grantee
= ACL_ID_PUBLIC
;
362 aip
->ai_grantee
= get_role_oid(name
, true);
363 if (!OidIsValid(aip
->ai_grantee
))
364 ereturn(escontext
, NULL
,
365 (errcode(ERRCODE_UNDEFINED_OBJECT
),
366 errmsg("role \"%s\" does not exist", name
)));
370 * XXX Allow a degree of backward compatibility by defaulting the grantor
375 s
= getid(s
+ 1, name2
, escontext
);
378 if (name2
[0] == '\0')
379 ereturn(escontext
, NULL
,
380 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
381 errmsg("a name must follow the \"/\" sign")));
382 aip
->ai_grantor
= get_role_oid(name2
, true);
383 if (!OidIsValid(aip
->ai_grantor
))
384 ereturn(escontext
, NULL
,
385 (errcode(ERRCODE_UNDEFINED_OBJECT
),
386 errmsg("role \"%s\" does not exist", name2
)));
390 aip
->ai_grantor
= BOOTSTRAP_SUPERUSERID
;
392 (errcode(ERRCODE_INVALID_GRANTOR
),
393 errmsg("defaulting grantor to user ID %u",
394 BOOTSTRAP_SUPERUSERID
)));
397 ACLITEM_SET_PRIVS_GOPTIONS(*aip
, privs
, goption
);
404 * Allocates storage for a new Acl with 'n' entries.
416 elog(ERROR
, "invalid size: %d", n
);
417 size
= ACL_N_SIZE(n
);
418 new_acl
= (Acl
*) palloc0(size
);
419 SET_VARSIZE(new_acl
, size
);
421 new_acl
->dataoffset
= 0; /* we never put in any nulls */
422 new_acl
->elemtype
= ACLITEMOID
;
423 ARR_LBOUND(new_acl
)[0] = 1;
424 ARR_DIMS(new_acl
)[0] = n
;
429 * Create a zero-entry ACL
441 aclcopy(const Acl
*orig_acl
)
445 result_acl
= allocacl(ACL_NUM(orig_acl
));
447 memcpy(ACL_DAT(result_acl
),
449 ACL_NUM(orig_acl
) * sizeof(AclItem
));
455 * Concatenate two ACLs
457 * This is a bit cheesy, since we may produce an ACL with redundant entries.
458 * Be careful what the result is used for!
461 aclconcat(const Acl
*left_acl
, const Acl
*right_acl
)
465 result_acl
= allocacl(ACL_NUM(left_acl
) + ACL_NUM(right_acl
));
467 memcpy(ACL_DAT(result_acl
),
469 ACL_NUM(left_acl
) * sizeof(AclItem
));
471 memcpy(ACL_DAT(result_acl
) + ACL_NUM(left_acl
),
473 ACL_NUM(right_acl
) * sizeof(AclItem
));
481 * This produces a properly merged ACL with no redundant entries.
482 * Returns NULL on NULL input.
485 aclmerge(const Acl
*left_acl
, const Acl
*right_acl
, Oid ownerId
)
492 /* Check for cases where one or both are empty/null */
493 if (left_acl
== NULL
|| ACL_NUM(left_acl
) == 0)
495 if (right_acl
== NULL
|| ACL_NUM(right_acl
) == 0)
498 return aclcopy(right_acl
);
502 if (right_acl
== NULL
|| ACL_NUM(right_acl
) == 0)
503 return aclcopy(left_acl
);
506 /* Merge them the hard way, one item at a time */
507 result_acl
= aclcopy(left_acl
);
509 aip
= ACL_DAT(right_acl
);
510 num
= ACL_NUM(right_acl
);
512 for (i
= 0; i
< num
; i
++, aip
++)
516 tmp_acl
= aclupdate(result_acl
, aip
, ACL_MODECHG_ADD
,
517 ownerId
, DROP_RESTRICT
);
519 result_acl
= tmp_acl
;
526 * Sort the items in an ACL (into an arbitrary but consistent order)
529 aclitemsort(Acl
*acl
)
531 if (acl
!= NULL
&& ACL_NUM(acl
) > 1)
532 qsort(ACL_DAT(acl
), ACL_NUM(acl
), sizeof(AclItem
), aclitemComparator
);
536 * Check if two ACLs are exactly equal
538 * This will not detect equality if the two arrays contain the same items
539 * in different orders. To handle that case, sort both inputs first,
540 * using aclitemsort().
543 aclequal(const Acl
*left_acl
, const Acl
*right_acl
)
545 /* Check for cases where one or both are empty/null */
546 if (left_acl
== NULL
|| ACL_NUM(left_acl
) == 0)
548 if (right_acl
== NULL
|| ACL_NUM(right_acl
) == 0)
555 if (right_acl
== NULL
|| ACL_NUM(right_acl
) == 0)
559 if (ACL_NUM(left_acl
) != ACL_NUM(right_acl
))
562 if (memcmp(ACL_DAT(left_acl
),
564 ACL_NUM(left_acl
) * sizeof(AclItem
)) == 0)
571 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
574 check_acl(const Acl
*acl
)
576 if (ARR_ELEMTYPE(acl
) != ACLITEMOID
)
578 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
579 errmsg("ACL array contains wrong data type")));
580 if (ARR_NDIM(acl
) != 1)
582 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
583 errmsg("ACL arrays must be one-dimensional")));
584 if (ARR_HASNULL(acl
))
586 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED
),
587 errmsg("ACL arrays must not contain null values")));
592 * Allocates storage for, and fills in, a new AclItem given a string
593 * 's' that contains an ACL specification. See aclparse for details.
599 aclitemin(PG_FUNCTION_ARGS
)
601 const char *s
= PG_GETARG_CSTRING(0);
602 Node
*escontext
= fcinfo
->context
;
605 aip
= (AclItem
*) palloc(sizeof(AclItem
));
607 s
= aclparse(s
, aip
, escontext
);
611 while (isspace((unsigned char) *s
))
614 ereturn(escontext
, (Datum
) 0,
615 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
616 errmsg("extra garbage at the end of the ACL specification")));
618 PG_RETURN_ACLITEM_P(aip
);
623 * Allocates storage for, and fills in, a new null-delimited string
624 * containing a formatted ACL specification. See aclparse for details.
630 aclitemout(PG_FUNCTION_ARGS
)
632 AclItem
*aip
= PG_GETARG_ACLITEM_P(0);
638 out
= palloc(strlen("=/") +
640 2 * (2 * NAMEDATALEN
+ 2) +
646 if (aip
->ai_grantee
!= ACL_ID_PUBLIC
)
648 htup
= SearchSysCache1(AUTHOID
, ObjectIdGetDatum(aip
->ai_grantee
));
649 if (HeapTupleIsValid(htup
))
651 putid(p
, NameStr(((Form_pg_authid
) GETSTRUCT(htup
))->rolname
));
652 ReleaseSysCache(htup
);
656 /* Generate numeric OID if we don't find an entry */
657 sprintf(p
, "%u", aip
->ai_grantee
);
665 for (i
= 0; i
< N_ACL_RIGHTS
; ++i
)
667 if (ACLITEM_GET_PRIVS(*aip
) & (UINT64CONST(1) << i
))
668 *p
++ = ACL_ALL_RIGHTS_STR
[i
];
669 if (ACLITEM_GET_GOPTIONS(*aip
) & (UINT64CONST(1) << i
))
676 htup
= SearchSysCache1(AUTHOID
, ObjectIdGetDatum(aip
->ai_grantor
));
677 if (HeapTupleIsValid(htup
))
679 putid(p
, NameStr(((Form_pg_authid
) GETSTRUCT(htup
))->rolname
));
680 ReleaseSysCache(htup
);
684 /* Generate numeric OID if we don't find an entry */
685 sprintf(p
, "%u", aip
->ai_grantor
);
688 PG_RETURN_CSTRING(out
);
693 * Two AclItems are considered to match iff they have the same
694 * grantee and grantor; the privileges are ignored.
697 aclitem_match(const AclItem
*a1
, const AclItem
*a2
)
699 return a1
->ai_grantee
== a2
->ai_grantee
&&
700 a1
->ai_grantor
== a2
->ai_grantor
;
705 * qsort comparison function for AclItems
708 aclitemComparator(const void *arg1
, const void *arg2
)
710 const AclItem
*a1
= (const AclItem
*) arg1
;
711 const AclItem
*a2
= (const AclItem
*) arg2
;
713 if (a1
->ai_grantee
> a2
->ai_grantee
)
715 if (a1
->ai_grantee
< a2
->ai_grantee
)
717 if (a1
->ai_grantor
> a2
->ai_grantor
)
719 if (a1
->ai_grantor
< a2
->ai_grantor
)
721 if (a1
->ai_privs
> a2
->ai_privs
)
723 if (a1
->ai_privs
< a2
->ai_privs
)
729 * aclitem equality operator
732 aclitem_eq(PG_FUNCTION_ARGS
)
734 AclItem
*a1
= PG_GETARG_ACLITEM_P(0);
735 AclItem
*a2
= PG_GETARG_ACLITEM_P(1);
738 result
= a1
->ai_privs
== a2
->ai_privs
&&
739 a1
->ai_grantee
== a2
->ai_grantee
&&
740 a1
->ai_grantor
== a2
->ai_grantor
;
741 PG_RETURN_BOOL(result
);
745 * aclitem hash function
747 * We make aclitems hashable not so much because anyone is likely to hash
748 * them, as because we want array equality to work on aclitem arrays, and
749 * with the typcache mechanism we must have a hash or btree opclass.
752 hash_aclitem(PG_FUNCTION_ARGS
)
754 AclItem
*a
= PG_GETARG_ACLITEM_P(0);
756 /* not very bright, but avoids any issue of padding in struct */
757 PG_RETURN_UINT32((uint32
) (a
->ai_privs
+ a
->ai_grantee
+ a
->ai_grantor
));
761 * 64-bit hash function for aclitem.
763 * Similar to hash_aclitem, but accepts a seed and returns a uint64 value.
766 hash_aclitem_extended(PG_FUNCTION_ARGS
)
768 AclItem
*a
= PG_GETARG_ACLITEM_P(0);
769 uint64 seed
= PG_GETARG_INT64(1);
770 uint32 sum
= (uint32
) (a
->ai_privs
+ a
->ai_grantee
+ a
->ai_grantor
);
772 return (seed
== 0) ? UInt64GetDatum(sum
) : hash_uint32_extended(sum
, seed
);
776 * acldefault() --- create an ACL describing default access permissions
778 * Change this routine if you want to alter the default access policy for
779 * newly-created objects (or any object with a NULL acl entry). When
780 * you make a change here, don't forget to update the GRANT man page,
781 * which explains all the default permissions.
783 * Note that these are the hard-wired "defaults" that are used in the
784 * absence of any pg_default_acl entry.
787 acldefault(ObjectType objtype
, Oid ownerId
)
789 AclMode world_default
;
790 AclMode owner_default
;
798 /* by default, columns have no extra privileges */
799 world_default
= ACL_NO_RIGHTS
;
800 owner_default
= ACL_NO_RIGHTS
;
803 world_default
= ACL_NO_RIGHTS
;
804 owner_default
= ACL_ALL_RIGHTS_RELATION
;
806 case OBJECT_SEQUENCE
:
807 world_default
= ACL_NO_RIGHTS
;
808 owner_default
= ACL_ALL_RIGHTS_SEQUENCE
;
810 case OBJECT_DATABASE
:
811 /* for backwards compatibility, grant some rights by default */
812 world_default
= ACL_CREATE_TEMP
| ACL_CONNECT
;
813 owner_default
= ACL_ALL_RIGHTS_DATABASE
;
815 case OBJECT_FUNCTION
:
816 /* Grant EXECUTE by default, for now */
817 world_default
= ACL_EXECUTE
;
818 owner_default
= ACL_ALL_RIGHTS_FUNCTION
;
820 case OBJECT_LANGUAGE
:
821 /* Grant USAGE by default, for now */
822 world_default
= ACL_USAGE
;
823 owner_default
= ACL_ALL_RIGHTS_LANGUAGE
;
825 case OBJECT_LARGEOBJECT
:
826 world_default
= ACL_NO_RIGHTS
;
827 owner_default
= ACL_ALL_RIGHTS_LARGEOBJECT
;
830 world_default
= ACL_NO_RIGHTS
;
831 owner_default
= ACL_ALL_RIGHTS_SCHEMA
;
833 case OBJECT_TABLESPACE
:
834 world_default
= ACL_NO_RIGHTS
;
835 owner_default
= ACL_ALL_RIGHTS_TABLESPACE
;
838 world_default
= ACL_NO_RIGHTS
;
839 owner_default
= ACL_ALL_RIGHTS_FDW
;
841 case OBJECT_FOREIGN_SERVER
:
842 world_default
= ACL_NO_RIGHTS
;
843 owner_default
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
847 world_default
= ACL_USAGE
;
848 owner_default
= ACL_ALL_RIGHTS_TYPE
;
850 case OBJECT_PARAMETER_ACL
:
851 world_default
= ACL_NO_RIGHTS
;
852 owner_default
= ACL_ALL_RIGHTS_PARAMETER_ACL
;
855 elog(ERROR
, "unrecognized object type: %d", (int) objtype
);
856 world_default
= ACL_NO_RIGHTS
; /* keep compiler quiet */
857 owner_default
= ACL_NO_RIGHTS
;
862 if (world_default
!= ACL_NO_RIGHTS
)
864 if (owner_default
!= ACL_NO_RIGHTS
)
867 acl
= allocacl(nacl
);
870 if (world_default
!= ACL_NO_RIGHTS
)
872 aip
->ai_grantee
= ACL_ID_PUBLIC
;
873 aip
->ai_grantor
= ownerId
;
874 ACLITEM_SET_PRIVS_GOPTIONS(*aip
, world_default
, ACL_NO_RIGHTS
);
879 * Note that the owner's entry shows all ordinary privileges but no grant
880 * options. This is because his grant options come "from the system" and
881 * not from his own efforts. (The SQL spec says that the owner's rights
882 * come from a "_SYSTEM" authid.) However, we do consider that the
883 * owner's ordinary privileges are self-granted; this lets him revoke
884 * them. We implement the owner's grant options without any explicit
885 * "_SYSTEM"-like ACL entry, by internally special-casing the owner
886 * wherever we are testing grant options.
888 if (owner_default
!= ACL_NO_RIGHTS
)
890 aip
->ai_grantee
= ownerId
;
891 aip
->ai_grantor
= ownerId
;
892 ACLITEM_SET_PRIVS_GOPTIONS(*aip
, owner_default
, ACL_NO_RIGHTS
);
900 * SQL-accessible version of acldefault(). Hackish mapping from "char" type to
904 acldefault_sql(PG_FUNCTION_ARGS
)
906 char objtypec
= PG_GETARG_CHAR(0);
907 Oid owner
= PG_GETARG_OID(1);
908 ObjectType objtype
= 0;
913 objtype
= OBJECT_COLUMN
;
916 objtype
= OBJECT_TABLE
;
919 objtype
= OBJECT_SEQUENCE
;
922 objtype
= OBJECT_DATABASE
;
925 objtype
= OBJECT_FUNCTION
;
928 objtype
= OBJECT_LANGUAGE
;
931 objtype
= OBJECT_LARGEOBJECT
;
934 objtype
= OBJECT_SCHEMA
;
937 objtype
= OBJECT_PARAMETER_ACL
;
940 objtype
= OBJECT_TABLESPACE
;
943 objtype
= OBJECT_FDW
;
946 objtype
= OBJECT_FOREIGN_SERVER
;
949 objtype
= OBJECT_TYPE
;
952 elog(ERROR
, "unrecognized object type abbreviation: %c", objtypec
);
955 PG_RETURN_ACL_P(acldefault(objtype
, owner
));
960 * Update an ACL array to add or remove specified privileges.
962 * old_acl: the input ACL array
963 * mod_aip: defines the privileges to be added, removed, or substituted
964 * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
965 * ownerId: Oid of object owner
966 * behavior: RESTRICT or CASCADE behavior for recursive removal
968 * ownerid and behavior are only relevant when the update operation specifies
969 * deletion of grant options.
971 * The result is a modified copy; the input object is not changed.
973 * NB: caller is responsible for having detoasted the input ACL, if needed.
976 aclupdate(const Acl
*old_acl
, const AclItem
*mod_aip
,
977 int modechg
, Oid ownerId
, DropBehavior behavior
)
989 /* Caller probably already checked old_acl, but be safe */
992 /* If granting grant options, check for circularity */
993 if (modechg
!= ACL_MODECHG_DEL
&&
994 ACLITEM_GET_GOPTIONS(*mod_aip
) != ACL_NO_RIGHTS
)
995 check_circularity(old_acl
, mod_aip
, ownerId
);
997 num
= ACL_NUM(old_acl
);
998 old_aip
= ACL_DAT(old_acl
);
1001 * Search the ACL for an existing entry for this grantee and grantor. If
1002 * one exists, just modify the entry in-place (well, in the same position,
1003 * since we actually return a copy); otherwise, insert the new entry at
1007 for (dst
= 0; dst
< num
; ++dst
)
1009 if (aclitem_match(mod_aip
, old_aip
+ dst
))
1011 /* found a match, so modify existing item */
1012 new_acl
= allocacl(num
);
1013 new_aip
= ACL_DAT(new_acl
);
1014 memcpy(new_acl
, old_acl
, ACL_SIZE(old_acl
));
1021 /* need to append a new item */
1022 new_acl
= allocacl(num
+ 1);
1023 new_aip
= ACL_DAT(new_acl
);
1024 memcpy(new_aip
, old_aip
, num
* sizeof(AclItem
));
1026 /* initialize the new entry with no permissions */
1027 new_aip
[dst
].ai_grantee
= mod_aip
->ai_grantee
;
1028 new_aip
[dst
].ai_grantor
= mod_aip
->ai_grantor
;
1029 ACLITEM_SET_PRIVS_GOPTIONS(new_aip
[dst
],
1030 ACL_NO_RIGHTS
, ACL_NO_RIGHTS
);
1031 num
++; /* set num to the size of new_acl */
1034 old_rights
= ACLITEM_GET_RIGHTS(new_aip
[dst
]);
1035 old_goptions
= ACLITEM_GET_GOPTIONS(new_aip
[dst
]);
1037 /* apply the specified permissions change */
1040 case ACL_MODECHG_ADD
:
1041 ACLITEM_SET_RIGHTS(new_aip
[dst
],
1042 old_rights
| ACLITEM_GET_RIGHTS(*mod_aip
));
1044 case ACL_MODECHG_DEL
:
1045 ACLITEM_SET_RIGHTS(new_aip
[dst
],
1046 old_rights
& ~ACLITEM_GET_RIGHTS(*mod_aip
));
1048 case ACL_MODECHG_EQL
:
1049 ACLITEM_SET_RIGHTS(new_aip
[dst
],
1050 ACLITEM_GET_RIGHTS(*mod_aip
));
1054 new_rights
= ACLITEM_GET_RIGHTS(new_aip
[dst
]);
1055 new_goptions
= ACLITEM_GET_GOPTIONS(new_aip
[dst
]);
1058 * If the adjusted entry has no permissions, delete it from the list.
1060 if (new_rights
== ACL_NO_RIGHTS
)
1062 memmove(new_aip
+ dst
,
1064 (num
- dst
- 1) * sizeof(AclItem
));
1065 /* Adjust array size to be 'num - 1' items */
1066 ARR_DIMS(new_acl
)[0] = num
- 1;
1067 SET_VARSIZE(new_acl
, ACL_N_SIZE(num
- 1));
1071 * Remove abandoned privileges (cascading revoke). Currently we can only
1072 * handle this when the grantee is not PUBLIC.
1074 if ((old_goptions
& ~new_goptions
) != 0)
1076 Assert(mod_aip
->ai_grantee
!= ACL_ID_PUBLIC
);
1077 new_acl
= recursive_revoke(new_acl
, mod_aip
->ai_grantee
,
1078 (old_goptions
& ~new_goptions
),
1086 * Update an ACL array to reflect a change of owner to the parent object
1088 * old_acl: the input ACL array (must not be NULL)
1089 * oldOwnerId: Oid of the old object owner
1090 * newOwnerId: Oid of the new object owner
1092 * The result is a modified copy; the input object is not changed.
1094 * NB: caller is responsible for having detoasted the input ACL, if needed.
1096 * Note: the name of this function is a bit of a misnomer, since it will
1097 * happily make the specified role substitution whether the old role is
1098 * really the owner of the parent object or merely mentioned in its ACL.
1099 * But the vast majority of callers use it in connection with ALTER OWNER
1100 * operations, so we'll keep the name.
1103 aclnewowner(const Acl
*old_acl
, Oid oldOwnerId
, Oid newOwnerId
)
1111 bool newpresent
= false;
1120 * Make a copy of the given ACL, substituting new owner ID for old
1121 * wherever it appears as either grantor or grantee. Also note if the new
1122 * owner ID is already present.
1124 num
= ACL_NUM(old_acl
);
1125 old_aip
= ACL_DAT(old_acl
);
1126 new_acl
= allocacl(num
);
1127 new_aip
= ACL_DAT(new_acl
);
1128 memcpy(new_aip
, old_aip
, num
* sizeof(AclItem
));
1129 for (dst
= 0, dst_aip
= new_aip
; dst
< num
; dst
++, dst_aip
++)
1131 if (dst_aip
->ai_grantor
== oldOwnerId
)
1132 dst_aip
->ai_grantor
= newOwnerId
;
1133 else if (dst_aip
->ai_grantor
== newOwnerId
)
1135 if (dst_aip
->ai_grantee
== oldOwnerId
)
1136 dst_aip
->ai_grantee
= newOwnerId
;
1137 else if (dst_aip
->ai_grantee
== newOwnerId
)
1142 * If the old ACL contained any references to the new owner, then we may
1143 * now have generated an ACL containing duplicate entries. Find them and
1144 * merge them so that there are not duplicates. (This is relatively
1145 * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
1146 * be the normal case.)
1148 * To simplify deletion of duplicate entries, we temporarily leave them in
1149 * the array but set their privilege masks to zero; when we reach such an
1150 * entry it's just skipped. (Thus, a side effect of this code will be to
1151 * remove privilege-free entries, should there be any in the input.) dst
1152 * is the next output slot, targ is the currently considered input slot
1153 * (always >= dst), and src scans entries to the right of targ looking for
1154 * duplicates. Once an entry has been emitted to dst it is known
1155 * duplicate-free and need not be considered anymore.
1160 for (targ
= 0, targ_aip
= new_aip
; targ
< num
; targ
++, targ_aip
++)
1162 /* ignore if deleted in an earlier pass */
1163 if (ACLITEM_GET_RIGHTS(*targ_aip
) == ACL_NO_RIGHTS
)
1165 /* find and merge any duplicates */
1166 for (src
= targ
+ 1, src_aip
= targ_aip
+ 1; src
< num
;
1169 if (ACLITEM_GET_RIGHTS(*src_aip
) == ACL_NO_RIGHTS
)
1171 if (aclitem_match(targ_aip
, src_aip
))
1173 ACLITEM_SET_RIGHTS(*targ_aip
,
1174 ACLITEM_GET_RIGHTS(*targ_aip
) |
1175 ACLITEM_GET_RIGHTS(*src_aip
));
1176 /* mark the duplicate deleted */
1177 ACLITEM_SET_RIGHTS(*src_aip
, ACL_NO_RIGHTS
);
1180 /* and emit to output */
1181 new_aip
[dst
] = *targ_aip
;
1184 /* Adjust array size to be 'dst' items */
1185 ARR_DIMS(new_acl
)[0] = dst
;
1186 SET_VARSIZE(new_acl
, ACL_N_SIZE(dst
));
1194 * When granting grant options, we must disallow attempts to set up circular
1195 * chains of grant options. Suppose A (the object owner) grants B some
1196 * privileges with grant option, and B re-grants them to C. If C could
1197 * grant the privileges to B as well, then A would be unable to effectively
1198 * revoke the privileges from B, since recursive_revoke would consider that
1199 * B still has 'em from C.
1201 * We check for this by recursively deleting all grant options belonging to
1202 * the target grantee, and then seeing if the would-be grantor still has the
1203 * grant option or not.
1206 check_circularity(const Acl
*old_acl
, const AclItem
*mod_aip
,
1218 * For now, grant options can only be granted to roles, not PUBLIC.
1219 * Otherwise we'd have to work a bit harder here.
1221 Assert(mod_aip
->ai_grantee
!= ACL_ID_PUBLIC
);
1223 /* The owner always has grant options, no need to check */
1224 if (mod_aip
->ai_grantor
== ownerId
)
1227 /* Make a working copy */
1228 acl
= allocacl(ACL_NUM(old_acl
));
1229 memcpy(acl
, old_acl
, ACL_SIZE(old_acl
));
1231 /* Zap all grant options of target grantee, plus what depends on 'em */
1235 for (i
= 0; i
< num
; i
++)
1237 if (aip
[i
].ai_grantee
== mod_aip
->ai_grantee
&&
1238 ACLITEM_GET_GOPTIONS(aip
[i
]) != ACL_NO_RIGHTS
)
1242 /* We'll actually zap ordinary privs too, but no matter */
1243 new_acl
= aclupdate(acl
, &aip
[i
], ACL_MODECHG_DEL
,
1244 ownerId
, DROP_CASCADE
);
1253 /* Now we can compute grantor's independently-derived privileges */
1254 own_privs
= aclmask(acl
,
1255 mod_aip
->ai_grantor
,
1257 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip
)),
1259 own_privs
= ACL_OPTION_TO_PRIVS(own_privs
);
1261 if ((ACLITEM_GET_GOPTIONS(*mod_aip
) & ~own_privs
) != 0)
1263 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1264 errmsg("grant options cannot be granted back to your own grantor")));
1271 * Ensure that no privilege is "abandoned". A privilege is abandoned
1272 * if the user that granted the privilege loses the grant option. (So
1273 * the chain through which it was granted is broken.) Either the
1274 * abandoned privileges are revoked as well, or an error message is
1275 * printed, depending on the drop behavior option.
1277 * acl: the input ACL list
1278 * grantee: the user from whom some grant options have been revoked
1279 * revoke_privs: the grant options being revoked
1280 * ownerId: Oid of object owner
1281 * behavior: RESTRICT or CASCADE behavior for recursive removal
1283 * The input Acl object is pfree'd if replaced.
1286 recursive_revoke(Acl
*acl
,
1288 AclMode revoke_privs
,
1290 DropBehavior behavior
)
1299 /* The owner can never truly lose grant options, so short-circuit */
1300 if (grantee
== ownerId
)
1303 /* The grantee might still have some grant options via another grantor */
1304 still_has
= aclmask(acl
, grantee
, ownerId
,
1305 ACL_GRANT_OPTION_FOR(revoke_privs
),
1307 revoke_privs
&= ~ACL_OPTION_TO_PRIVS(still_has
);
1308 if (revoke_privs
== ACL_NO_RIGHTS
)
1314 for (i
= 0; i
< num
; i
++)
1316 if (aip
[i
].ai_grantor
== grantee
1317 && (ACLITEM_GET_PRIVS(aip
[i
]) & revoke_privs
) != 0)
1322 if (behavior
== DROP_RESTRICT
)
1324 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST
),
1325 errmsg("dependent privileges exist"),
1326 errhint("Use CASCADE to revoke them too.")));
1328 mod_acl
.ai_grantor
= grantee
;
1329 mod_acl
.ai_grantee
= aip
[i
].ai_grantee
;
1330 ACLITEM_SET_PRIVS_GOPTIONS(mod_acl
,
1334 new_acl
= aclupdate(acl
, &mod_acl
, ACL_MODECHG_DEL
,
1349 * aclmask --- compute bitmask of all privileges held by roleid.
1351 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1352 * held by the given roleid according to the given ACL list, ANDed
1353 * with 'mask'. (The point of passing 'mask' is to let the routine
1354 * exit early if all privileges of interest have been found.)
1356 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1357 * is known true. (This lets us exit soonest in cases where the
1358 * caller is only going to test for zero or nonzero result.)
1362 * To see if any of a set of privileges are held:
1363 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1365 * To see if all of a set of privileges are held:
1366 * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1368 * To determine exactly which of a set of privileges are held:
1369 * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1372 aclmask(const Acl
*acl
, Oid roleid
, Oid ownerId
,
1373 AclMode mask
, AclMaskHow how
)
1382 * Null ACL should not happen, since caller should have inserted
1383 * appropriate default
1386 elog(ERROR
, "null ACL");
1390 /* Quick exit for mask == 0 */
1396 /* Owner always implicitly has all grant options */
1397 if ((mask
& ACLITEM_ALL_GOPTION_BITS
) &&
1398 has_privs_of_role(roleid
, ownerId
))
1400 result
= mask
& ACLITEM_ALL_GOPTION_BITS
;
1401 if ((how
== ACLMASK_ALL
) ? (result
== mask
) : (result
!= 0))
1406 aidat
= ACL_DAT(acl
);
1409 * Check privileges granted directly to roleid or to public
1411 for (i
= 0; i
< num
; i
++)
1413 AclItem
*aidata
= &aidat
[i
];
1415 if (aidata
->ai_grantee
== ACL_ID_PUBLIC
||
1416 aidata
->ai_grantee
== roleid
)
1418 result
|= aidata
->ai_privs
& mask
;
1419 if ((how
== ACLMASK_ALL
) ? (result
== mask
) : (result
!= 0))
1425 * Check privileges granted indirectly via role memberships. We do this in
1426 * a separate pass to minimize expensive indirect membership tests. In
1427 * particular, it's worth testing whether a given ACL entry grants any
1428 * privileges still of interest before we perform the has_privs_of_role
1431 remaining
= mask
& ~result
;
1432 for (i
= 0; i
< num
; i
++)
1434 AclItem
*aidata
= &aidat
[i
];
1436 if (aidata
->ai_grantee
== ACL_ID_PUBLIC
||
1437 aidata
->ai_grantee
== roleid
)
1438 continue; /* already checked it */
1440 if ((aidata
->ai_privs
& remaining
) &&
1441 has_privs_of_role(roleid
, aidata
->ai_grantee
))
1443 result
|= aidata
->ai_privs
& mask
;
1444 if ((how
== ACLMASK_ALL
) ? (result
== mask
) : (result
!= 0))
1446 remaining
= mask
& ~result
;
1455 * aclmask_direct --- compute bitmask of all privileges held by roleid.
1457 * This is exactly like aclmask() except that we consider only privileges
1458 * held *directly* by roleid, not those inherited via role membership.
1461 aclmask_direct(const Acl
*acl
, Oid roleid
, Oid ownerId
,
1462 AclMode mask
, AclMaskHow how
)
1470 * Null ACL should not happen, since caller should have inserted
1471 * appropriate default
1474 elog(ERROR
, "null ACL");
1478 /* Quick exit for mask == 0 */
1484 /* Owner always implicitly has all grant options */
1485 if ((mask
& ACLITEM_ALL_GOPTION_BITS
) &&
1488 result
= mask
& ACLITEM_ALL_GOPTION_BITS
;
1489 if ((how
== ACLMASK_ALL
) ? (result
== mask
) : (result
!= 0))
1494 aidat
= ACL_DAT(acl
);
1497 * Check privileges granted directly to roleid (and not to public)
1499 for (i
= 0; i
< num
; i
++)
1501 AclItem
*aidata
= &aidat
[i
];
1503 if (aidata
->ai_grantee
== roleid
)
1505 result
|= aidata
->ai_privs
& mask
;
1506 if ((how
== ACLMASK_ALL
) ? (result
== mask
) : (result
!= 0))
1517 * Find out all the roleids mentioned in an Acl.
1518 * Note that we do not distinguish grantors from grantees.
1520 * *roleids is set to point to a palloc'd array containing distinct OIDs
1521 * in sorted order. The length of the array is the function result.
1524 aclmembers(const Acl
*acl
, Oid
**roleids
)
1527 const AclItem
*acldat
;
1531 if (acl
== NULL
|| ACL_NUM(acl
) == 0)
1539 /* Allocate the worst-case space requirement */
1540 list
= palloc(ACL_NUM(acl
) * 2 * sizeof(Oid
));
1541 acldat
= ACL_DAT(acl
);
1544 * Walk the ACL collecting mentioned RoleIds.
1547 for (i
= 0; i
< ACL_NUM(acl
); i
++)
1549 const AclItem
*ai
= &acldat
[i
];
1551 if (ai
->ai_grantee
!= ACL_ID_PUBLIC
)
1552 list
[j
++] = ai
->ai_grantee
;
1553 /* grantor is currently never PUBLIC, but let's check anyway */
1554 if (ai
->ai_grantor
!= ACL_ID_PUBLIC
)
1555 list
[j
++] = ai
->ai_grantor
;
1558 /* Sort the array */
1559 qsort(list
, j
, sizeof(Oid
), oid_cmp
);
1562 * We could repalloc the array down to minimum size, but it's hardly worth
1563 * it since it's only transient memory.
1567 /* Remove duplicates from the array */
1568 return qunique(list
, j
, sizeof(Oid
), oid_cmp
);
1573 * aclinsert (exported function)
1576 aclinsert(PG_FUNCTION_ARGS
)
1579 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
1580 errmsg("aclinsert is no longer supported")));
1582 PG_RETURN_NULL(); /* keep compiler quiet */
1586 aclremove(PG_FUNCTION_ARGS
)
1589 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
1590 errmsg("aclremove is no longer supported")));
1592 PG_RETURN_NULL(); /* keep compiler quiet */
1596 aclcontains(PG_FUNCTION_ARGS
)
1598 Acl
*acl
= PG_GETARG_ACL_P(0);
1599 AclItem
*aip
= PG_GETARG_ACLITEM_P(1);
1606 aidat
= ACL_DAT(acl
);
1607 for (i
= 0; i
< num
; ++i
)
1609 if (aip
->ai_grantee
== aidat
[i
].ai_grantee
&&
1610 aip
->ai_grantor
== aidat
[i
].ai_grantor
&&
1611 (ACLITEM_GET_RIGHTS(*aip
) & ACLITEM_GET_RIGHTS(aidat
[i
])) == ACLITEM_GET_RIGHTS(*aip
))
1612 PG_RETURN_BOOL(true);
1614 PG_RETURN_BOOL(false);
1618 makeaclitem(PG_FUNCTION_ARGS
)
1620 Oid grantee
= PG_GETARG_OID(0);
1621 Oid grantor
= PG_GETARG_OID(1);
1622 text
*privtext
= PG_GETARG_TEXT_PP(2);
1623 bool goption
= PG_GETARG_BOOL(3);
1626 static const priv_map any_priv_map
[] = {
1627 {"SELECT", ACL_SELECT
},
1628 {"INSERT", ACL_INSERT
},
1629 {"UPDATE", ACL_UPDATE
},
1630 {"DELETE", ACL_DELETE
},
1631 {"TRUNCATE", ACL_TRUNCATE
},
1632 {"REFERENCES", ACL_REFERENCES
},
1633 {"TRIGGER", ACL_TRIGGER
},
1634 {"EXECUTE", ACL_EXECUTE
},
1635 {"USAGE", ACL_USAGE
},
1636 {"CREATE", ACL_CREATE
},
1637 {"TEMP", ACL_CREATE_TEMP
},
1638 {"TEMPORARY", ACL_CREATE_TEMP
},
1639 {"CONNECT", ACL_CONNECT
},
1641 {"ALTER SYSTEM", ACL_ALTER_SYSTEM
},
1642 {"MAINTAIN", ACL_MAINTAIN
},
1646 priv
= convert_any_priv_string(privtext
, any_priv_map
);
1648 result
= (AclItem
*) palloc(sizeof(AclItem
));
1650 result
->ai_grantee
= grantee
;
1651 result
->ai_grantor
= grantor
;
1653 ACLITEM_SET_PRIVS_GOPTIONS(*result
, priv
,
1654 (goption
? priv
: ACL_NO_RIGHTS
));
1656 PG_RETURN_ACLITEM_P(result
);
1661 * convert_any_priv_string: recognize privilege strings for has_foo_privilege
1663 * We accept a comma-separated list of case-insensitive privilege names,
1664 * producing a bitmask of the OR'd privilege bits. We are liberal about
1665 * whitespace between items, not so much about whitespace within items.
1666 * The allowed privilege names are given as an array of priv_map structs,
1667 * terminated by one with a NULL name pointer.
1670 convert_any_priv_string(text
*priv_type_text
,
1671 const priv_map
*privileges
)
1674 char *priv_type
= text_to_cstring(priv_type_text
);
1678 /* We rely on priv_type being a private, modifiable string */
1679 for (chunk
= priv_type
; chunk
; chunk
= next_chunk
)
1682 const priv_map
*this_priv
;
1684 /* Split string at commas */
1685 next_chunk
= strchr(chunk
, ',');
1687 *next_chunk
++ = '\0';
1689 /* Drop leading/trailing whitespace in this chunk */
1690 while (*chunk
&& isspace((unsigned char) *chunk
))
1692 chunk_len
= strlen(chunk
);
1693 while (chunk_len
> 0 && isspace((unsigned char) chunk
[chunk_len
- 1]))
1695 chunk
[chunk_len
] = '\0';
1697 /* Match to the privileges list */
1698 for (this_priv
= privileges
; this_priv
->name
; this_priv
++)
1700 if (pg_strcasecmp(this_priv
->name
, chunk
) == 0)
1702 result
|= this_priv
->value
;
1706 if (!this_priv
->name
)
1708 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1709 errmsg("unrecognized privilege type: \"%s\"", chunk
)));
1718 convert_aclright_to_string(int aclright
)
1732 case ACL_REFERENCES
:
1733 return "REFERENCES";
1742 case ACL_CREATE_TEMP
:
1748 case ACL_ALTER_SYSTEM
:
1749 return "ALTER SYSTEM";
1753 elog(ERROR
, "unrecognized aclright: %d", aclright
);
1760 * Convert an aclitem[] to a table.
1764 * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
1768 * {{ OID(joe), 0::OID, 'SELECT', false },
1769 * { OID(joe), OID(foo), 'INSERT', true },
1770 * { OID(joe), OID(foo), 'UPDATE', false }}
1774 aclexplode(PG_FUNCTION_ARGS
)
1776 Acl
*acl
= PG_GETARG_ACL_P(0);
1777 FuncCallContext
*funcctx
;
1781 if (SRF_IS_FIRSTCALL())
1784 MemoryContext oldcontext
;
1788 funcctx
= SRF_FIRSTCALL_INIT();
1789 oldcontext
= MemoryContextSwitchTo(funcctx
->multi_call_memory_ctx
);
1792 * build tupdesc for result tuples (matches out parameters in pg_proc
1795 tupdesc
= CreateTemplateTupleDesc(4);
1796 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "grantor",
1798 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "grantee",
1800 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "privilege_type",
1802 TupleDescInitEntry(tupdesc
, (AttrNumber
) 4, "is_grantable",
1805 funcctx
->tuple_desc
= BlessTupleDesc(tupdesc
);
1807 /* allocate memory for user context */
1808 idx
= (int *) palloc(sizeof(int[2]));
1809 idx
[0] = 0; /* ACL array item index */
1810 idx
[1] = -1; /* privilege type counter */
1811 funcctx
->user_fctx
= idx
;
1813 MemoryContextSwitchTo(oldcontext
);
1816 funcctx
= SRF_PERCALL_SETUP();
1817 idx
= (int *) funcctx
->user_fctx
;
1818 aidat
= ACL_DAT(acl
);
1820 /* need test here in case acl has no items */
1821 while (idx
[0] < ACL_NUM(acl
))
1827 if (idx
[1] == N_ACL_RIGHTS
)
1831 if (idx
[0] >= ACL_NUM(acl
)) /* done */
1834 aidata
= &aidat
[idx
[0]];
1835 priv_bit
= UINT64CONST(1) << idx
[1];
1837 if (ACLITEM_GET_PRIVS(*aidata
) & priv_bit
)
1841 bool nulls
[4] = {0};
1844 values
[0] = ObjectIdGetDatum(aidata
->ai_grantor
);
1845 values
[1] = ObjectIdGetDatum(aidata
->ai_grantee
);
1846 values
[2] = CStringGetTextDatum(convert_aclright_to_string(priv_bit
));
1847 values
[3] = BoolGetDatum((ACLITEM_GET_GOPTIONS(*aidata
) & priv_bit
) != 0);
1849 tuple
= heap_form_tuple(funcctx
->tuple_desc
, values
, nulls
);
1850 result
= HeapTupleGetDatum(tuple
);
1852 SRF_RETURN_NEXT(funcctx
, result
);
1856 SRF_RETURN_DONE(funcctx
);
1861 * has_table_privilege variants
1862 * These are all named "has_table_privilege" at the SQL level.
1863 * They take various combinations of relation name, relation OID,
1864 * user name, user OID, or implicit user = current_user.
1866 * The result is a boolean value: true if user has the indicated
1867 * privilege, false if not. The variants that take a relation OID
1868 * return NULL if the OID doesn't exist (rather than failing, as
1869 * they did before Postgres 8.4).
1873 * has_table_privilege_name_name
1874 * Check user privileges on a table given
1875 * name username, text tablename, and text priv name.
1878 has_table_privilege_name_name(PG_FUNCTION_ARGS
)
1880 Name rolename
= PG_GETARG_NAME(0);
1881 text
*tablename
= PG_GETARG_TEXT_PP(1);
1882 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
1886 AclResult aclresult
;
1888 roleid
= get_role_oid_or_public(NameStr(*rolename
));
1889 tableoid
= convert_table_name(tablename
);
1890 mode
= convert_table_priv_string(priv_type_text
);
1892 aclresult
= pg_class_aclcheck(tableoid
, roleid
, mode
);
1894 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
1898 * has_table_privilege_name
1899 * Check user privileges on a table given
1900 * text tablename and text priv name.
1901 * current_user is assumed
1904 has_table_privilege_name(PG_FUNCTION_ARGS
)
1906 text
*tablename
= PG_GETARG_TEXT_PP(0);
1907 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
1911 AclResult aclresult
;
1913 roleid
= GetUserId();
1914 tableoid
= convert_table_name(tablename
);
1915 mode
= convert_table_priv_string(priv_type_text
);
1917 aclresult
= pg_class_aclcheck(tableoid
, roleid
, mode
);
1919 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
1923 * has_table_privilege_name_id
1924 * Check user privileges on a table given
1925 * name usename, table oid, and text priv name.
1928 has_table_privilege_name_id(PG_FUNCTION_ARGS
)
1930 Name username
= PG_GETARG_NAME(0);
1931 Oid tableoid
= PG_GETARG_OID(1);
1932 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
1935 AclResult aclresult
;
1936 bool is_missing
= false;
1938 roleid
= get_role_oid_or_public(NameStr(*username
));
1939 mode
= convert_table_priv_string(priv_type_text
);
1941 aclresult
= pg_class_aclcheck_ext(tableoid
, roleid
, mode
, &is_missing
);
1946 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
1950 * has_table_privilege_id
1951 * Check user privileges on a table given
1952 * table oid, and text priv name.
1953 * current_user is assumed
1956 has_table_privilege_id(PG_FUNCTION_ARGS
)
1958 Oid tableoid
= PG_GETARG_OID(0);
1959 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
1962 AclResult aclresult
;
1963 bool is_missing
= false;
1965 roleid
= GetUserId();
1966 mode
= convert_table_priv_string(priv_type_text
);
1968 aclresult
= pg_class_aclcheck_ext(tableoid
, roleid
, mode
, &is_missing
);
1973 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
1977 * has_table_privilege_id_name
1978 * Check user privileges on a table given
1979 * roleid, text tablename, and text priv name.
1982 has_table_privilege_id_name(PG_FUNCTION_ARGS
)
1984 Oid roleid
= PG_GETARG_OID(0);
1985 text
*tablename
= PG_GETARG_TEXT_PP(1);
1986 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
1989 AclResult aclresult
;
1991 tableoid
= convert_table_name(tablename
);
1992 mode
= convert_table_priv_string(priv_type_text
);
1994 aclresult
= pg_class_aclcheck(tableoid
, roleid
, mode
);
1996 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2000 * has_table_privilege_id_id
2001 * Check user privileges on a table given
2002 * roleid, table oid, and text priv name.
2005 has_table_privilege_id_id(PG_FUNCTION_ARGS
)
2007 Oid roleid
= PG_GETARG_OID(0);
2008 Oid tableoid
= PG_GETARG_OID(1);
2009 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2011 AclResult aclresult
;
2012 bool is_missing
= false;
2014 mode
= convert_table_priv_string(priv_type_text
);
2016 aclresult
= pg_class_aclcheck_ext(tableoid
, roleid
, mode
, &is_missing
);
2021 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2025 * Support routines for has_table_privilege family.
2029 * Given a table name expressed as a string, look it up and return Oid
2032 convert_table_name(text
*tablename
)
2036 relrv
= makeRangeVarFromNameList(textToQualifiedNameList(tablename
));
2038 /* We might not even have permissions on this relation; don't lock it. */
2039 return RangeVarGetRelid(relrv
, NoLock
, false);
2043 * convert_table_priv_string
2044 * Convert text string to AclMode value.
2047 convert_table_priv_string(text
*priv_type_text
)
2049 static const priv_map table_priv_map
[] = {
2050 {"SELECT", ACL_SELECT
},
2051 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT
)},
2052 {"INSERT", ACL_INSERT
},
2053 {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT
)},
2054 {"UPDATE", ACL_UPDATE
},
2055 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE
)},
2056 {"DELETE", ACL_DELETE
},
2057 {"DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE
)},
2058 {"TRUNCATE", ACL_TRUNCATE
},
2059 {"TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE
)},
2060 {"REFERENCES", ACL_REFERENCES
},
2061 {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES
)},
2062 {"TRIGGER", ACL_TRIGGER
},
2063 {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER
)},
2064 {"MAINTAIN", ACL_MAINTAIN
},
2065 {"MAINTAIN WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_MAINTAIN
)},
2069 return convert_any_priv_string(priv_type_text
, table_priv_map
);
2073 * has_sequence_privilege variants
2074 * These are all named "has_sequence_privilege" at the SQL level.
2075 * They take various combinations of relation name, relation OID,
2076 * user name, user OID, or implicit user = current_user.
2078 * The result is a boolean value: true if user has the indicated
2079 * privilege, false if not. The variants that take a relation OID
2080 * return NULL if the OID doesn't exist.
2084 * has_sequence_privilege_name_name
2085 * Check user privileges on a sequence given
2086 * name username, text sequencename, and text priv name.
2089 has_sequence_privilege_name_name(PG_FUNCTION_ARGS
)
2091 Name rolename
= PG_GETARG_NAME(0);
2092 text
*sequencename
= PG_GETARG_TEXT_PP(1);
2093 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2097 AclResult aclresult
;
2099 roleid
= get_role_oid_or_public(NameStr(*rolename
));
2100 mode
= convert_sequence_priv_string(priv_type_text
);
2101 sequenceoid
= convert_table_name(sequencename
);
2102 if (get_rel_relkind(sequenceoid
) != RELKIND_SEQUENCE
)
2104 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2105 errmsg("\"%s\" is not a sequence",
2106 text_to_cstring(sequencename
))));
2108 aclresult
= pg_class_aclcheck(sequenceoid
, roleid
, mode
);
2110 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2114 * has_sequence_privilege_name
2115 * Check user privileges on a sequence given
2116 * text sequencename and text priv name.
2117 * current_user is assumed
2120 has_sequence_privilege_name(PG_FUNCTION_ARGS
)
2122 text
*sequencename
= PG_GETARG_TEXT_PP(0);
2123 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
2127 AclResult aclresult
;
2129 roleid
= GetUserId();
2130 mode
= convert_sequence_priv_string(priv_type_text
);
2131 sequenceoid
= convert_table_name(sequencename
);
2132 if (get_rel_relkind(sequenceoid
) != RELKIND_SEQUENCE
)
2134 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2135 errmsg("\"%s\" is not a sequence",
2136 text_to_cstring(sequencename
))));
2138 aclresult
= pg_class_aclcheck(sequenceoid
, roleid
, mode
);
2140 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2144 * has_sequence_privilege_name_id
2145 * Check user privileges on a sequence given
2146 * name usename, sequence oid, and text priv name.
2149 has_sequence_privilege_name_id(PG_FUNCTION_ARGS
)
2151 Name username
= PG_GETARG_NAME(0);
2152 Oid sequenceoid
= PG_GETARG_OID(1);
2153 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2156 AclResult aclresult
;
2158 bool is_missing
= false;
2160 roleid
= get_role_oid_or_public(NameStr(*username
));
2161 mode
= convert_sequence_priv_string(priv_type_text
);
2162 relkind
= get_rel_relkind(sequenceoid
);
2163 if (relkind
== '\0')
2165 else if (relkind
!= RELKIND_SEQUENCE
)
2167 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2168 errmsg("\"%s\" is not a sequence",
2169 get_rel_name(sequenceoid
))));
2171 aclresult
= pg_class_aclcheck_ext(sequenceoid
, roleid
, mode
, &is_missing
);
2176 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2180 * has_sequence_privilege_id
2181 * Check user privileges on a sequence given
2182 * sequence oid, and text priv name.
2183 * current_user is assumed
2186 has_sequence_privilege_id(PG_FUNCTION_ARGS
)
2188 Oid sequenceoid
= PG_GETARG_OID(0);
2189 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
2192 AclResult aclresult
;
2194 bool is_missing
= false;
2196 roleid
= GetUserId();
2197 mode
= convert_sequence_priv_string(priv_type_text
);
2198 relkind
= get_rel_relkind(sequenceoid
);
2199 if (relkind
== '\0')
2201 else if (relkind
!= RELKIND_SEQUENCE
)
2203 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2204 errmsg("\"%s\" is not a sequence",
2205 get_rel_name(sequenceoid
))));
2207 aclresult
= pg_class_aclcheck_ext(sequenceoid
, roleid
, mode
, &is_missing
);
2212 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2216 * has_sequence_privilege_id_name
2217 * Check user privileges on a sequence given
2218 * roleid, text sequencename, and text priv name.
2221 has_sequence_privilege_id_name(PG_FUNCTION_ARGS
)
2223 Oid roleid
= PG_GETARG_OID(0);
2224 text
*sequencename
= PG_GETARG_TEXT_PP(1);
2225 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2228 AclResult aclresult
;
2230 mode
= convert_sequence_priv_string(priv_type_text
);
2231 sequenceoid
= convert_table_name(sequencename
);
2232 if (get_rel_relkind(sequenceoid
) != RELKIND_SEQUENCE
)
2234 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2235 errmsg("\"%s\" is not a sequence",
2236 text_to_cstring(sequencename
))));
2238 aclresult
= pg_class_aclcheck(sequenceoid
, roleid
, mode
);
2240 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2244 * has_sequence_privilege_id_id
2245 * Check user privileges on a sequence given
2246 * roleid, sequence oid, and text priv name.
2249 has_sequence_privilege_id_id(PG_FUNCTION_ARGS
)
2251 Oid roleid
= PG_GETARG_OID(0);
2252 Oid sequenceoid
= PG_GETARG_OID(1);
2253 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2255 AclResult aclresult
;
2257 bool is_missing
= false;
2259 mode
= convert_sequence_priv_string(priv_type_text
);
2260 relkind
= get_rel_relkind(sequenceoid
);
2261 if (relkind
== '\0')
2263 else if (relkind
!= RELKIND_SEQUENCE
)
2265 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2266 errmsg("\"%s\" is not a sequence",
2267 get_rel_name(sequenceoid
))));
2269 aclresult
= pg_class_aclcheck_ext(sequenceoid
, roleid
, mode
, &is_missing
);
2274 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2278 * convert_sequence_priv_string
2279 * Convert text string to AclMode value.
2282 convert_sequence_priv_string(text
*priv_type_text
)
2284 static const priv_map sequence_priv_map
[] = {
2285 {"USAGE", ACL_USAGE
},
2286 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE
)},
2287 {"SELECT", ACL_SELECT
},
2288 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT
)},
2289 {"UPDATE", ACL_UPDATE
},
2290 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE
)},
2294 return convert_any_priv_string(priv_type_text
, sequence_priv_map
);
2299 * has_any_column_privilege variants
2300 * These are all named "has_any_column_privilege" at the SQL level.
2301 * They take various combinations of relation name, relation OID,
2302 * user name, user OID, or implicit user = current_user.
2304 * The result is a boolean value: true if user has the indicated
2305 * privilege for any column of the table, false if not. The variants
2306 * that take a relation OID return NULL if the OID doesn't exist.
2310 * has_any_column_privilege_name_name
2311 * Check user privileges on any column of a table given
2312 * name username, text tablename, and text priv name.
2315 has_any_column_privilege_name_name(PG_FUNCTION_ARGS
)
2317 Name rolename
= PG_GETARG_NAME(0);
2318 text
*tablename
= PG_GETARG_TEXT_PP(1);
2319 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2323 AclResult aclresult
;
2325 roleid
= get_role_oid_or_public(NameStr(*rolename
));
2326 tableoid
= convert_table_name(tablename
);
2327 mode
= convert_column_priv_string(priv_type_text
);
2329 /* First check at table level, then examine each column if needed */
2330 aclresult
= pg_class_aclcheck(tableoid
, roleid
, mode
);
2331 if (aclresult
!= ACLCHECK_OK
)
2332 aclresult
= pg_attribute_aclcheck_all(tableoid
, roleid
, mode
,
2335 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2339 * has_any_column_privilege_name
2340 * Check user privileges on any column of a table given
2341 * text tablename and text priv name.
2342 * current_user is assumed
2345 has_any_column_privilege_name(PG_FUNCTION_ARGS
)
2347 text
*tablename
= PG_GETARG_TEXT_PP(0);
2348 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
2352 AclResult aclresult
;
2354 roleid
= GetUserId();
2355 tableoid
= convert_table_name(tablename
);
2356 mode
= convert_column_priv_string(priv_type_text
);
2358 /* First check at table level, then examine each column if needed */
2359 aclresult
= pg_class_aclcheck(tableoid
, roleid
, mode
);
2360 if (aclresult
!= ACLCHECK_OK
)
2361 aclresult
= pg_attribute_aclcheck_all(tableoid
, roleid
, mode
,
2364 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2368 * has_any_column_privilege_name_id
2369 * Check user privileges on any column of a table given
2370 * name usename, table oid, and text priv name.
2373 has_any_column_privilege_name_id(PG_FUNCTION_ARGS
)
2375 Name username
= PG_GETARG_NAME(0);
2376 Oid tableoid
= PG_GETARG_OID(1);
2377 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2380 AclResult aclresult
;
2381 bool is_missing
= false;
2383 roleid
= get_role_oid_or_public(NameStr(*username
));
2384 mode
= convert_column_priv_string(priv_type_text
);
2386 /* First check at table level, then examine each column if needed */
2387 aclresult
= pg_class_aclcheck_ext(tableoid
, roleid
, mode
, &is_missing
);
2388 if (aclresult
!= ACLCHECK_OK
)
2392 aclresult
= pg_attribute_aclcheck_all_ext(tableoid
, roleid
, mode
,
2393 ACLMASK_ANY
, &is_missing
);
2398 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2402 * has_any_column_privilege_id
2403 * Check user privileges on any column of a table given
2404 * table oid, and text priv name.
2405 * current_user is assumed
2408 has_any_column_privilege_id(PG_FUNCTION_ARGS
)
2410 Oid tableoid
= PG_GETARG_OID(0);
2411 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
2414 AclResult aclresult
;
2415 bool is_missing
= false;
2417 roleid
= GetUserId();
2418 mode
= convert_column_priv_string(priv_type_text
);
2420 /* First check at table level, then examine each column if needed */
2421 aclresult
= pg_class_aclcheck_ext(tableoid
, roleid
, mode
, &is_missing
);
2422 if (aclresult
!= ACLCHECK_OK
)
2426 aclresult
= pg_attribute_aclcheck_all_ext(tableoid
, roleid
, mode
,
2427 ACLMASK_ANY
, &is_missing
);
2432 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2436 * has_any_column_privilege_id_name
2437 * Check user privileges on any column of a table given
2438 * roleid, text tablename, and text priv name.
2441 has_any_column_privilege_id_name(PG_FUNCTION_ARGS
)
2443 Oid roleid
= PG_GETARG_OID(0);
2444 text
*tablename
= PG_GETARG_TEXT_PP(1);
2445 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2448 AclResult aclresult
;
2450 tableoid
= convert_table_name(tablename
);
2451 mode
= convert_column_priv_string(priv_type_text
);
2453 /* First check at table level, then examine each column if needed */
2454 aclresult
= pg_class_aclcheck(tableoid
, roleid
, mode
);
2455 if (aclresult
!= ACLCHECK_OK
)
2456 aclresult
= pg_attribute_aclcheck_all(tableoid
, roleid
, mode
,
2459 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2463 * has_any_column_privilege_id_id
2464 * Check user privileges on any column of a table given
2465 * roleid, table oid, and text priv name.
2468 has_any_column_privilege_id_id(PG_FUNCTION_ARGS
)
2470 Oid roleid
= PG_GETARG_OID(0);
2471 Oid tableoid
= PG_GETARG_OID(1);
2472 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2474 AclResult aclresult
;
2475 bool is_missing
= false;
2477 mode
= convert_column_priv_string(priv_type_text
);
2479 /* First check at table level, then examine each column if needed */
2480 aclresult
= pg_class_aclcheck_ext(tableoid
, roleid
, mode
, &is_missing
);
2481 if (aclresult
!= ACLCHECK_OK
)
2485 aclresult
= pg_attribute_aclcheck_all_ext(tableoid
, roleid
, mode
,
2486 ACLMASK_ANY
, &is_missing
);
2491 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2496 * has_column_privilege variants
2497 * These are all named "has_column_privilege" at the SQL level.
2498 * They take various combinations of relation name, relation OID,
2499 * column name, column attnum, user name, user OID, or
2500 * implicit user = current_user.
2502 * The result is a boolean value: true if user has the indicated
2503 * privilege, false if not. The variants that take a relation OID
2504 * return NULL (rather than throwing an error) if that relation OID
2505 * doesn't exist. Likewise, the variants that take an integer attnum
2506 * return NULL (rather than throwing an error) if there is no such
2507 * pg_attribute entry. All variants return NULL if an attisdropped
2508 * column is selected. These rules are meant to avoid unnecessary
2509 * failures in queries that scan pg_attribute.
2513 * column_privilege_check: check column privileges, but don't throw an error
2514 * for dropped column or table
2516 * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
2519 column_privilege_check(Oid tableoid
, AttrNumber attnum
,
2520 Oid roleid
, AclMode mode
)
2522 AclResult aclresult
;
2523 bool is_missing
= false;
2526 * If convert_column_name failed, we can just return -1 immediately.
2528 if (attnum
== InvalidAttrNumber
)
2532 * Check for column-level privileges first. This serves in part as a check
2533 * on whether the column even exists, so we need to do it before checking
2534 * table-level privilege.
2536 aclresult
= pg_attribute_aclcheck_ext(tableoid
, attnum
, roleid
,
2538 if (aclresult
== ACLCHECK_OK
)
2540 else if (is_missing
)
2543 /* Next check if we have the privilege at the table level */
2544 aclresult
= pg_class_aclcheck_ext(tableoid
, roleid
, mode
, &is_missing
);
2545 if (aclresult
== ACLCHECK_OK
)
2547 else if (is_missing
)
2554 * has_column_privilege_name_name_name
2555 * Check user privileges on a column given
2556 * name username, text tablename, text colname, and text priv name.
2559 has_column_privilege_name_name_name(PG_FUNCTION_ARGS
)
2561 Name rolename
= PG_GETARG_NAME(0);
2562 text
*tablename
= PG_GETARG_TEXT_PP(1);
2563 text
*column
= PG_GETARG_TEXT_PP(2);
2564 text
*priv_type_text
= PG_GETARG_TEXT_PP(3);
2567 AttrNumber colattnum
;
2571 roleid
= get_role_oid_or_public(NameStr(*rolename
));
2572 tableoid
= convert_table_name(tablename
);
2573 colattnum
= convert_column_name(tableoid
, column
);
2574 mode
= convert_column_priv_string(priv_type_text
);
2576 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2579 PG_RETURN_BOOL(privresult
);
2583 * has_column_privilege_name_name_attnum
2584 * Check user privileges on a column given
2585 * name username, text tablename, int attnum, and text priv name.
2588 has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS
)
2590 Name rolename
= PG_GETARG_NAME(0);
2591 text
*tablename
= PG_GETARG_TEXT_PP(1);
2592 AttrNumber colattnum
= PG_GETARG_INT16(2);
2593 text
*priv_type_text
= PG_GETARG_TEXT_PP(3);
2599 roleid
= get_role_oid_or_public(NameStr(*rolename
));
2600 tableoid
= convert_table_name(tablename
);
2601 mode
= convert_column_priv_string(priv_type_text
);
2603 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2606 PG_RETURN_BOOL(privresult
);
2610 * has_column_privilege_name_id_name
2611 * Check user privileges on a column given
2612 * name username, table oid, text colname, and text priv name.
2615 has_column_privilege_name_id_name(PG_FUNCTION_ARGS
)
2617 Name username
= PG_GETARG_NAME(0);
2618 Oid tableoid
= PG_GETARG_OID(1);
2619 text
*column
= PG_GETARG_TEXT_PP(2);
2620 text
*priv_type_text
= PG_GETARG_TEXT_PP(3);
2622 AttrNumber colattnum
;
2626 roleid
= get_role_oid_or_public(NameStr(*username
));
2627 colattnum
= convert_column_name(tableoid
, column
);
2628 mode
= convert_column_priv_string(priv_type_text
);
2630 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2633 PG_RETURN_BOOL(privresult
);
2637 * has_column_privilege_name_id_attnum
2638 * Check user privileges on a column given
2639 * name username, table oid, int attnum, and text priv name.
2642 has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS
)
2644 Name username
= PG_GETARG_NAME(0);
2645 Oid tableoid
= PG_GETARG_OID(1);
2646 AttrNumber colattnum
= PG_GETARG_INT16(2);
2647 text
*priv_type_text
= PG_GETARG_TEXT_PP(3);
2652 roleid
= get_role_oid_or_public(NameStr(*username
));
2653 mode
= convert_column_priv_string(priv_type_text
);
2655 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2658 PG_RETURN_BOOL(privresult
);
2662 * has_column_privilege_id_name_name
2663 * Check user privileges on a column given
2664 * oid roleid, text tablename, text colname, and text priv name.
2667 has_column_privilege_id_name_name(PG_FUNCTION_ARGS
)
2669 Oid roleid
= PG_GETARG_OID(0);
2670 text
*tablename
= PG_GETARG_TEXT_PP(1);
2671 text
*column
= PG_GETARG_TEXT_PP(2);
2672 text
*priv_type_text
= PG_GETARG_TEXT_PP(3);
2674 AttrNumber colattnum
;
2678 tableoid
= convert_table_name(tablename
);
2679 colattnum
= convert_column_name(tableoid
, column
);
2680 mode
= convert_column_priv_string(priv_type_text
);
2682 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2685 PG_RETURN_BOOL(privresult
);
2689 * has_column_privilege_id_name_attnum
2690 * Check user privileges on a column given
2691 * oid roleid, text tablename, int attnum, and text priv name.
2694 has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS
)
2696 Oid roleid
= PG_GETARG_OID(0);
2697 text
*tablename
= PG_GETARG_TEXT_PP(1);
2698 AttrNumber colattnum
= PG_GETARG_INT16(2);
2699 text
*priv_type_text
= PG_GETARG_TEXT_PP(3);
2704 tableoid
= convert_table_name(tablename
);
2705 mode
= convert_column_priv_string(priv_type_text
);
2707 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2710 PG_RETURN_BOOL(privresult
);
2714 * has_column_privilege_id_id_name
2715 * Check user privileges on a column given
2716 * oid roleid, table oid, text colname, and text priv name.
2719 has_column_privilege_id_id_name(PG_FUNCTION_ARGS
)
2721 Oid roleid
= PG_GETARG_OID(0);
2722 Oid tableoid
= PG_GETARG_OID(1);
2723 text
*column
= PG_GETARG_TEXT_PP(2);
2724 text
*priv_type_text
= PG_GETARG_TEXT_PP(3);
2725 AttrNumber colattnum
;
2729 colattnum
= convert_column_name(tableoid
, column
);
2730 mode
= convert_column_priv_string(priv_type_text
);
2732 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2735 PG_RETURN_BOOL(privresult
);
2739 * has_column_privilege_id_id_attnum
2740 * Check user privileges on a column given
2741 * oid roleid, table oid, int attnum, and text priv name.
2744 has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS
)
2746 Oid roleid
= PG_GETARG_OID(0);
2747 Oid tableoid
= PG_GETARG_OID(1);
2748 AttrNumber colattnum
= PG_GETARG_INT16(2);
2749 text
*priv_type_text
= PG_GETARG_TEXT_PP(3);
2753 mode
= convert_column_priv_string(priv_type_text
);
2755 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2758 PG_RETURN_BOOL(privresult
);
2762 * has_column_privilege_name_name
2763 * Check user privileges on a column given
2764 * text tablename, text colname, and text priv name.
2765 * current_user is assumed
2768 has_column_privilege_name_name(PG_FUNCTION_ARGS
)
2770 text
*tablename
= PG_GETARG_TEXT_PP(0);
2771 text
*column
= PG_GETARG_TEXT_PP(1);
2772 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2775 AttrNumber colattnum
;
2779 roleid
= GetUserId();
2780 tableoid
= convert_table_name(tablename
);
2781 colattnum
= convert_column_name(tableoid
, column
);
2782 mode
= convert_column_priv_string(priv_type_text
);
2784 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2787 PG_RETURN_BOOL(privresult
);
2791 * has_column_privilege_name_attnum
2792 * Check user privileges on a column given
2793 * text tablename, int attnum, and text priv name.
2794 * current_user is assumed
2797 has_column_privilege_name_attnum(PG_FUNCTION_ARGS
)
2799 text
*tablename
= PG_GETARG_TEXT_PP(0);
2800 AttrNumber colattnum
= PG_GETARG_INT16(1);
2801 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2807 roleid
= GetUserId();
2808 tableoid
= convert_table_name(tablename
);
2809 mode
= convert_column_priv_string(priv_type_text
);
2811 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2814 PG_RETURN_BOOL(privresult
);
2818 * has_column_privilege_id_name
2819 * Check user privileges on a column given
2820 * table oid, text colname, and text priv name.
2821 * current_user is assumed
2824 has_column_privilege_id_name(PG_FUNCTION_ARGS
)
2826 Oid tableoid
= PG_GETARG_OID(0);
2827 text
*column
= PG_GETARG_TEXT_PP(1);
2828 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2830 AttrNumber colattnum
;
2834 roleid
= GetUserId();
2835 colattnum
= convert_column_name(tableoid
, column
);
2836 mode
= convert_column_priv_string(priv_type_text
);
2838 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2841 PG_RETURN_BOOL(privresult
);
2845 * has_column_privilege_id_attnum
2846 * Check user privileges on a column given
2847 * table oid, int attnum, and text priv name.
2848 * current_user is assumed
2851 has_column_privilege_id_attnum(PG_FUNCTION_ARGS
)
2853 Oid tableoid
= PG_GETARG_OID(0);
2854 AttrNumber colattnum
= PG_GETARG_INT16(1);
2855 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2860 roleid
= GetUserId();
2861 mode
= convert_column_priv_string(priv_type_text
);
2863 privresult
= column_privilege_check(tableoid
, colattnum
, roleid
, mode
);
2866 PG_RETURN_BOOL(privresult
);
2870 * Support routines for has_column_privilege family.
2874 * Given a table OID and a column name expressed as a string, look it up
2875 * and return the column number. Returns InvalidAttrNumber in cases
2876 * where caller should return NULL instead of failing.
2879 convert_column_name(Oid tableoid
, text
*column
)
2885 colname
= text_to_cstring(column
);
2888 * We don't use get_attnum() here because it will report that dropped
2889 * columns don't exist. We need to treat dropped columns differently from
2890 * nonexistent columns.
2892 attTuple
= SearchSysCache2(ATTNAME
,
2893 ObjectIdGetDatum(tableoid
),
2894 CStringGetDatum(colname
));
2895 if (HeapTupleIsValid(attTuple
))
2897 Form_pg_attribute attributeForm
;
2899 attributeForm
= (Form_pg_attribute
) GETSTRUCT(attTuple
);
2900 /* We want to return NULL for dropped columns */
2901 if (attributeForm
->attisdropped
)
2902 attnum
= InvalidAttrNumber
;
2904 attnum
= attributeForm
->attnum
;
2905 ReleaseSysCache(attTuple
);
2909 char *tablename
= get_rel_name(tableoid
);
2912 * If the table OID is bogus, or it's just been dropped, we'll get
2913 * NULL back. In such cases we want has_column_privilege to return
2914 * NULL too, so just return InvalidAttrNumber.
2916 if (tablename
!= NULL
)
2918 /* tableoid exists, colname does not, so throw error */
2920 (errcode(ERRCODE_UNDEFINED_COLUMN
),
2921 errmsg("column \"%s\" of relation \"%s\" does not exist",
2922 colname
, tablename
)));
2924 /* tableoid doesn't exist, so act like attisdropped case */
2925 attnum
= InvalidAttrNumber
;
2933 * convert_column_priv_string
2934 * Convert text string to AclMode value.
2937 convert_column_priv_string(text
*priv_type_text
)
2939 static const priv_map column_priv_map
[] = {
2940 {"SELECT", ACL_SELECT
},
2941 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT
)},
2942 {"INSERT", ACL_INSERT
},
2943 {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT
)},
2944 {"UPDATE", ACL_UPDATE
},
2945 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE
)},
2946 {"REFERENCES", ACL_REFERENCES
},
2947 {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES
)},
2951 return convert_any_priv_string(priv_type_text
, column_priv_map
);
2956 * has_database_privilege variants
2957 * These are all named "has_database_privilege" at the SQL level.
2958 * They take various combinations of database name, database OID,
2959 * user name, user OID, or implicit user = current_user.
2961 * The result is a boolean value: true if user has the indicated
2962 * privilege, false if not, or NULL if object doesn't exist.
2966 * has_database_privilege_name_name
2967 * Check user privileges on a database given
2968 * name username, text databasename, and text priv name.
2971 has_database_privilege_name_name(PG_FUNCTION_ARGS
)
2973 Name username
= PG_GETARG_NAME(0);
2974 text
*databasename
= PG_GETARG_TEXT_PP(1);
2975 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
2979 AclResult aclresult
;
2981 roleid
= get_role_oid_or_public(NameStr(*username
));
2982 databaseoid
= convert_database_name(databasename
);
2983 mode
= convert_database_priv_string(priv_type_text
);
2985 aclresult
= object_aclcheck(DatabaseRelationId
, databaseoid
, roleid
, mode
);
2987 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
2991 * has_database_privilege_name
2992 * Check user privileges on a database given
2993 * text databasename and text priv name.
2994 * current_user is assumed
2997 has_database_privilege_name(PG_FUNCTION_ARGS
)
2999 text
*databasename
= PG_GETARG_TEXT_PP(0);
3000 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3004 AclResult aclresult
;
3006 roleid
= GetUserId();
3007 databaseoid
= convert_database_name(databasename
);
3008 mode
= convert_database_priv_string(priv_type_text
);
3010 aclresult
= object_aclcheck(DatabaseRelationId
, databaseoid
, roleid
, mode
);
3012 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3016 * has_database_privilege_name_id
3017 * Check user privileges on a database given
3018 * name usename, database oid, and text priv name.
3021 has_database_privilege_name_id(PG_FUNCTION_ARGS
)
3023 Name username
= PG_GETARG_NAME(0);
3024 Oid databaseoid
= PG_GETARG_OID(1);
3025 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3028 AclResult aclresult
;
3029 bool is_missing
= false;
3031 roleid
= get_role_oid_or_public(NameStr(*username
));
3032 mode
= convert_database_priv_string(priv_type_text
);
3034 aclresult
= object_aclcheck_ext(DatabaseRelationId
, databaseoid
,
3041 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3045 * has_database_privilege_id
3046 * Check user privileges on a database given
3047 * database oid, and text priv name.
3048 * current_user is assumed
3051 has_database_privilege_id(PG_FUNCTION_ARGS
)
3053 Oid databaseoid
= PG_GETARG_OID(0);
3054 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3057 AclResult aclresult
;
3058 bool is_missing
= false;
3060 roleid
= GetUserId();
3061 mode
= convert_database_priv_string(priv_type_text
);
3063 aclresult
= object_aclcheck_ext(DatabaseRelationId
, databaseoid
,
3070 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3074 * has_database_privilege_id_name
3075 * Check user privileges on a database given
3076 * roleid, text databasename, and text priv name.
3079 has_database_privilege_id_name(PG_FUNCTION_ARGS
)
3081 Oid roleid
= PG_GETARG_OID(0);
3082 text
*databasename
= PG_GETARG_TEXT_PP(1);
3083 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3086 AclResult aclresult
;
3088 databaseoid
= convert_database_name(databasename
);
3089 mode
= convert_database_priv_string(priv_type_text
);
3091 aclresult
= object_aclcheck(DatabaseRelationId
, databaseoid
, roleid
, mode
);
3093 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3097 * has_database_privilege_id_id
3098 * Check user privileges on a database given
3099 * roleid, database oid, and text priv name.
3102 has_database_privilege_id_id(PG_FUNCTION_ARGS
)
3104 Oid roleid
= PG_GETARG_OID(0);
3105 Oid databaseoid
= PG_GETARG_OID(1);
3106 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3108 AclResult aclresult
;
3109 bool is_missing
= false;
3111 mode
= convert_database_priv_string(priv_type_text
);
3113 aclresult
= object_aclcheck_ext(DatabaseRelationId
, databaseoid
,
3120 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3124 * Support routines for has_database_privilege family.
3128 * Given a database name expressed as a string, look it up and return Oid
3131 convert_database_name(text
*databasename
)
3133 char *dbname
= text_to_cstring(databasename
);
3135 return get_database_oid(dbname
, false);
3139 * convert_database_priv_string
3140 * Convert text string to AclMode value.
3143 convert_database_priv_string(text
*priv_type_text
)
3145 static const priv_map database_priv_map
[] = {
3146 {"CREATE", ACL_CREATE
},
3147 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
3148 {"TEMPORARY", ACL_CREATE_TEMP
},
3149 {"TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP
)},
3150 {"TEMP", ACL_CREATE_TEMP
},
3151 {"TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP
)},
3152 {"CONNECT", ACL_CONNECT
},
3153 {"CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT
)},
3157 return convert_any_priv_string(priv_type_text
, database_priv_map
);
3162 * has_foreign_data_wrapper_privilege variants
3163 * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
3164 * They take various combinations of foreign-data wrapper name,
3165 * fdw OID, user name, user OID, or implicit user = current_user.
3167 * The result is a boolean value: true if user has the indicated
3168 * privilege, false if not.
3172 * has_foreign_data_wrapper_privilege_name_name
3173 * Check user privileges on a foreign-data wrapper given
3174 * name username, text fdwname, and text priv name.
3177 has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS
)
3179 Name username
= PG_GETARG_NAME(0);
3180 text
*fdwname
= PG_GETARG_TEXT_PP(1);
3181 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3185 AclResult aclresult
;
3187 roleid
= get_role_oid_or_public(NameStr(*username
));
3188 fdwid
= convert_foreign_data_wrapper_name(fdwname
);
3189 mode
= convert_foreign_data_wrapper_priv_string(priv_type_text
);
3191 aclresult
= object_aclcheck(ForeignDataWrapperRelationId
, fdwid
, roleid
, mode
);
3193 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3197 * has_foreign_data_wrapper_privilege_name
3198 * Check user privileges on a foreign-data wrapper given
3199 * text fdwname and text priv name.
3200 * current_user is assumed
3203 has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS
)
3205 text
*fdwname
= PG_GETARG_TEXT_PP(0);
3206 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3210 AclResult aclresult
;
3212 roleid
= GetUserId();
3213 fdwid
= convert_foreign_data_wrapper_name(fdwname
);
3214 mode
= convert_foreign_data_wrapper_priv_string(priv_type_text
);
3216 aclresult
= object_aclcheck(ForeignDataWrapperRelationId
, fdwid
, roleid
, mode
);
3218 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3222 * has_foreign_data_wrapper_privilege_name_id
3223 * Check user privileges on a foreign-data wrapper given
3224 * name usename, foreign-data wrapper oid, and text priv name.
3227 has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS
)
3229 Name username
= PG_GETARG_NAME(0);
3230 Oid fdwid
= PG_GETARG_OID(1);
3231 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3234 AclResult aclresult
;
3235 bool is_missing
= false;
3237 roleid
= get_role_oid_or_public(NameStr(*username
));
3238 mode
= convert_foreign_data_wrapper_priv_string(priv_type_text
);
3240 aclresult
= object_aclcheck_ext(ForeignDataWrapperRelationId
, fdwid
,
3247 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3251 * has_foreign_data_wrapper_privilege_id
3252 * Check user privileges on a foreign-data wrapper given
3253 * foreign-data wrapper oid, and text priv name.
3254 * current_user is assumed
3257 has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS
)
3259 Oid fdwid
= PG_GETARG_OID(0);
3260 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3263 AclResult aclresult
;
3264 bool is_missing
= false;
3266 roleid
= GetUserId();
3267 mode
= convert_foreign_data_wrapper_priv_string(priv_type_text
);
3269 aclresult
= object_aclcheck_ext(ForeignDataWrapperRelationId
, fdwid
,
3276 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3280 * has_foreign_data_wrapper_privilege_id_name
3281 * Check user privileges on a foreign-data wrapper given
3282 * roleid, text fdwname, and text priv name.
3285 has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS
)
3287 Oid roleid
= PG_GETARG_OID(0);
3288 text
*fdwname
= PG_GETARG_TEXT_PP(1);
3289 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3292 AclResult aclresult
;
3294 fdwid
= convert_foreign_data_wrapper_name(fdwname
);
3295 mode
= convert_foreign_data_wrapper_priv_string(priv_type_text
);
3297 aclresult
= object_aclcheck(ForeignDataWrapperRelationId
, fdwid
, roleid
, mode
);
3299 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3303 * has_foreign_data_wrapper_privilege_id_id
3304 * Check user privileges on a foreign-data wrapper given
3305 * roleid, fdw oid, and text priv name.
3308 has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS
)
3310 Oid roleid
= PG_GETARG_OID(0);
3311 Oid fdwid
= PG_GETARG_OID(1);
3312 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3314 AclResult aclresult
;
3315 bool is_missing
= false;
3317 mode
= convert_foreign_data_wrapper_priv_string(priv_type_text
);
3319 aclresult
= object_aclcheck_ext(ForeignDataWrapperRelationId
, fdwid
,
3326 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3330 * Support routines for has_foreign_data_wrapper_privilege family.
3334 * Given a FDW name expressed as a string, look it up and return Oid
3337 convert_foreign_data_wrapper_name(text
*fdwname
)
3339 char *fdwstr
= text_to_cstring(fdwname
);
3341 return get_foreign_data_wrapper_oid(fdwstr
, false);
3345 * convert_foreign_data_wrapper_priv_string
3346 * Convert text string to AclMode value.
3349 convert_foreign_data_wrapper_priv_string(text
*priv_type_text
)
3351 static const priv_map foreign_data_wrapper_priv_map
[] = {
3352 {"USAGE", ACL_USAGE
},
3353 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE
)},
3357 return convert_any_priv_string(priv_type_text
, foreign_data_wrapper_priv_map
);
3362 * has_function_privilege variants
3363 * These are all named "has_function_privilege" at the SQL level.
3364 * They take various combinations of function name, function OID,
3365 * user name, user OID, or implicit user = current_user.
3367 * The result is a boolean value: true if user has the indicated
3368 * privilege, false if not, or NULL if object doesn't exist.
3372 * has_function_privilege_name_name
3373 * Check user privileges on a function given
3374 * name username, text functionname, and text priv name.
3377 has_function_privilege_name_name(PG_FUNCTION_ARGS
)
3379 Name username
= PG_GETARG_NAME(0);
3380 text
*functionname
= PG_GETARG_TEXT_PP(1);
3381 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3385 AclResult aclresult
;
3387 roleid
= get_role_oid_or_public(NameStr(*username
));
3388 functionoid
= convert_function_name(functionname
);
3389 mode
= convert_function_priv_string(priv_type_text
);
3391 aclresult
= object_aclcheck(ProcedureRelationId
, functionoid
, roleid
, mode
);
3393 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3397 * has_function_privilege_name
3398 * Check user privileges on a function given
3399 * text functionname and text priv name.
3400 * current_user is assumed
3403 has_function_privilege_name(PG_FUNCTION_ARGS
)
3405 text
*functionname
= PG_GETARG_TEXT_PP(0);
3406 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3410 AclResult aclresult
;
3412 roleid
= GetUserId();
3413 functionoid
= convert_function_name(functionname
);
3414 mode
= convert_function_priv_string(priv_type_text
);
3416 aclresult
= object_aclcheck(ProcedureRelationId
, functionoid
, roleid
, mode
);
3418 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3422 * has_function_privilege_name_id
3423 * Check user privileges on a function given
3424 * name usename, function oid, and text priv name.
3427 has_function_privilege_name_id(PG_FUNCTION_ARGS
)
3429 Name username
= PG_GETARG_NAME(0);
3430 Oid functionoid
= PG_GETARG_OID(1);
3431 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3434 AclResult aclresult
;
3435 bool is_missing
= false;
3437 roleid
= get_role_oid_or_public(NameStr(*username
));
3438 mode
= convert_function_priv_string(priv_type_text
);
3440 aclresult
= object_aclcheck_ext(ProcedureRelationId
, functionoid
,
3447 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3451 * has_function_privilege_id
3452 * Check user privileges on a function given
3453 * function oid, and text priv name.
3454 * current_user is assumed
3457 has_function_privilege_id(PG_FUNCTION_ARGS
)
3459 Oid functionoid
= PG_GETARG_OID(0);
3460 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3463 AclResult aclresult
;
3464 bool is_missing
= false;
3466 roleid
= GetUserId();
3467 mode
= convert_function_priv_string(priv_type_text
);
3469 aclresult
= object_aclcheck_ext(ProcedureRelationId
, functionoid
,
3476 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3480 * has_function_privilege_id_name
3481 * Check user privileges on a function given
3482 * roleid, text functionname, and text priv name.
3485 has_function_privilege_id_name(PG_FUNCTION_ARGS
)
3487 Oid roleid
= PG_GETARG_OID(0);
3488 text
*functionname
= PG_GETARG_TEXT_PP(1);
3489 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3492 AclResult aclresult
;
3494 functionoid
= convert_function_name(functionname
);
3495 mode
= convert_function_priv_string(priv_type_text
);
3497 aclresult
= object_aclcheck(ProcedureRelationId
, functionoid
, roleid
, mode
);
3499 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3503 * has_function_privilege_id_id
3504 * Check user privileges on a function given
3505 * roleid, function oid, and text priv name.
3508 has_function_privilege_id_id(PG_FUNCTION_ARGS
)
3510 Oid roleid
= PG_GETARG_OID(0);
3511 Oid functionoid
= PG_GETARG_OID(1);
3512 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3514 AclResult aclresult
;
3515 bool is_missing
= false;
3517 mode
= convert_function_priv_string(priv_type_text
);
3519 aclresult
= object_aclcheck_ext(ProcedureRelationId
, functionoid
,
3526 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3530 * Support routines for has_function_privilege family.
3534 * Given a function name expressed as a string, look it up and return Oid
3537 convert_function_name(text
*functionname
)
3539 char *funcname
= text_to_cstring(functionname
);
3542 oid
= DatumGetObjectId(DirectFunctionCall1(regprocedurein
,
3543 CStringGetDatum(funcname
)));
3545 if (!OidIsValid(oid
))
3547 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
3548 errmsg("function \"%s\" does not exist", funcname
)));
3554 * convert_function_priv_string
3555 * Convert text string to AclMode value.
3558 convert_function_priv_string(text
*priv_type_text
)
3560 static const priv_map function_priv_map
[] = {
3561 {"EXECUTE", ACL_EXECUTE
},
3562 {"EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE
)},
3566 return convert_any_priv_string(priv_type_text
, function_priv_map
);
3571 * has_language_privilege variants
3572 * These are all named "has_language_privilege" at the SQL level.
3573 * They take various combinations of language name, language OID,
3574 * user name, user OID, or implicit user = current_user.
3576 * The result is a boolean value: true if user has the indicated
3577 * privilege, false if not, or NULL if object doesn't exist.
3581 * has_language_privilege_name_name
3582 * Check user privileges on a language given
3583 * name username, text languagename, and text priv name.
3586 has_language_privilege_name_name(PG_FUNCTION_ARGS
)
3588 Name username
= PG_GETARG_NAME(0);
3589 text
*languagename
= PG_GETARG_TEXT_PP(1);
3590 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3594 AclResult aclresult
;
3596 roleid
= get_role_oid_or_public(NameStr(*username
));
3597 languageoid
= convert_language_name(languagename
);
3598 mode
= convert_language_priv_string(priv_type_text
);
3600 aclresult
= object_aclcheck(LanguageRelationId
, languageoid
, roleid
, mode
);
3602 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3606 * has_language_privilege_name
3607 * Check user privileges on a language given
3608 * text languagename and text priv name.
3609 * current_user is assumed
3612 has_language_privilege_name(PG_FUNCTION_ARGS
)
3614 text
*languagename
= PG_GETARG_TEXT_PP(0);
3615 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3619 AclResult aclresult
;
3621 roleid
= GetUserId();
3622 languageoid
= convert_language_name(languagename
);
3623 mode
= convert_language_priv_string(priv_type_text
);
3625 aclresult
= object_aclcheck(LanguageRelationId
, languageoid
, roleid
, mode
);
3627 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3631 * has_language_privilege_name_id
3632 * Check user privileges on a language given
3633 * name usename, language oid, and text priv name.
3636 has_language_privilege_name_id(PG_FUNCTION_ARGS
)
3638 Name username
= PG_GETARG_NAME(0);
3639 Oid languageoid
= PG_GETARG_OID(1);
3640 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3643 AclResult aclresult
;
3644 bool is_missing
= false;
3646 roleid
= get_role_oid_or_public(NameStr(*username
));
3647 mode
= convert_language_priv_string(priv_type_text
);
3649 aclresult
= object_aclcheck_ext(LanguageRelationId
, languageoid
,
3656 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3660 * has_language_privilege_id
3661 * Check user privileges on a language given
3662 * language oid, and text priv name.
3663 * current_user is assumed
3666 has_language_privilege_id(PG_FUNCTION_ARGS
)
3668 Oid languageoid
= PG_GETARG_OID(0);
3669 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3672 AclResult aclresult
;
3673 bool is_missing
= false;
3675 roleid
= GetUserId();
3676 mode
= convert_language_priv_string(priv_type_text
);
3678 aclresult
= object_aclcheck_ext(LanguageRelationId
, languageoid
,
3685 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3689 * has_language_privilege_id_name
3690 * Check user privileges on a language given
3691 * roleid, text languagename, and text priv name.
3694 has_language_privilege_id_name(PG_FUNCTION_ARGS
)
3696 Oid roleid
= PG_GETARG_OID(0);
3697 text
*languagename
= PG_GETARG_TEXT_PP(1);
3698 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3701 AclResult aclresult
;
3703 languageoid
= convert_language_name(languagename
);
3704 mode
= convert_language_priv_string(priv_type_text
);
3706 aclresult
= object_aclcheck(LanguageRelationId
, languageoid
, roleid
, mode
);
3708 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3712 * has_language_privilege_id_id
3713 * Check user privileges on a language given
3714 * roleid, language oid, and text priv name.
3717 has_language_privilege_id_id(PG_FUNCTION_ARGS
)
3719 Oid roleid
= PG_GETARG_OID(0);
3720 Oid languageoid
= PG_GETARG_OID(1);
3721 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3723 AclResult aclresult
;
3724 bool is_missing
= false;
3726 mode
= convert_language_priv_string(priv_type_text
);
3728 aclresult
= object_aclcheck_ext(LanguageRelationId
, languageoid
,
3735 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3739 * Support routines for has_language_privilege family.
3743 * Given a language name expressed as a string, look it up and return Oid
3746 convert_language_name(text
*languagename
)
3748 char *langname
= text_to_cstring(languagename
);
3750 return get_language_oid(langname
, false);
3754 * convert_language_priv_string
3755 * Convert text string to AclMode value.
3758 convert_language_priv_string(text
*priv_type_text
)
3760 static const priv_map language_priv_map
[] = {
3761 {"USAGE", ACL_USAGE
},
3762 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE
)},
3766 return convert_any_priv_string(priv_type_text
, language_priv_map
);
3771 * has_schema_privilege variants
3772 * These are all named "has_schema_privilege" at the SQL level.
3773 * They take various combinations of schema name, schema OID,
3774 * user name, user OID, or implicit user = current_user.
3776 * The result is a boolean value: true if user has the indicated
3777 * privilege, false if not, or NULL if object doesn't exist.
3781 * has_schema_privilege_name_name
3782 * Check user privileges on a schema given
3783 * name username, text schemaname, and text priv name.
3786 has_schema_privilege_name_name(PG_FUNCTION_ARGS
)
3788 Name username
= PG_GETARG_NAME(0);
3789 text
*schemaname
= PG_GETARG_TEXT_PP(1);
3790 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3794 AclResult aclresult
;
3796 roleid
= get_role_oid_or_public(NameStr(*username
));
3797 schemaoid
= convert_schema_name(schemaname
);
3798 mode
= convert_schema_priv_string(priv_type_text
);
3800 aclresult
= object_aclcheck(NamespaceRelationId
, schemaoid
, roleid
, mode
);
3802 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3806 * has_schema_privilege_name
3807 * Check user privileges on a schema given
3808 * text schemaname and text priv name.
3809 * current_user is assumed
3812 has_schema_privilege_name(PG_FUNCTION_ARGS
)
3814 text
*schemaname
= PG_GETARG_TEXT_PP(0);
3815 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3819 AclResult aclresult
;
3821 roleid
= GetUserId();
3822 schemaoid
= convert_schema_name(schemaname
);
3823 mode
= convert_schema_priv_string(priv_type_text
);
3825 aclresult
= object_aclcheck(NamespaceRelationId
, schemaoid
, roleid
, mode
);
3827 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3831 * has_schema_privilege_name_id
3832 * Check user privileges on a schema given
3833 * name usename, schema oid, and text priv name.
3836 has_schema_privilege_name_id(PG_FUNCTION_ARGS
)
3838 Name username
= PG_GETARG_NAME(0);
3839 Oid schemaoid
= PG_GETARG_OID(1);
3840 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3843 AclResult aclresult
;
3844 bool is_missing
= false;
3846 roleid
= get_role_oid_or_public(NameStr(*username
));
3847 mode
= convert_schema_priv_string(priv_type_text
);
3849 aclresult
= object_aclcheck_ext(NamespaceRelationId
, schemaoid
,
3856 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3860 * has_schema_privilege_id
3861 * Check user privileges on a schema given
3862 * schema oid, and text priv name.
3863 * current_user is assumed
3866 has_schema_privilege_id(PG_FUNCTION_ARGS
)
3868 Oid schemaoid
= PG_GETARG_OID(0);
3869 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
3872 AclResult aclresult
;
3873 bool is_missing
= false;
3875 roleid
= GetUserId();
3876 mode
= convert_schema_priv_string(priv_type_text
);
3878 aclresult
= object_aclcheck_ext(NamespaceRelationId
, schemaoid
,
3885 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3889 * has_schema_privilege_id_name
3890 * Check user privileges on a schema given
3891 * roleid, text schemaname, and text priv name.
3894 has_schema_privilege_id_name(PG_FUNCTION_ARGS
)
3896 Oid roleid
= PG_GETARG_OID(0);
3897 text
*schemaname
= PG_GETARG_TEXT_PP(1);
3898 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3901 AclResult aclresult
;
3903 schemaoid
= convert_schema_name(schemaname
);
3904 mode
= convert_schema_priv_string(priv_type_text
);
3906 aclresult
= object_aclcheck(NamespaceRelationId
, schemaoid
, roleid
, mode
);
3908 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3912 * has_schema_privilege_id_id
3913 * Check user privileges on a schema given
3914 * roleid, schema oid, and text priv name.
3917 has_schema_privilege_id_id(PG_FUNCTION_ARGS
)
3919 Oid roleid
= PG_GETARG_OID(0);
3920 Oid schemaoid
= PG_GETARG_OID(1);
3921 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3923 AclResult aclresult
;
3924 bool is_missing
= false;
3926 mode
= convert_schema_priv_string(priv_type_text
);
3928 aclresult
= object_aclcheck_ext(NamespaceRelationId
, schemaoid
,
3935 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
3939 * Support routines for has_schema_privilege family.
3943 * Given a schema name expressed as a string, look it up and return Oid
3946 convert_schema_name(text
*schemaname
)
3948 char *nspname
= text_to_cstring(schemaname
);
3950 return get_namespace_oid(nspname
, false);
3954 * convert_schema_priv_string
3955 * Convert text string to AclMode value.
3958 convert_schema_priv_string(text
*priv_type_text
)
3960 static const priv_map schema_priv_map
[] = {
3961 {"CREATE", ACL_CREATE
},
3962 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
3963 {"USAGE", ACL_USAGE
},
3964 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE
)},
3968 return convert_any_priv_string(priv_type_text
, schema_priv_map
);
3973 * has_server_privilege variants
3974 * These are all named "has_server_privilege" at the SQL level.
3975 * They take various combinations of foreign server name,
3976 * server OID, user name, user OID, or implicit user = current_user.
3978 * The result is a boolean value: true if user has the indicated
3979 * privilege, false if not.
3983 * has_server_privilege_name_name
3984 * Check user privileges on a foreign server given
3985 * name username, text servername, and text priv name.
3988 has_server_privilege_name_name(PG_FUNCTION_ARGS
)
3990 Name username
= PG_GETARG_NAME(0);
3991 text
*servername
= PG_GETARG_TEXT_PP(1);
3992 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
3996 AclResult aclresult
;
3998 roleid
= get_role_oid_or_public(NameStr(*username
));
3999 serverid
= convert_server_name(servername
);
4000 mode
= convert_server_priv_string(priv_type_text
);
4002 aclresult
= object_aclcheck(ForeignServerRelationId
, serverid
, roleid
, mode
);
4004 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4008 * has_server_privilege_name
4009 * Check user privileges on a foreign server given
4010 * text servername and text priv name.
4011 * current_user is assumed
4014 has_server_privilege_name(PG_FUNCTION_ARGS
)
4016 text
*servername
= PG_GETARG_TEXT_PP(0);
4017 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4021 AclResult aclresult
;
4023 roleid
= GetUserId();
4024 serverid
= convert_server_name(servername
);
4025 mode
= convert_server_priv_string(priv_type_text
);
4027 aclresult
= object_aclcheck(ForeignServerRelationId
, serverid
, roleid
, mode
);
4029 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4033 * has_server_privilege_name_id
4034 * Check user privileges on a foreign server given
4035 * name usename, foreign server oid, and text priv name.
4038 has_server_privilege_name_id(PG_FUNCTION_ARGS
)
4040 Name username
= PG_GETARG_NAME(0);
4041 Oid serverid
= PG_GETARG_OID(1);
4042 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4045 AclResult aclresult
;
4046 bool is_missing
= false;
4048 roleid
= get_role_oid_or_public(NameStr(*username
));
4049 mode
= convert_server_priv_string(priv_type_text
);
4051 aclresult
= object_aclcheck_ext(ForeignServerRelationId
, serverid
,
4058 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4062 * has_server_privilege_id
4063 * Check user privileges on a foreign server given
4064 * server oid, and text priv name.
4065 * current_user is assumed
4068 has_server_privilege_id(PG_FUNCTION_ARGS
)
4070 Oid serverid
= PG_GETARG_OID(0);
4071 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4074 AclResult aclresult
;
4075 bool is_missing
= false;
4077 roleid
= GetUserId();
4078 mode
= convert_server_priv_string(priv_type_text
);
4080 aclresult
= object_aclcheck_ext(ForeignServerRelationId
, serverid
,
4087 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4091 * has_server_privilege_id_name
4092 * Check user privileges on a foreign server given
4093 * roleid, text servername, and text priv name.
4096 has_server_privilege_id_name(PG_FUNCTION_ARGS
)
4098 Oid roleid
= PG_GETARG_OID(0);
4099 text
*servername
= PG_GETARG_TEXT_PP(1);
4100 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4103 AclResult aclresult
;
4105 serverid
= convert_server_name(servername
);
4106 mode
= convert_server_priv_string(priv_type_text
);
4108 aclresult
= object_aclcheck(ForeignServerRelationId
, serverid
, roleid
, mode
);
4110 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4114 * has_server_privilege_id_id
4115 * Check user privileges on a foreign server given
4116 * roleid, server oid, and text priv name.
4119 has_server_privilege_id_id(PG_FUNCTION_ARGS
)
4121 Oid roleid
= PG_GETARG_OID(0);
4122 Oid serverid
= PG_GETARG_OID(1);
4123 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4125 AclResult aclresult
;
4126 bool is_missing
= false;
4128 mode
= convert_server_priv_string(priv_type_text
);
4130 aclresult
= object_aclcheck_ext(ForeignServerRelationId
, serverid
,
4137 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4141 * Support routines for has_server_privilege family.
4145 * Given a server name expressed as a string, look it up and return Oid
4148 convert_server_name(text
*servername
)
4150 char *serverstr
= text_to_cstring(servername
);
4152 return get_foreign_server_oid(serverstr
, false);
4156 * convert_server_priv_string
4157 * Convert text string to AclMode value.
4160 convert_server_priv_string(text
*priv_type_text
)
4162 static const priv_map server_priv_map
[] = {
4163 {"USAGE", ACL_USAGE
},
4164 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE
)},
4168 return convert_any_priv_string(priv_type_text
, server_priv_map
);
4173 * has_tablespace_privilege variants
4174 * These are all named "has_tablespace_privilege" at the SQL level.
4175 * They take various combinations of tablespace name, tablespace OID,
4176 * user name, user OID, or implicit user = current_user.
4178 * The result is a boolean value: true if user has the indicated
4179 * privilege, false if not.
4183 * has_tablespace_privilege_name_name
4184 * Check user privileges on a tablespace given
4185 * name username, text tablespacename, and text priv name.
4188 has_tablespace_privilege_name_name(PG_FUNCTION_ARGS
)
4190 Name username
= PG_GETARG_NAME(0);
4191 text
*tablespacename
= PG_GETARG_TEXT_PP(1);
4192 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4196 AclResult aclresult
;
4198 roleid
= get_role_oid_or_public(NameStr(*username
));
4199 tablespaceoid
= convert_tablespace_name(tablespacename
);
4200 mode
= convert_tablespace_priv_string(priv_type_text
);
4202 aclresult
= object_aclcheck(TableSpaceRelationId
, tablespaceoid
, roleid
, mode
);
4204 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4208 * has_tablespace_privilege_name
4209 * Check user privileges on a tablespace given
4210 * text tablespacename and text priv name.
4211 * current_user is assumed
4214 has_tablespace_privilege_name(PG_FUNCTION_ARGS
)
4216 text
*tablespacename
= PG_GETARG_TEXT_PP(0);
4217 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4221 AclResult aclresult
;
4223 roleid
= GetUserId();
4224 tablespaceoid
= convert_tablespace_name(tablespacename
);
4225 mode
= convert_tablespace_priv_string(priv_type_text
);
4227 aclresult
= object_aclcheck(TableSpaceRelationId
, tablespaceoid
, roleid
, mode
);
4229 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4233 * has_tablespace_privilege_name_id
4234 * Check user privileges on a tablespace given
4235 * name usename, tablespace oid, and text priv name.
4238 has_tablespace_privilege_name_id(PG_FUNCTION_ARGS
)
4240 Name username
= PG_GETARG_NAME(0);
4241 Oid tablespaceoid
= PG_GETARG_OID(1);
4242 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4245 AclResult aclresult
;
4246 bool is_missing
= false;
4248 roleid
= get_role_oid_or_public(NameStr(*username
));
4249 mode
= convert_tablespace_priv_string(priv_type_text
);
4251 aclresult
= object_aclcheck_ext(TableSpaceRelationId
, tablespaceoid
,
4258 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4262 * has_tablespace_privilege_id
4263 * Check user privileges on a tablespace given
4264 * tablespace oid, and text priv name.
4265 * current_user is assumed
4268 has_tablespace_privilege_id(PG_FUNCTION_ARGS
)
4270 Oid tablespaceoid
= PG_GETARG_OID(0);
4271 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4274 AclResult aclresult
;
4275 bool is_missing
= false;
4277 roleid
= GetUserId();
4278 mode
= convert_tablespace_priv_string(priv_type_text
);
4280 aclresult
= object_aclcheck_ext(TableSpaceRelationId
, tablespaceoid
,
4287 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4291 * has_tablespace_privilege_id_name
4292 * Check user privileges on a tablespace given
4293 * roleid, text tablespacename, and text priv name.
4296 has_tablespace_privilege_id_name(PG_FUNCTION_ARGS
)
4298 Oid roleid
= PG_GETARG_OID(0);
4299 text
*tablespacename
= PG_GETARG_TEXT_PP(1);
4300 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4303 AclResult aclresult
;
4305 tablespaceoid
= convert_tablespace_name(tablespacename
);
4306 mode
= convert_tablespace_priv_string(priv_type_text
);
4308 aclresult
= object_aclcheck(TableSpaceRelationId
, tablespaceoid
, roleid
, mode
);
4310 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4314 * has_tablespace_privilege_id_id
4315 * Check user privileges on a tablespace given
4316 * roleid, tablespace oid, and text priv name.
4319 has_tablespace_privilege_id_id(PG_FUNCTION_ARGS
)
4321 Oid roleid
= PG_GETARG_OID(0);
4322 Oid tablespaceoid
= PG_GETARG_OID(1);
4323 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4325 AclResult aclresult
;
4326 bool is_missing
= false;
4328 mode
= convert_tablespace_priv_string(priv_type_text
);
4330 aclresult
= object_aclcheck_ext(TableSpaceRelationId
, tablespaceoid
,
4337 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4341 * Support routines for has_tablespace_privilege family.
4345 * Given a tablespace name expressed as a string, look it up and return Oid
4348 convert_tablespace_name(text
*tablespacename
)
4350 char *spcname
= text_to_cstring(tablespacename
);
4352 return get_tablespace_oid(spcname
, false);
4356 * convert_tablespace_priv_string
4357 * Convert text string to AclMode value.
4360 convert_tablespace_priv_string(text
*priv_type_text
)
4362 static const priv_map tablespace_priv_map
[] = {
4363 {"CREATE", ACL_CREATE
},
4364 {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
4368 return convert_any_priv_string(priv_type_text
, tablespace_priv_map
);
4372 * has_type_privilege variants
4373 * These are all named "has_type_privilege" at the SQL level.
4374 * They take various combinations of type name, type OID,
4375 * user name, user OID, or implicit user = current_user.
4377 * The result is a boolean value: true if user has the indicated
4378 * privilege, false if not, or NULL if object doesn't exist.
4382 * has_type_privilege_name_name
4383 * Check user privileges on a type given
4384 * name username, text typename, and text priv name.
4387 has_type_privilege_name_name(PG_FUNCTION_ARGS
)
4389 Name username
= PG_GETARG_NAME(0);
4390 text
*typename
= PG_GETARG_TEXT_PP(1);
4391 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4395 AclResult aclresult
;
4397 roleid
= get_role_oid_or_public(NameStr(*username
));
4398 typeoid
= convert_type_name(typename
);
4399 mode
= convert_type_priv_string(priv_type_text
);
4401 aclresult
= object_aclcheck(TypeRelationId
, typeoid
, roleid
, mode
);
4403 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4407 * has_type_privilege_name
4408 * Check user privileges on a type given
4409 * text typename and text priv name.
4410 * current_user is assumed
4413 has_type_privilege_name(PG_FUNCTION_ARGS
)
4415 text
*typename
= PG_GETARG_TEXT_PP(0);
4416 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4420 AclResult aclresult
;
4422 roleid
= GetUserId();
4423 typeoid
= convert_type_name(typename
);
4424 mode
= convert_type_priv_string(priv_type_text
);
4426 aclresult
= object_aclcheck(TypeRelationId
, typeoid
, roleid
, mode
);
4428 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4432 * has_type_privilege_name_id
4433 * Check user privileges on a type given
4434 * name usename, type oid, and text priv name.
4437 has_type_privilege_name_id(PG_FUNCTION_ARGS
)
4439 Name username
= PG_GETARG_NAME(0);
4440 Oid typeoid
= PG_GETARG_OID(1);
4441 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4444 AclResult aclresult
;
4445 bool is_missing
= false;
4447 roleid
= get_role_oid_or_public(NameStr(*username
));
4448 mode
= convert_type_priv_string(priv_type_text
);
4450 aclresult
= object_aclcheck_ext(TypeRelationId
, typeoid
,
4457 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4461 * has_type_privilege_id
4462 * Check user privileges on a type given
4463 * type oid, and text priv name.
4464 * current_user is assumed
4467 has_type_privilege_id(PG_FUNCTION_ARGS
)
4469 Oid typeoid
= PG_GETARG_OID(0);
4470 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4473 AclResult aclresult
;
4474 bool is_missing
= false;
4476 roleid
= GetUserId();
4477 mode
= convert_type_priv_string(priv_type_text
);
4479 aclresult
= object_aclcheck_ext(TypeRelationId
, typeoid
,
4486 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4490 * has_type_privilege_id_name
4491 * Check user privileges on a type given
4492 * roleid, text typename, and text priv name.
4495 has_type_privilege_id_name(PG_FUNCTION_ARGS
)
4497 Oid roleid
= PG_GETARG_OID(0);
4498 text
*typename
= PG_GETARG_TEXT_PP(1);
4499 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4502 AclResult aclresult
;
4504 typeoid
= convert_type_name(typename
);
4505 mode
= convert_type_priv_string(priv_type_text
);
4507 aclresult
= object_aclcheck(TypeRelationId
, typeoid
, roleid
, mode
);
4509 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4513 * has_type_privilege_id_id
4514 * Check user privileges on a type given
4515 * roleid, type oid, and text priv name.
4518 has_type_privilege_id_id(PG_FUNCTION_ARGS
)
4520 Oid roleid
= PG_GETARG_OID(0);
4521 Oid typeoid
= PG_GETARG_OID(1);
4522 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4524 AclResult aclresult
;
4525 bool is_missing
= false;
4527 mode
= convert_type_priv_string(priv_type_text
);
4529 aclresult
= object_aclcheck_ext(TypeRelationId
, typeoid
,
4536 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4540 * Support routines for has_type_privilege family.
4544 * Given a type name expressed as a string, look it up and return Oid
4547 convert_type_name(text
*typename
)
4549 char *typname
= text_to_cstring(typename
);
4552 oid
= DatumGetObjectId(DirectFunctionCall1(regtypein
,
4553 CStringGetDatum(typname
)));
4555 if (!OidIsValid(oid
))
4557 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4558 errmsg("type \"%s\" does not exist", typname
)));
4564 * convert_type_priv_string
4565 * Convert text string to AclMode value.
4568 convert_type_priv_string(text
*priv_type_text
)
4570 static const priv_map type_priv_map
[] = {
4571 {"USAGE", ACL_USAGE
},
4572 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE
)},
4576 return convert_any_priv_string(priv_type_text
, type_priv_map
);
4580 * has_parameter_privilege variants
4581 * These are all named "has_parameter_privilege" at the SQL level.
4582 * They take various combinations of parameter name with
4583 * user name, user OID, or implicit user = current_user.
4585 * The result is a boolean value: true if user has been granted
4586 * the indicated privilege or false if not.
4590 * has_param_priv_byname
4592 * Helper function to check user privileges on a parameter given the
4593 * role by Oid, parameter by text name, and privileges as AclMode.
4596 has_param_priv_byname(Oid roleid
, const text
*parameter
, AclMode priv
)
4598 char *paramstr
= text_to_cstring(parameter
);
4600 return pg_parameter_aclcheck(paramstr
, roleid
, priv
) == ACLCHECK_OK
;
4604 * has_parameter_privilege_name_name
4605 * Check user privileges on a parameter given name username, text
4606 * parameter, and text priv name.
4609 has_parameter_privilege_name_name(PG_FUNCTION_ARGS
)
4611 Name username
= PG_GETARG_NAME(0);
4612 text
*parameter
= PG_GETARG_TEXT_PP(1);
4613 AclMode priv
= convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
4614 Oid roleid
= get_role_oid_or_public(NameStr(*username
));
4616 PG_RETURN_BOOL(has_param_priv_byname(roleid
, parameter
, priv
));
4620 * has_parameter_privilege_name
4621 * Check user privileges on a parameter given text parameter and text priv
4622 * name. current_user is assumed
4625 has_parameter_privilege_name(PG_FUNCTION_ARGS
)
4627 text
*parameter
= PG_GETARG_TEXT_PP(0);
4628 AclMode priv
= convert_parameter_priv_string(PG_GETARG_TEXT_PP(1));
4630 PG_RETURN_BOOL(has_param_priv_byname(GetUserId(), parameter
, priv
));
4634 * has_parameter_privilege_id_name
4635 * Check user privileges on a parameter given roleid, text parameter, and
4639 has_parameter_privilege_id_name(PG_FUNCTION_ARGS
)
4641 Oid roleid
= PG_GETARG_OID(0);
4642 text
*parameter
= PG_GETARG_TEXT_PP(1);
4643 AclMode priv
= convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
4645 PG_RETURN_BOOL(has_param_priv_byname(roleid
, parameter
, priv
));
4649 * Support routines for has_parameter_privilege family.
4653 * convert_parameter_priv_string
4654 * Convert text string to AclMode value.
4657 convert_parameter_priv_string(text
*priv_text
)
4659 static const priv_map parameter_priv_map
[] = {
4661 {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SET
)},
4662 {"ALTER SYSTEM", ACL_ALTER_SYSTEM
},
4663 {"ALTER SYSTEM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ALTER_SYSTEM
)},
4667 return convert_any_priv_string(priv_text
, parameter_priv_map
);
4671 * has_largeobject_privilege variants
4672 * These are all named "has_largeobject_privilege" at the SQL level.
4673 * They take various combinations of large object OID with
4674 * user name, user OID, or implicit user = current_user.
4676 * The result is a boolean value: true if user has the indicated
4677 * privilege, false if not, or NULL if object doesn't exist.
4683 * Helper function to check user privileges on a large object given the
4684 * role by Oid, large object by Oid, and privileges as AclMode.
4687 has_lo_priv_byid(Oid roleid
, Oid lobjId
, AclMode priv
, bool *is_missing
)
4689 Snapshot snapshot
= NULL
;
4690 AclResult aclresult
;
4692 if (priv
& ACL_UPDATE
)
4695 snapshot
= GetActiveSnapshot();
4697 if (!LargeObjectExistsWithSnapshot(lobjId
, snapshot
))
4699 Assert(is_missing
!= NULL
);
4704 if (lo_compat_privileges
)
4707 aclresult
= pg_largeobject_aclcheck_snapshot(lobjId
,
4711 return aclresult
== ACLCHECK_OK
;
4715 * has_largeobject_privilege_name_id
4716 * Check user privileges on a large object given
4717 * name username, large object oid, and text priv name.
4720 has_largeobject_privilege_name_id(PG_FUNCTION_ARGS
)
4722 Name username
= PG_GETARG_NAME(0);
4723 Oid roleid
= get_role_oid_or_public(NameStr(*username
));
4724 Oid lobjId
= PG_GETARG_OID(1);
4725 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4727 bool is_missing
= false;
4730 mode
= convert_largeobject_priv_string(priv_type_text
);
4731 result
= has_lo_priv_byid(roleid
, lobjId
, mode
, &is_missing
);
4736 PG_RETURN_BOOL(result
);
4740 * has_largeobject_privilege_id
4741 * Check user privileges on a large object given
4742 * large object oid, and text priv name.
4743 * current_user is assumed
4746 has_largeobject_privilege_id(PG_FUNCTION_ARGS
)
4748 Oid lobjId
= PG_GETARG_OID(0);
4749 Oid roleid
= GetUserId();
4750 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4752 bool is_missing
= false;
4755 mode
= convert_largeobject_priv_string(priv_type_text
);
4756 result
= has_lo_priv_byid(roleid
, lobjId
, mode
, &is_missing
);
4761 PG_RETURN_BOOL(result
);
4765 * has_largeobject_privilege_id_id
4766 * Check user privileges on a large object given
4767 * roleid, large object oid, and text priv name.
4770 has_largeobject_privilege_id_id(PG_FUNCTION_ARGS
)
4772 Oid roleid
= PG_GETARG_OID(0);
4773 Oid lobjId
= PG_GETARG_OID(1);
4774 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4776 bool is_missing
= false;
4779 mode
= convert_largeobject_priv_string(priv_type_text
);
4780 result
= has_lo_priv_byid(roleid
, lobjId
, mode
, &is_missing
);
4785 PG_RETURN_BOOL(result
);
4789 * convert_largeobject_priv_string
4790 * Convert text string to AclMode value.
4793 convert_largeobject_priv_string(text
*priv_type_text
)
4795 static const priv_map largeobject_priv_map
[] = {
4796 {"SELECT", ACL_SELECT
},
4797 {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT
)},
4798 {"UPDATE", ACL_UPDATE
},
4799 {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE
)},
4803 return convert_any_priv_string(priv_type_text
, largeobject_priv_map
);
4807 * pg_has_role variants
4808 * These are all named "pg_has_role" at the SQL level.
4809 * They take various combinations of role name, role OID,
4810 * user name, user OID, or implicit user = current_user.
4812 * The result is a boolean value: true if user has the indicated
4813 * privilege, false if not.
4817 * pg_has_role_name_name
4818 * Check user privileges on a role given
4819 * name username, name rolename, and text priv name.
4822 pg_has_role_name_name(PG_FUNCTION_ARGS
)
4824 Name username
= PG_GETARG_NAME(0);
4825 Name rolename
= PG_GETARG_NAME(1);
4826 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4830 AclResult aclresult
;
4832 roleid
= get_role_oid(NameStr(*username
), false);
4833 roleoid
= get_role_oid(NameStr(*rolename
), false);
4834 mode
= convert_role_priv_string(priv_type_text
);
4836 aclresult
= pg_role_aclcheck(roleoid
, roleid
, mode
);
4838 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4843 * Check user privileges on a role given
4844 * name rolename and text priv name.
4845 * current_user is assumed
4848 pg_has_role_name(PG_FUNCTION_ARGS
)
4850 Name rolename
= PG_GETARG_NAME(0);
4851 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4855 AclResult aclresult
;
4857 roleid
= GetUserId();
4858 roleoid
= get_role_oid(NameStr(*rolename
), false);
4859 mode
= convert_role_priv_string(priv_type_text
);
4861 aclresult
= pg_role_aclcheck(roleoid
, roleid
, mode
);
4863 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4867 * pg_has_role_name_id
4868 * Check user privileges on a role given
4869 * name usename, role oid, and text priv name.
4872 pg_has_role_name_id(PG_FUNCTION_ARGS
)
4874 Name username
= PG_GETARG_NAME(0);
4875 Oid roleoid
= PG_GETARG_OID(1);
4876 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4879 AclResult aclresult
;
4881 roleid
= get_role_oid(NameStr(*username
), false);
4882 mode
= convert_role_priv_string(priv_type_text
);
4884 aclresult
= pg_role_aclcheck(roleoid
, roleid
, mode
);
4886 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4891 * Check user privileges on a role given
4892 * role oid, and text priv name.
4893 * current_user is assumed
4896 pg_has_role_id(PG_FUNCTION_ARGS
)
4898 Oid roleoid
= PG_GETARG_OID(0);
4899 text
*priv_type_text
= PG_GETARG_TEXT_PP(1);
4902 AclResult aclresult
;
4904 roleid
= GetUserId();
4905 mode
= convert_role_priv_string(priv_type_text
);
4907 aclresult
= pg_role_aclcheck(roleoid
, roleid
, mode
);
4909 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4913 * pg_has_role_id_name
4914 * Check user privileges on a role given
4915 * roleid, name rolename, and text priv name.
4918 pg_has_role_id_name(PG_FUNCTION_ARGS
)
4920 Oid roleid
= PG_GETARG_OID(0);
4921 Name rolename
= PG_GETARG_NAME(1);
4922 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4925 AclResult aclresult
;
4927 roleoid
= get_role_oid(NameStr(*rolename
), false);
4928 mode
= convert_role_priv_string(priv_type_text
);
4930 aclresult
= pg_role_aclcheck(roleoid
, roleid
, mode
);
4932 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4937 * Check user privileges on a role given
4938 * roleid, role oid, and text priv name.
4941 pg_has_role_id_id(PG_FUNCTION_ARGS
)
4943 Oid roleid
= PG_GETARG_OID(0);
4944 Oid roleoid
= PG_GETARG_OID(1);
4945 text
*priv_type_text
= PG_GETARG_TEXT_PP(2);
4947 AclResult aclresult
;
4949 mode
= convert_role_priv_string(priv_type_text
);
4951 aclresult
= pg_role_aclcheck(roleoid
, roleid
, mode
);
4953 PG_RETURN_BOOL(aclresult
== ACLCHECK_OK
);
4957 * Support routines for pg_has_role family.
4961 * convert_role_priv_string
4962 * Convert text string to AclMode value.
4964 * We use USAGE to denote whether the privileges of the role are accessible
4965 * (has_privs_of_role), MEMBER to denote is_member, and MEMBER WITH GRANT
4966 * (or ADMIN) OPTION to denote is_admin. There is no ACL bit corresponding
4967 * to MEMBER so we cheat and use ACL_CREATE for that. This convention
4968 * is shared only with pg_role_aclcheck, below.
4971 convert_role_priv_string(text
*priv_type_text
)
4973 static const priv_map role_priv_map
[] = {
4974 {"USAGE", ACL_USAGE
},
4975 {"MEMBER", ACL_CREATE
},
4977 {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
4978 {"USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
4979 {"MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
4980 {"MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
4981 {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
4982 {"SET WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE
)},
4986 return convert_any_priv_string(priv_type_text
, role_priv_map
);
4991 * Quick-and-dirty support for pg_has_role
4994 pg_role_aclcheck(Oid role_oid
, Oid roleid
, AclMode mode
)
4996 if (mode
& ACL_GRANT_OPTION_FOR(ACL_CREATE
))
4998 if (is_admin_of_role(roleid
, role_oid
))
5001 if (mode
& ACL_CREATE
)
5003 if (is_member_of_role(roleid
, role_oid
))
5006 if (mode
& ACL_USAGE
)
5008 if (has_privs_of_role(roleid
, role_oid
))
5013 if (member_can_set_role(roleid
, role_oid
))
5016 return ACLCHECK_NO_PRIV
;
5021 * initialization function (called by InitPostgres)
5024 initialize_acl(void)
5026 if (!IsBootstrapProcessingMode())
5029 GetSysCacheHashValue1(DATABASEOID
,
5030 ObjectIdGetDatum(MyDatabaseId
));
5033 * In normal mode, set a callback on any syscache invalidation of rows
5034 * of pg_auth_members (for roles_is_member_of()) pg_database (for
5035 * roles_is_member_of())
5037 CacheRegisterSyscacheCallback(AUTHMEMROLEMEM
,
5038 RoleMembershipCacheCallback
,
5040 CacheRegisterSyscacheCallback(AUTHOID
,
5041 RoleMembershipCacheCallback
,
5043 CacheRegisterSyscacheCallback(DATABASEOID
,
5044 RoleMembershipCacheCallback
,
5050 * RoleMembershipCacheCallback
5051 * Syscache inval callback function
5054 RoleMembershipCacheCallback(Datum arg
, int cacheid
, uint32 hashvalue
)
5056 if (cacheid
== DATABASEOID
&&
5057 hashvalue
!= cached_db_hash
&&
5060 return; /* ignore pg_database changes for other DBs */
5063 /* Force membership caches to be recomputed on next use */
5064 cached_role
[ROLERECURSE_MEMBERS
] = InvalidOid
;
5065 cached_role
[ROLERECURSE_PRIVS
] = InvalidOid
;
5066 cached_role
[ROLERECURSE_SETROLE
] = InvalidOid
;
5070 * A helper function for roles_is_member_of() that provides an optimized
5071 * implementation of list_append_unique_oid() via a Bloom filter. The caller
5072 * (i.e., roles_is_member_of()) is responsible for freeing bf once it is done
5073 * using this function.
5075 static inline List
*
5076 roles_list_append(List
*roles_list
, bloom_filter
**bf
, Oid role
)
5078 unsigned char *roleptr
= (unsigned char *) &role
;
5081 * If there is a previously-created Bloom filter, use it to try to
5082 * determine whether the role is missing from the list. If it says yes,
5083 * that's a hard fact and we can go ahead and add the role. If it says
5084 * no, that's only probabilistic and we'd better search the list. Without
5085 * a filter, we must always do an ordinary linear search through the
5088 if ((*bf
&& bloom_lacks_element(*bf
, roleptr
, sizeof(Oid
))) ||
5089 !list_member_oid(roles_list
, role
))
5092 * If the list is large, we take on the overhead of creating and
5093 * populating a Bloom filter to speed up future calls to this
5097 list_length(roles_list
) > ROLES_LIST_BLOOM_THRESHOLD
)
5099 *bf
= bloom_create(ROLES_LIST_BLOOM_THRESHOLD
* 10, work_mem
, 0);
5100 foreach_oid(roleid
, roles_list
)
5101 bloom_add_element(*bf
, (unsigned char *) &roleid
, sizeof(Oid
));
5105 * Finally, add the role to the list and the Bloom filter, if it
5108 roles_list
= lappend_oid(roles_list
, role
);
5110 bloom_add_element(*bf
, roleptr
, sizeof(Oid
));
5117 * Get a list of roles that the specified roleid is a member of
5119 * Type ROLERECURSE_MEMBERS recurses through all grants; ROLERECURSE_PRIVS
5120 * recurses only through inheritable grants; and ROLERECURSE_SETROLE recurses
5121 * only through grants with set_option.
5123 * Since indirect membership testing is relatively expensive, we cache
5124 * a list of memberships. Hence, the result is only guaranteed good until
5125 * the next call of roles_is_member_of()!
5127 * For the benefit of select_best_grantor, the result is defined to be
5128 * in breadth-first order, ie, closer relationships earlier.
5130 * If admin_of is not InvalidOid, this function sets *admin_role, either
5131 * to the OID of the first role in the result list that directly possesses
5132 * ADMIN OPTION on the role corresponding to admin_of, or to InvalidOid if
5133 * there is no such role.
5136 roles_is_member_of(Oid roleid
, enum RoleRecurseType type
,
5137 Oid admin_of
, Oid
*admin_role
)
5142 List
*new_cached_roles
;
5143 MemoryContext oldctx
;
5144 bloom_filter
*bf
= NULL
;
5146 Assert(OidIsValid(admin_of
) == PointerIsValid(admin_role
));
5147 if (admin_role
!= NULL
)
5148 *admin_role
= InvalidOid
;
5150 /* If cache is valid and ADMIN OPTION not sought, just return the list */
5151 if (cached_role
[type
] == roleid
&& !OidIsValid(admin_of
) &&
5152 OidIsValid(cached_role
[type
]))
5153 return cached_roles
[type
];
5156 * Role expansion happens in a non-database backend when guc.c checks
5157 * ROLE_PG_READ_ALL_SETTINGS for a physical walsender SHOW command. In
5158 * that case, no role gets pg_database_owner.
5160 if (!OidIsValid(MyDatabaseId
))
5166 dbtup
= SearchSysCache1(DATABASEOID
, ObjectIdGetDatum(MyDatabaseId
));
5167 if (!HeapTupleIsValid(dbtup
))
5168 elog(ERROR
, "cache lookup failed for database %u", MyDatabaseId
);
5169 dba
= ((Form_pg_database
) GETSTRUCT(dbtup
))->datdba
;
5170 ReleaseSysCache(dbtup
);
5174 * Find all the roles that roleid is a member of, including multi-level
5175 * recursion. The role itself will always be the first element of the
5178 * Each element of the list is scanned to see if it adds any indirect
5179 * memberships. We can use a single list as both the record of
5180 * already-found memberships and the agenda of roles yet to be scanned.
5181 * This is a bit tricky but works because the foreach() macro doesn't
5182 * fetch the next list element until the bottom of the loop.
5184 roles_list
= list_make1_oid(roleid
);
5186 foreach(l
, roles_list
)
5188 Oid memberid
= lfirst_oid(l
);
5192 /* Find roles that memberid is directly a member of */
5193 memlist
= SearchSysCacheList1(AUTHMEMMEMROLE
,
5194 ObjectIdGetDatum(memberid
));
5195 for (i
= 0; i
< memlist
->n_members
; i
++)
5197 HeapTuple tup
= &memlist
->members
[i
]->tuple
;
5198 Form_pg_auth_members form
= (Form_pg_auth_members
) GETSTRUCT(tup
);
5199 Oid otherid
= form
->roleid
;
5202 * While otherid==InvalidOid shouldn't appear in the catalog, the
5203 * OidIsValid() avoids crashing if that arises.
5205 if (otherid
== admin_of
&& form
->admin_option
&&
5206 OidIsValid(admin_of
) && !OidIsValid(*admin_role
))
5207 *admin_role
= memberid
;
5209 /* If we're supposed to ignore non-heritable grants, do so. */
5210 if (type
== ROLERECURSE_PRIVS
&& !form
->inherit_option
)
5213 /* If we're supposed to ignore non-SET grants, do so. */
5214 if (type
== ROLERECURSE_SETROLE
&& !form
->set_option
)
5218 * Even though there shouldn't be any loops in the membership
5219 * graph, we must test for having already seen this role. It is
5220 * legal for instance to have both A->B and A->C->B.
5222 roles_list
= roles_list_append(roles_list
, &bf
, otherid
);
5224 ReleaseSysCacheList(memlist
);
5226 /* implement pg_database_owner implicit membership */
5227 if (memberid
== dba
&& OidIsValid(dba
))
5228 roles_list
= roles_list_append(roles_list
, &bf
,
5229 ROLE_PG_DATABASE_OWNER
);
5233 * Free the Bloom filter created by roles_list_append(), if there is one.
5239 * Copy the completed list into TopMemoryContext so it will persist.
5241 oldctx
= MemoryContextSwitchTo(TopMemoryContext
);
5242 new_cached_roles
= list_copy(roles_list
);
5243 MemoryContextSwitchTo(oldctx
);
5244 list_free(roles_list
);
5247 * Now safe to assign to state variable
5249 cached_role
[type
] = InvalidOid
; /* just paranoia */
5250 list_free(cached_roles
[type
]);
5251 cached_roles
[type
] = new_cached_roles
;
5252 cached_role
[type
] = roleid
;
5254 /* And now we can return the answer */
5255 return cached_roles
[type
];
5260 * Does member have the privileges of role (directly or indirectly)?
5262 * This is defined not to recurse through grants that are not inherited,
5263 * and only inherited grants confer the associated privileges automatically.
5265 * See also member_can_set_role, below.
5268 has_privs_of_role(Oid member
, Oid role
)
5270 /* Fast path for simple case */
5274 /* Superusers have every privilege, so are part of every role */
5275 if (superuser_arg(member
))
5279 * Find all the roles that member has the privileges of, including
5280 * multi-level recursion, then see if target role is any one of them.
5282 return list_member_oid(roles_is_member_of(member
, ROLERECURSE_PRIVS
,
5288 * Can member use SET ROLE to this role?
5290 * There must be a chain of grants from 'member' to 'role' each of which
5291 * permits SET ROLE; that is, each of which has set_option = true.
5293 * It doesn't matter whether the grants are inheritable. That's a separate
5294 * question; see has_privs_of_role.
5296 * This function should be used to determine whether the session user can
5297 * use SET ROLE to become the target user. We also use it to determine whether
5298 * the session user can change an existing object to be owned by the target
5299 * user, or create new objects owned by the target user.
5302 member_can_set_role(Oid member
, Oid role
)
5304 /* Fast path for simple case */
5308 /* Superusers have every privilege, so can always SET ROLE */
5309 if (superuser_arg(member
))
5313 * Find all the roles that member can access via SET ROLE, including
5314 * multi-level recursion, then see if target role is any one of them.
5316 return list_member_oid(roles_is_member_of(member
, ROLERECURSE_SETROLE
,
5322 * Permission violation error unless able to SET ROLE to target role.
5325 check_can_set_role(Oid member
, Oid role
)
5327 if (!member_can_set_role(member
, role
))
5329 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
5330 errmsg("must be able to SET ROLE \"%s\"",
5331 GetUserNameFromId(role
, false))));
5335 * Is member a member of role (directly or indirectly)?
5337 * This is defined to recurse through grants whether they are inherited or not.
5339 * Do not use this for privilege checking, instead use has_privs_of_role().
5340 * Don't use it for determining whether it's possible to SET ROLE to some
5341 * other role; for that, use member_can_set_role(). And don't use it for
5342 * determining whether it's OK to create an object owned by some other role:
5343 * use member_can_set_role() for that, too.
5345 * In short, calling this function is the wrong thing to do nearly everywhere.
5348 is_member_of_role(Oid member
, Oid role
)
5350 /* Fast path for simple case */
5354 /* Superusers have every privilege, so are part of every role */
5355 if (superuser_arg(member
))
5359 * Find all the roles that member is a member of, including multi-level
5360 * recursion, then see if target role is any one of them.
5362 return list_member_oid(roles_is_member_of(member
, ROLERECURSE_MEMBERS
,
5368 * Is member a member of role, not considering superuserness?
5370 * This is identical to is_member_of_role except we ignore superuser
5373 * Do not use this for privilege checking, instead use has_privs_of_role()
5376 is_member_of_role_nosuper(Oid member
, Oid role
)
5378 /* Fast path for simple case */
5383 * Find all the roles that member is a member of, including multi-level
5384 * recursion, then see if target role is any one of them.
5386 return list_member_oid(roles_is_member_of(member
, ROLERECURSE_MEMBERS
,
5393 * Is member an admin of role? That is, is member the role itself (subject to
5394 * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
5398 is_admin_of_role(Oid member
, Oid role
)
5402 if (superuser_arg(member
))
5405 /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5409 (void) roles_is_member_of(member
, ROLERECURSE_MEMBERS
, role
, &admin_role
);
5410 return OidIsValid(admin_role
);
5414 * Find a role whose privileges "member" inherits which has ADMIN OPTION
5415 * on "role", ignoring super-userness.
5417 * There might be more than one such role; prefer one which involves fewer
5418 * hops. That is, if member has ADMIN OPTION, prefer that over all other
5419 * options; if not, prefer a role from which member inherits more directly
5420 * over more indirect inheritance.
5423 select_best_admin(Oid member
, Oid role
)
5427 /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5431 (void) roles_is_member_of(member
, ROLERECURSE_PRIVS
, role
, &admin_role
);
5436 /* does what it says ... */
5438 count_one_bits(AclMode mask
)
5442 /* this code relies on AclMode being an unsigned type */
5454 * Select the effective grantor ID for a GRANT or REVOKE operation.
5456 * The grantor must always be either the object owner or some role that has
5457 * been explicitly granted grant options. This ensures that all granted
5458 * privileges appear to flow from the object owner, and there are never
5459 * multiple "original sources" of a privilege. Therefore, if the would-be
5460 * grantor is a member of a role that has the needed grant options, we have
5461 * to do the grant as that role instead.
5463 * It is possible that the would-be grantor is a member of several roles
5464 * that have different subsets of the desired grant options, but no one
5465 * role has 'em all. In this case we pick a role with the largest number
5466 * of desired options. Ties are broken in favor of closer ancestors.
5468 * roleId: the role attempting to do the GRANT/REVOKE
5469 * privileges: the privileges to be granted/revoked
5470 * acl: the ACL of the object in question
5471 * ownerId: the role owning the object in question
5472 * *grantorId: receives the OID of the role to do the grant as
5473 * *grantOptions: receives the grant options actually held by grantorId
5475 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
5478 select_best_grantor(Oid roleId
, AclMode privileges
,
5479 const Acl
*acl
, Oid ownerId
,
5480 Oid
*grantorId
, AclMode
*grantOptions
)
5482 AclMode needed_goptions
= ACL_GRANT_OPTION_FOR(privileges
);
5488 * The object owner is always treated as having all grant options, so if
5489 * roleId is the owner it's easy. Also, if roleId is a superuser it's
5490 * easy: superusers are implicitly members of every role, so they act as
5493 if (roleId
== ownerId
|| superuser_arg(roleId
))
5495 *grantorId
= ownerId
;
5496 *grantOptions
= needed_goptions
;
5501 * Otherwise we have to do a careful search to see if roleId has the
5502 * privileges of any suitable role. Note: we can hang onto the result of
5503 * roles_is_member_of() throughout this loop, because aclmask_direct()
5504 * doesn't query any role memberships.
5506 roles_list
= roles_is_member_of(roleId
, ROLERECURSE_PRIVS
,
5509 /* initialize candidate result as default */
5510 *grantorId
= roleId
;
5511 *grantOptions
= ACL_NO_RIGHTS
;
5514 foreach(l
, roles_list
)
5516 Oid otherrole
= lfirst_oid(l
);
5519 otherprivs
= aclmask_direct(acl
, otherrole
, ownerId
,
5520 needed_goptions
, ACLMASK_ALL
);
5521 if (otherprivs
== needed_goptions
)
5523 /* Found a suitable grantor */
5524 *grantorId
= otherrole
;
5525 *grantOptions
= otherprivs
;
5530 * If it has just some of the needed privileges, remember best
5533 if (otherprivs
!= ACL_NO_RIGHTS
)
5535 int nnewrights
= count_one_bits(otherprivs
);
5537 if (nnewrights
> nrights
)
5539 *grantorId
= otherrole
;
5540 *grantOptions
= otherprivs
;
5541 nrights
= nnewrights
;
5548 * get_role_oid - Given a role name, look up the role's OID.
5550 * If missing_ok is false, throw an error if role name not found. If
5551 * true, just return InvalidOid.
5554 get_role_oid(const char *rolname
, bool missing_ok
)
5558 oid
= GetSysCacheOid1(AUTHNAME
, Anum_pg_authid_oid
,
5559 CStringGetDatum(rolname
));
5560 if (!OidIsValid(oid
) && !missing_ok
)
5562 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5563 errmsg("role \"%s\" does not exist", rolname
)));
5568 * get_role_oid_or_public - As above, but return ACL_ID_PUBLIC if the
5569 * role name is "public".
5572 get_role_oid_or_public(const char *rolname
)
5574 if (strcmp(rolname
, "public") == 0)
5575 return ACL_ID_PUBLIC
;
5577 return get_role_oid(rolname
, false);
5581 * Given a RoleSpec node, return the OID it corresponds to. If missing_ok is
5582 * true, return InvalidOid if the role does not exist.
5584 * PUBLIC is always disallowed here. Routines wanting to handle the PUBLIC
5585 * case must check the case separately.
5588 get_rolespec_oid(const RoleSpec
*role
, bool missing_ok
)
5592 switch (role
->roletype
)
5594 case ROLESPEC_CSTRING
:
5595 Assert(role
->rolename
);
5596 oid
= get_role_oid(role
->rolename
, missing_ok
);
5599 case ROLESPEC_CURRENT_ROLE
:
5600 case ROLESPEC_CURRENT_USER
:
5604 case ROLESPEC_SESSION_USER
:
5605 oid
= GetSessionUserId();
5608 case ROLESPEC_PUBLIC
:
5610 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5611 errmsg("role \"%s\" does not exist", "public")));
5612 oid
= InvalidOid
; /* make compiler happy */
5616 elog(ERROR
, "unexpected role type %d", role
->roletype
);
5623 * Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
5624 * Caller must ReleaseSysCache when done with the result tuple.
5627 get_rolespec_tuple(const RoleSpec
*role
)
5631 switch (role
->roletype
)
5633 case ROLESPEC_CSTRING
:
5634 Assert(role
->rolename
);
5635 tuple
= SearchSysCache1(AUTHNAME
, CStringGetDatum(role
->rolename
));
5636 if (!HeapTupleIsValid(tuple
))
5638 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5639 errmsg("role \"%s\" does not exist", role
->rolename
)));
5642 case ROLESPEC_CURRENT_ROLE
:
5643 case ROLESPEC_CURRENT_USER
:
5644 tuple
= SearchSysCache1(AUTHOID
, ObjectIdGetDatum(GetUserId()));
5645 if (!HeapTupleIsValid(tuple
))
5646 elog(ERROR
, "cache lookup failed for role %u", GetUserId());
5649 case ROLESPEC_SESSION_USER
:
5650 tuple
= SearchSysCache1(AUTHOID
, ObjectIdGetDatum(GetSessionUserId()));
5651 if (!HeapTupleIsValid(tuple
))
5652 elog(ERROR
, "cache lookup failed for role %u", GetSessionUserId());
5655 case ROLESPEC_PUBLIC
:
5657 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5658 errmsg("role \"%s\" does not exist", "public")));
5659 tuple
= NULL
; /* make compiler happy */
5663 elog(ERROR
, "unexpected role type %d", role
->roletype
);
5670 * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
5673 get_rolespec_name(const RoleSpec
*role
)
5676 Form_pg_authid authForm
;
5679 tp
= get_rolespec_tuple(role
);
5680 authForm
= (Form_pg_authid
) GETSTRUCT(tp
);
5681 rolename
= pstrdup(NameStr(authForm
->rolname
));
5682 ReleaseSysCache(tp
);
5688 * Given a RoleSpec, throw an error if the name is reserved, using detail_msg,
5689 * if provided (which must be already translated).
5691 * If node is NULL, no error is thrown. If detail_msg is NULL then no detail
5692 * message is provided.
5695 check_rolespec_name(const RoleSpec
*role
, const char *detail_msg
)
5700 if (role
->roletype
!= ROLESPEC_CSTRING
)
5703 if (IsReservedName(role
->rolename
))
5707 (errcode(ERRCODE_RESERVED_NAME
),
5708 errmsg("role name \"%s\" is reserved",
5710 errdetail_internal("%s", detail_msg
)));
5713 (errcode(ERRCODE_RESERVED_NAME
),
5714 errmsg("role name \"%s\" is reserved",