sepgsql: update TAP test to use fat comma style
[pgsql.git] / src / backend / utils / adt / acl.c
blob6a76550a5e2ddb1ab0b0bd3cb819fac3abc5bbe4
1 /*-------------------------------------------------------------------------
3 * acl.c
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
10 * IDENTIFICATION
11 * src/backend/utils/adt/acl.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include <ctype.h>
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"
39 #include "funcapi.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"
55 typedef struct
57 const char *name;
58 AclMode value;
59 } priv_map;
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.
75 enum RoleRecurseType
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,
101 Oid ownerId);
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);
138 * getid
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.
143 * RETURNS:
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.
152 static const char *
153 getid(const char *s, char *n, Node *escontext)
155 int len = 0;
156 bool in_quotes = false;
158 Assert(s && n);
160 while (isspace((unsigned char) *s))
161 s++;
162 /* This code had better match what putid() does, below */
163 for (;
164 *s != '\0' &&
165 (isalnum((unsigned char) *s) ||
166 *s == '_' ||
167 *s == '"' ||
168 in_quotes);
169 s++)
171 if (*s == '"')
173 /* safe to look at next char (could be '\0' though) */
174 if (*(s + 1) != '"')
176 in_quotes = !in_quotes;
177 continue;
179 /* it's an escaped double quote; skip the escaping char */
180 s++;
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.",
189 NAMEDATALEN)));
191 n[len++] = *s;
193 n[len] = '\0';
194 while (isspace((unsigned char) *s))
195 s++;
196 return 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
204 static void
205 putid(char *p, const char *s)
207 const char *src;
208 bool safe = true;
210 for (src = s; *src; src++)
212 /* This test had better match what getid() does, above */
213 if (!isalnum((unsigned char) *src) && *src != '_')
215 safe = false;
216 break;
219 if (!safe)
220 *p++ = '"';
221 for (src = s; *src; src++)
223 /* A double quote character in a username is encoded as "" */
224 if (*src == '"')
225 *p++ = '"';
226 *p++ = *src;
228 if (!safe)
229 *p++ = '"';
230 *p = '\0';
234 * aclparse
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
239 * ACL specification.
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.
247 * RETURNS:
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.
256 static const char *
257 aclparse(const char *s, AclItem *aip, Node *escontext)
259 AclMode privs,
260 goption,
261 read;
262 char name[NAMEDATALEN];
263 char name2[NAMEDATALEN];
265 Assert(s && aip);
267 s = getid(s, name, escontext);
268 if (s == NULL)
269 return NULL;
270 if (*s != '=')
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);
280 if (s == NULL)
281 return NULL;
282 if (name[0] == '\0')
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.")));
289 if (*s != '=')
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++)
298 switch (*s)
300 case '*':
301 goption |= read;
302 break;
303 case ACL_INSERT_CHR:
304 read = ACL_INSERT;
305 break;
306 case ACL_SELECT_CHR:
307 read = ACL_SELECT;
308 break;
309 case ACL_UPDATE_CHR:
310 read = ACL_UPDATE;
311 break;
312 case ACL_DELETE_CHR:
313 read = ACL_DELETE;
314 break;
315 case ACL_TRUNCATE_CHR:
316 read = ACL_TRUNCATE;
317 break;
318 case ACL_REFERENCES_CHR:
319 read = ACL_REFERENCES;
320 break;
321 case ACL_TRIGGER_CHR:
322 read = ACL_TRIGGER;
323 break;
324 case ACL_EXECUTE_CHR:
325 read = ACL_EXECUTE;
326 break;
327 case ACL_USAGE_CHR:
328 read = ACL_USAGE;
329 break;
330 case ACL_CREATE_CHR:
331 read = ACL_CREATE;
332 break;
333 case ACL_CREATE_TEMP_CHR:
334 read = ACL_CREATE_TEMP;
335 break;
336 case ACL_CONNECT_CHR:
337 read = ACL_CONNECT;
338 break;
339 case ACL_SET_CHR:
340 read = ACL_SET;
341 break;
342 case ACL_ALTER_SYSTEM_CHR:
343 read = ACL_ALTER_SYSTEM;
344 break;
345 case ACL_MAINTAIN_CHR:
346 read = ACL_MAINTAIN;
347 break;
348 default:
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)));
355 privs |= read;
358 if (name[0] == '\0')
359 aip->ai_grantee = ACL_ID_PUBLIC;
360 else
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
371 * to the superuser.
373 if (*s == '/')
375 s = getid(s + 1, name2, escontext);
376 if (s == NULL)
377 return NULL;
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)));
388 else
390 aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
391 ereport(WARNING,
392 (errcode(ERRCODE_INVALID_GRANTOR),
393 errmsg("defaulting grantor to user ID %u",
394 BOOTSTRAP_SUPERUSERID)));
397 ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
399 return s;
403 * allocacl
404 * Allocates storage for a new Acl with 'n' entries.
406 * RETURNS:
407 * the new Acl
409 static Acl *
410 allocacl(int n)
412 Acl *new_acl;
413 Size size;
415 if (n < 0)
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);
420 new_acl->ndim = 1;
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;
425 return new_acl;
429 * Create a zero-entry ACL
431 Acl *
432 make_empty_acl(void)
434 return allocacl(0);
438 * Copy an ACL
440 Acl *
441 aclcopy(const Acl *orig_acl)
443 Acl *result_acl;
445 result_acl = allocacl(ACL_NUM(orig_acl));
447 memcpy(ACL_DAT(result_acl),
448 ACL_DAT(orig_acl),
449 ACL_NUM(orig_acl) * sizeof(AclItem));
451 return result_acl;
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!
460 Acl *
461 aclconcat(const Acl *left_acl, const Acl *right_acl)
463 Acl *result_acl;
465 result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
467 memcpy(ACL_DAT(result_acl),
468 ACL_DAT(left_acl),
469 ACL_NUM(left_acl) * sizeof(AclItem));
471 memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
472 ACL_DAT(right_acl),
473 ACL_NUM(right_acl) * sizeof(AclItem));
475 return result_acl;
479 * Merge two ACLs
481 * This produces a properly merged ACL with no redundant entries.
482 * Returns NULL on NULL input.
484 Acl *
485 aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
487 Acl *result_acl;
488 AclItem *aip;
489 int i,
490 num;
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)
496 return NULL;
497 else
498 return aclcopy(right_acl);
500 else
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++)
514 Acl *tmp_acl;
516 tmp_acl = aclupdate(result_acl, aip, ACL_MODECHG_ADD,
517 ownerId, DROP_RESTRICT);
518 pfree(result_acl);
519 result_acl = tmp_acl;
522 return result_acl;
526 * Sort the items in an ACL (into an arbitrary but consistent order)
528 void
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().
542 bool
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)
549 return true;
550 else
551 return false;
553 else
555 if (right_acl == NULL || ACL_NUM(right_acl) == 0)
556 return false;
559 if (ACL_NUM(left_acl) != ACL_NUM(right_acl))
560 return false;
562 if (memcmp(ACL_DAT(left_acl),
563 ACL_DAT(right_acl),
564 ACL_NUM(left_acl) * sizeof(AclItem)) == 0)
565 return true;
567 return false;
571 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
573 static void
574 check_acl(const Acl *acl)
576 if (ARR_ELEMTYPE(acl) != ACLITEMOID)
577 ereport(ERROR,
578 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
579 errmsg("ACL array contains wrong data type")));
580 if (ARR_NDIM(acl) != 1)
581 ereport(ERROR,
582 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
583 errmsg("ACL arrays must be one-dimensional")));
584 if (ARR_HASNULL(acl))
585 ereport(ERROR,
586 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
587 errmsg("ACL arrays must not contain null values")));
591 * aclitemin
592 * Allocates storage for, and fills in, a new AclItem given a string
593 * 's' that contains an ACL specification. See aclparse for details.
595 * RETURNS:
596 * the new AclItem
598 Datum
599 aclitemin(PG_FUNCTION_ARGS)
601 const char *s = PG_GETARG_CSTRING(0);
602 Node *escontext = fcinfo->context;
603 AclItem *aip;
605 aip = (AclItem *) palloc(sizeof(AclItem));
607 s = aclparse(s, aip, escontext);
608 if (s == NULL)
609 PG_RETURN_NULL();
611 while (isspace((unsigned char) *s))
612 ++s;
613 if (*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);
622 * aclitemout
623 * Allocates storage for, and fills in, a new null-delimited string
624 * containing a formatted ACL specification. See aclparse for details.
626 * RETURNS:
627 * the new string
629 Datum
630 aclitemout(PG_FUNCTION_ARGS)
632 AclItem *aip = PG_GETARG_ACLITEM_P(0);
633 char *p;
634 char *out;
635 HeapTuple htup;
636 unsigned i;
638 out = palloc(strlen("=/") +
639 2 * N_ACL_RIGHTS +
640 2 * (2 * NAMEDATALEN + 2) +
643 p = out;
644 *p = '\0';
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);
654 else
656 /* Generate numeric OID if we don't find an entry */
657 sprintf(p, "%u", aip->ai_grantee);
660 while (*p)
661 ++p;
663 *p++ = '=';
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))
670 *p++ = '*';
673 *p++ = '/';
674 *p = '\0';
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);
682 else
684 /* Generate numeric OID if we don't find an entry */
685 sprintf(p, "%u", aip->ai_grantor);
688 PG_RETURN_CSTRING(out);
692 * aclitem_match
693 * Two AclItems are considered to match iff they have the same
694 * grantee and grantor; the privileges are ignored.
696 static bool
697 aclitem_match(const AclItem *a1, const AclItem *a2)
699 return a1->ai_grantee == a2->ai_grantee &&
700 a1->ai_grantor == a2->ai_grantor;
704 * aclitemComparator
705 * qsort comparison function for AclItems
707 static int
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)
714 return 1;
715 if (a1->ai_grantee < a2->ai_grantee)
716 return -1;
717 if (a1->ai_grantor > a2->ai_grantor)
718 return 1;
719 if (a1->ai_grantor < a2->ai_grantor)
720 return -1;
721 if (a1->ai_privs > a2->ai_privs)
722 return 1;
723 if (a1->ai_privs < a2->ai_privs)
724 return -1;
725 return 0;
729 * aclitem equality operator
731 Datum
732 aclitem_eq(PG_FUNCTION_ARGS)
734 AclItem *a1 = PG_GETARG_ACLITEM_P(0);
735 AclItem *a2 = PG_GETARG_ACLITEM_P(1);
736 bool result;
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.
751 Datum
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.
765 Datum
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.
786 Acl *
787 acldefault(ObjectType objtype, Oid ownerId)
789 AclMode world_default;
790 AclMode owner_default;
791 int nacl;
792 Acl *acl;
793 AclItem *aip;
795 switch (objtype)
797 case OBJECT_COLUMN:
798 /* by default, columns have no extra privileges */
799 world_default = ACL_NO_RIGHTS;
800 owner_default = ACL_NO_RIGHTS;
801 break;
802 case OBJECT_TABLE:
803 world_default = ACL_NO_RIGHTS;
804 owner_default = ACL_ALL_RIGHTS_RELATION;
805 break;
806 case OBJECT_SEQUENCE:
807 world_default = ACL_NO_RIGHTS;
808 owner_default = ACL_ALL_RIGHTS_SEQUENCE;
809 break;
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;
814 break;
815 case OBJECT_FUNCTION:
816 /* Grant EXECUTE by default, for now */
817 world_default = ACL_EXECUTE;
818 owner_default = ACL_ALL_RIGHTS_FUNCTION;
819 break;
820 case OBJECT_LANGUAGE:
821 /* Grant USAGE by default, for now */
822 world_default = ACL_USAGE;
823 owner_default = ACL_ALL_RIGHTS_LANGUAGE;
824 break;
825 case OBJECT_LARGEOBJECT:
826 world_default = ACL_NO_RIGHTS;
827 owner_default = ACL_ALL_RIGHTS_LARGEOBJECT;
828 break;
829 case OBJECT_SCHEMA:
830 world_default = ACL_NO_RIGHTS;
831 owner_default = ACL_ALL_RIGHTS_SCHEMA;
832 break;
833 case OBJECT_TABLESPACE:
834 world_default = ACL_NO_RIGHTS;
835 owner_default = ACL_ALL_RIGHTS_TABLESPACE;
836 break;
837 case OBJECT_FDW:
838 world_default = ACL_NO_RIGHTS;
839 owner_default = ACL_ALL_RIGHTS_FDW;
840 break;
841 case OBJECT_FOREIGN_SERVER:
842 world_default = ACL_NO_RIGHTS;
843 owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
844 break;
845 case OBJECT_DOMAIN:
846 case OBJECT_TYPE:
847 world_default = ACL_USAGE;
848 owner_default = ACL_ALL_RIGHTS_TYPE;
849 break;
850 case OBJECT_PARAMETER_ACL:
851 world_default = ACL_NO_RIGHTS;
852 owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
853 break;
854 default:
855 elog(ERROR, "unrecognized object type: %d", (int) objtype);
856 world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
857 owner_default = ACL_NO_RIGHTS;
858 break;
861 nacl = 0;
862 if (world_default != ACL_NO_RIGHTS)
863 nacl++;
864 if (owner_default != ACL_NO_RIGHTS)
865 nacl++;
867 acl = allocacl(nacl);
868 aip = ACL_DAT(acl);
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);
875 aip++;
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);
895 return acl;
900 * SQL-accessible version of acldefault(). Hackish mapping from "char" type to
901 * OBJECT_* values.
903 Datum
904 acldefault_sql(PG_FUNCTION_ARGS)
906 char objtypec = PG_GETARG_CHAR(0);
907 Oid owner = PG_GETARG_OID(1);
908 ObjectType objtype = 0;
910 switch (objtypec)
912 case 'c':
913 objtype = OBJECT_COLUMN;
914 break;
915 case 'r':
916 objtype = OBJECT_TABLE;
917 break;
918 case 's':
919 objtype = OBJECT_SEQUENCE;
920 break;
921 case 'd':
922 objtype = OBJECT_DATABASE;
923 break;
924 case 'f':
925 objtype = OBJECT_FUNCTION;
926 break;
927 case 'l':
928 objtype = OBJECT_LANGUAGE;
929 break;
930 case 'L':
931 objtype = OBJECT_LARGEOBJECT;
932 break;
933 case 'n':
934 objtype = OBJECT_SCHEMA;
935 break;
936 case 'p':
937 objtype = OBJECT_PARAMETER_ACL;
938 break;
939 case 't':
940 objtype = OBJECT_TABLESPACE;
941 break;
942 case 'F':
943 objtype = OBJECT_FDW;
944 break;
945 case 'S':
946 objtype = OBJECT_FOREIGN_SERVER;
947 break;
948 case 'T':
949 objtype = OBJECT_TYPE;
950 break;
951 default:
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.
975 Acl *
976 aclupdate(const Acl *old_acl, const AclItem *mod_aip,
977 int modechg, Oid ownerId, DropBehavior behavior)
979 Acl *new_acl = NULL;
980 AclItem *old_aip,
981 *new_aip = NULL;
982 AclMode old_rights,
983 old_goptions,
984 new_rights,
985 new_goptions;
986 int dst,
987 num;
989 /* Caller probably already checked old_acl, but be safe */
990 check_acl(old_acl);
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
1004 * the end.
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));
1015 break;
1019 if (dst == num)
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 */
1038 switch (modechg)
1040 case ACL_MODECHG_ADD:
1041 ACLITEM_SET_RIGHTS(new_aip[dst],
1042 old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
1043 break;
1044 case ACL_MODECHG_DEL:
1045 ACLITEM_SET_RIGHTS(new_aip[dst],
1046 old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
1047 break;
1048 case ACL_MODECHG_EQL:
1049 ACLITEM_SET_RIGHTS(new_aip[dst],
1050 ACLITEM_GET_RIGHTS(*mod_aip));
1051 break;
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,
1063 new_aip + dst + 1,
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),
1079 ownerId, behavior);
1082 return new_acl;
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.
1102 Acl *
1103 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
1105 Acl *new_acl;
1106 AclItem *new_aip;
1107 AclItem *old_aip;
1108 AclItem *dst_aip;
1109 AclItem *src_aip;
1110 AclItem *targ_aip;
1111 bool newpresent = false;
1112 int dst,
1113 src,
1114 targ,
1115 num;
1117 check_acl(old_acl);
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)
1134 newpresent = true;
1135 if (dst_aip->ai_grantee == oldOwnerId)
1136 dst_aip->ai_grantee = newOwnerId;
1137 else if (dst_aip->ai_grantee == newOwnerId)
1138 newpresent = true;
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.
1157 if (newpresent)
1159 dst = 0;
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)
1164 continue;
1165 /* find and merge any duplicates */
1166 for (src = targ + 1, src_aip = targ_aip + 1; src < num;
1167 src++, src_aip++)
1169 if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
1170 continue;
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;
1182 dst++;
1184 /* Adjust array size to be 'dst' items */
1185 ARR_DIMS(new_acl)[0] = dst;
1186 SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
1189 return new_acl;
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.
1205 static void
1206 check_circularity(const Acl *old_acl, const AclItem *mod_aip,
1207 Oid ownerId)
1209 Acl *acl;
1210 AclItem *aip;
1211 int i,
1212 num;
1213 AclMode own_privs;
1215 check_acl(old_acl);
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)
1225 return;
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 */
1232 cc_restart:
1233 num = ACL_NUM(acl);
1234 aip = ACL_DAT(acl);
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)
1240 Acl *new_acl;
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);
1246 pfree(acl);
1247 acl = new_acl;
1249 goto cc_restart;
1253 /* Now we can compute grantor's independently-derived privileges */
1254 own_privs = aclmask(acl,
1255 mod_aip->ai_grantor,
1256 ownerId,
1257 ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
1258 ACLMASK_ALL);
1259 own_privs = ACL_OPTION_TO_PRIVS(own_privs);
1261 if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
1262 ereport(ERROR,
1263 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1264 errmsg("grant options cannot be granted back to your own grantor")));
1266 pfree(acl);
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.
1285 static Acl *
1286 recursive_revoke(Acl *acl,
1287 Oid grantee,
1288 AclMode revoke_privs,
1289 Oid ownerId,
1290 DropBehavior behavior)
1292 AclMode still_has;
1293 AclItem *aip;
1294 int i,
1295 num;
1297 check_acl(acl);
1299 /* The owner can never truly lose grant options, so short-circuit */
1300 if (grantee == ownerId)
1301 return acl;
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),
1306 ACLMASK_ALL);
1307 revoke_privs &= ~ACL_OPTION_TO_PRIVS(still_has);
1308 if (revoke_privs == ACL_NO_RIGHTS)
1309 return acl;
1311 restart:
1312 num = ACL_NUM(acl);
1313 aip = ACL_DAT(acl);
1314 for (i = 0; i < num; i++)
1316 if (aip[i].ai_grantor == grantee
1317 && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1319 AclItem mod_acl;
1320 Acl *new_acl;
1322 if (behavior == DROP_RESTRICT)
1323 ereport(ERROR,
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,
1331 revoke_privs,
1332 revoke_privs);
1334 new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1335 ownerId, behavior);
1337 pfree(acl);
1338 acl = new_acl;
1340 goto restart;
1344 return acl;
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.)
1360 * Usage patterns:
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);
1371 AclMode
1372 aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1373 AclMode mask, AclMaskHow how)
1375 AclMode result;
1376 AclMode remaining;
1377 AclItem *aidat;
1378 int i,
1379 num;
1382 * Null ACL should not happen, since caller should have inserted
1383 * appropriate default
1385 if (acl == NULL)
1386 elog(ERROR, "null ACL");
1388 check_acl(acl);
1390 /* Quick exit for mask == 0 */
1391 if (mask == 0)
1392 return 0;
1394 result = 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))
1402 return result;
1405 num = ACL_NUM(acl);
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))
1420 return result;
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
1429 * test.
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))
1445 return result;
1446 remaining = mask & ~result;
1450 return 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.
1460 static AclMode
1461 aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1462 AclMode mask, AclMaskHow how)
1464 AclMode result;
1465 AclItem *aidat;
1466 int i,
1467 num;
1470 * Null ACL should not happen, since caller should have inserted
1471 * appropriate default
1473 if (acl == NULL)
1474 elog(ERROR, "null ACL");
1476 check_acl(acl);
1478 /* Quick exit for mask == 0 */
1479 if (mask == 0)
1480 return 0;
1482 result = 0;
1484 /* Owner always implicitly has all grant options */
1485 if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1486 roleid == ownerId)
1488 result = mask & ACLITEM_ALL_GOPTION_BITS;
1489 if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1490 return result;
1493 num = ACL_NUM(acl);
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))
1507 return result;
1511 return result;
1516 * aclmembers
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)
1526 Oid *list;
1527 const AclItem *acldat;
1528 int i,
1531 if (acl == NULL || ACL_NUM(acl) == 0)
1533 *roleids = NULL;
1534 return 0;
1537 check_acl(acl);
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.
1546 j = 0;
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.
1565 *roleids = list;
1567 /* Remove duplicates from the array */
1568 return qunique(list, j, sizeof(Oid), oid_cmp);
1573 * aclinsert (exported function)
1575 Datum
1576 aclinsert(PG_FUNCTION_ARGS)
1578 ereport(ERROR,
1579 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1580 errmsg("aclinsert is no longer supported")));
1582 PG_RETURN_NULL(); /* keep compiler quiet */
1585 Datum
1586 aclremove(PG_FUNCTION_ARGS)
1588 ereport(ERROR,
1589 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1590 errmsg("aclremove is no longer supported")));
1592 PG_RETURN_NULL(); /* keep compiler quiet */
1595 Datum
1596 aclcontains(PG_FUNCTION_ARGS)
1598 Acl *acl = PG_GETARG_ACL_P(0);
1599 AclItem *aip = PG_GETARG_ACLITEM_P(1);
1600 AclItem *aidat;
1601 int i,
1602 num;
1604 check_acl(acl);
1605 num = ACL_NUM(acl);
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);
1617 Datum
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);
1624 AclItem *result;
1625 AclMode priv;
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},
1640 {"SET", ACL_SET},
1641 {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
1642 {"MAINTAIN", ACL_MAINTAIN},
1643 {NULL, 0}
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.
1669 static AclMode
1670 convert_any_priv_string(text *priv_type_text,
1671 const priv_map *privileges)
1673 AclMode result = 0;
1674 char *priv_type = text_to_cstring(priv_type_text);
1675 char *chunk;
1676 char *next_chunk;
1678 /* We rely on priv_type being a private, modifiable string */
1679 for (chunk = priv_type; chunk; chunk = next_chunk)
1681 int chunk_len;
1682 const priv_map *this_priv;
1684 /* Split string at commas */
1685 next_chunk = strchr(chunk, ',');
1686 if (next_chunk)
1687 *next_chunk++ = '\0';
1689 /* Drop leading/trailing whitespace in this chunk */
1690 while (*chunk && isspace((unsigned char) *chunk))
1691 chunk++;
1692 chunk_len = strlen(chunk);
1693 while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
1694 chunk_len--;
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;
1703 break;
1706 if (!this_priv->name)
1707 ereport(ERROR,
1708 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1709 errmsg("unrecognized privilege type: \"%s\"", chunk)));
1712 pfree(priv_type);
1713 return result;
1717 static const char *
1718 convert_aclright_to_string(int aclright)
1720 switch (aclright)
1722 case ACL_INSERT:
1723 return "INSERT";
1724 case ACL_SELECT:
1725 return "SELECT";
1726 case ACL_UPDATE:
1727 return "UPDATE";
1728 case ACL_DELETE:
1729 return "DELETE";
1730 case ACL_TRUNCATE:
1731 return "TRUNCATE";
1732 case ACL_REFERENCES:
1733 return "REFERENCES";
1734 case ACL_TRIGGER:
1735 return "TRIGGER";
1736 case ACL_EXECUTE:
1737 return "EXECUTE";
1738 case ACL_USAGE:
1739 return "USAGE";
1740 case ACL_CREATE:
1741 return "CREATE";
1742 case ACL_CREATE_TEMP:
1743 return "TEMPORARY";
1744 case ACL_CONNECT:
1745 return "CONNECT";
1746 case ACL_SET:
1747 return "SET";
1748 case ACL_ALTER_SYSTEM:
1749 return "ALTER SYSTEM";
1750 case ACL_MAINTAIN:
1751 return "MAINTAIN";
1752 default:
1753 elog(ERROR, "unrecognized aclright: %d", aclright);
1754 return NULL;
1759 /*----------
1760 * Convert an aclitem[] to a table.
1762 * Example:
1764 * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
1766 * returns the table
1768 * {{ OID(joe), 0::OID, 'SELECT', false },
1769 * { OID(joe), OID(foo), 'INSERT', true },
1770 * { OID(joe), OID(foo), 'UPDATE', false }}
1771 *----------
1773 Datum
1774 aclexplode(PG_FUNCTION_ARGS)
1776 Acl *acl = PG_GETARG_ACL_P(0);
1777 FuncCallContext *funcctx;
1778 int *idx;
1779 AclItem *aidat;
1781 if (SRF_IS_FIRSTCALL())
1783 TupleDesc tupdesc;
1784 MemoryContext oldcontext;
1786 check_acl(acl);
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
1793 * entry)
1795 tupdesc = CreateTemplateTupleDesc(4);
1796 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
1797 OIDOID, -1, 0);
1798 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
1799 OIDOID, -1, 0);
1800 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
1801 TEXTOID, -1, 0);
1802 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
1803 BOOLOID, -1, 0);
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))
1823 AclItem *aidata;
1824 AclMode priv_bit;
1826 idx[1]++;
1827 if (idx[1] == N_ACL_RIGHTS)
1829 idx[1] = 0;
1830 idx[0]++;
1831 if (idx[0] >= ACL_NUM(acl)) /* done */
1832 break;
1834 aidata = &aidat[idx[0]];
1835 priv_bit = UINT64CONST(1) << idx[1];
1837 if (ACLITEM_GET_PRIVS(*aidata) & priv_bit)
1839 Datum result;
1840 Datum values[4];
1841 bool nulls[4] = {0};
1842 HeapTuple tuple;
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.
1877 Datum
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);
1883 Oid roleid;
1884 Oid tableoid;
1885 AclMode mode;
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
1903 Datum
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);
1908 Oid roleid;
1909 Oid tableoid;
1910 AclMode mode;
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.
1927 Datum
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);
1933 Oid roleid;
1934 AclMode mode;
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);
1943 if (is_missing)
1944 PG_RETURN_NULL();
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
1955 Datum
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);
1960 Oid roleid;
1961 AclMode mode;
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);
1970 if (is_missing)
1971 PG_RETURN_NULL();
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.
1981 Datum
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);
1987 Oid tableoid;
1988 AclMode mode;
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.
2004 Datum
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);
2010 AclMode mode;
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);
2018 if (is_missing)
2019 PG_RETURN_NULL();
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
2031 static Oid
2032 convert_table_name(text *tablename)
2034 RangeVar *relrv;
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.
2046 static AclMode
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)},
2066 {NULL, 0}
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.
2088 Datum
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);
2094 Oid roleid;
2095 Oid sequenceoid;
2096 AclMode mode;
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)
2103 ereport(ERROR,
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
2119 Datum
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);
2124 Oid roleid;
2125 Oid sequenceoid;
2126 AclMode mode;
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)
2133 ereport(ERROR,
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.
2148 Datum
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);
2154 Oid roleid;
2155 AclMode mode;
2156 AclResult aclresult;
2157 char relkind;
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')
2164 PG_RETURN_NULL();
2165 else if (relkind != RELKIND_SEQUENCE)
2166 ereport(ERROR,
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);
2173 if (is_missing)
2174 PG_RETURN_NULL();
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
2185 Datum
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);
2190 Oid roleid;
2191 AclMode mode;
2192 AclResult aclresult;
2193 char relkind;
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')
2200 PG_RETURN_NULL();
2201 else if (relkind != RELKIND_SEQUENCE)
2202 ereport(ERROR,
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);
2209 if (is_missing)
2210 PG_RETURN_NULL();
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.
2220 Datum
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);
2226 Oid sequenceoid;
2227 AclMode mode;
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)
2233 ereport(ERROR,
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.
2248 Datum
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);
2254 AclMode mode;
2255 AclResult aclresult;
2256 char relkind;
2257 bool is_missing = false;
2259 mode = convert_sequence_priv_string(priv_type_text);
2260 relkind = get_rel_relkind(sequenceoid);
2261 if (relkind == '\0')
2262 PG_RETURN_NULL();
2263 else if (relkind != RELKIND_SEQUENCE)
2264 ereport(ERROR,
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);
2271 if (is_missing)
2272 PG_RETURN_NULL();
2274 PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2278 * convert_sequence_priv_string
2279 * Convert text string to AclMode value.
2281 static AclMode
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)},
2291 {NULL, 0}
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.
2314 Datum
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);
2320 Oid roleid;
2321 Oid tableoid;
2322 AclMode mode;
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,
2333 ACLMASK_ANY);
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
2344 Datum
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);
2349 Oid roleid;
2350 Oid tableoid;
2351 AclMode mode;
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,
2362 ACLMASK_ANY);
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.
2372 Datum
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);
2378 Oid roleid;
2379 AclMode mode;
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)
2390 if (is_missing)
2391 PG_RETURN_NULL();
2392 aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2393 ACLMASK_ANY, &is_missing);
2394 if (is_missing)
2395 PG_RETURN_NULL();
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
2407 Datum
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);
2412 Oid roleid;
2413 AclMode mode;
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)
2424 if (is_missing)
2425 PG_RETURN_NULL();
2426 aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2427 ACLMASK_ANY, &is_missing);
2428 if (is_missing)
2429 PG_RETURN_NULL();
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.
2440 Datum
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);
2446 Oid tableoid;
2447 AclMode mode;
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,
2457 ACLMASK_ANY);
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.
2467 Datum
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);
2473 AclMode mode;
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)
2483 if (is_missing)
2484 PG_RETURN_NULL();
2485 aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2486 ACLMASK_ANY, &is_missing);
2487 if (is_missing)
2488 PG_RETURN_NULL();
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.
2518 static int
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)
2529 return -1;
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,
2537 mode, &is_missing);
2538 if (aclresult == ACLCHECK_OK)
2539 return 1;
2540 else if (is_missing)
2541 return -1;
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)
2546 return 1;
2547 else if (is_missing)
2548 return -1;
2549 else
2550 return 0;
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.
2558 Datum
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);
2565 Oid roleid;
2566 Oid tableoid;
2567 AttrNumber colattnum;
2568 AclMode mode;
2569 int privresult;
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);
2577 if (privresult < 0)
2578 PG_RETURN_NULL();
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.
2587 Datum
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);
2594 Oid roleid;
2595 Oid tableoid;
2596 AclMode mode;
2597 int privresult;
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);
2604 if (privresult < 0)
2605 PG_RETURN_NULL();
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.
2614 Datum
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);
2621 Oid roleid;
2622 AttrNumber colattnum;
2623 AclMode mode;
2624 int privresult;
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);
2631 if (privresult < 0)
2632 PG_RETURN_NULL();
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.
2641 Datum
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);
2648 Oid roleid;
2649 AclMode mode;
2650 int privresult;
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);
2656 if (privresult < 0)
2657 PG_RETURN_NULL();
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.
2666 Datum
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);
2673 Oid tableoid;
2674 AttrNumber colattnum;
2675 AclMode mode;
2676 int privresult;
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);
2683 if (privresult < 0)
2684 PG_RETURN_NULL();
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.
2693 Datum
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);
2700 Oid tableoid;
2701 AclMode mode;
2702 int privresult;
2704 tableoid = convert_table_name(tablename);
2705 mode = convert_column_priv_string(priv_type_text);
2707 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2708 if (privresult < 0)
2709 PG_RETURN_NULL();
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.
2718 Datum
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;
2726 AclMode mode;
2727 int privresult;
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);
2733 if (privresult < 0)
2734 PG_RETURN_NULL();
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.
2743 Datum
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);
2750 AclMode mode;
2751 int privresult;
2753 mode = convert_column_priv_string(priv_type_text);
2755 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2756 if (privresult < 0)
2757 PG_RETURN_NULL();
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
2767 Datum
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);
2773 Oid roleid;
2774 Oid tableoid;
2775 AttrNumber colattnum;
2776 AclMode mode;
2777 int privresult;
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);
2785 if (privresult < 0)
2786 PG_RETURN_NULL();
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
2796 Datum
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);
2802 Oid roleid;
2803 Oid tableoid;
2804 AclMode mode;
2805 int privresult;
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);
2812 if (privresult < 0)
2813 PG_RETURN_NULL();
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
2823 Datum
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);
2829 Oid roleid;
2830 AttrNumber colattnum;
2831 AclMode mode;
2832 int privresult;
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);
2839 if (privresult < 0)
2840 PG_RETURN_NULL();
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
2850 Datum
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);
2856 Oid roleid;
2857 AclMode mode;
2858 int privresult;
2860 roleid = GetUserId();
2861 mode = convert_column_priv_string(priv_type_text);
2863 privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2864 if (privresult < 0)
2865 PG_RETURN_NULL();
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.
2878 static AttrNumber
2879 convert_column_name(Oid tableoid, text *column)
2881 char *colname;
2882 HeapTuple attTuple;
2883 AttrNumber attnum;
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;
2903 else
2904 attnum = attributeForm->attnum;
2905 ReleaseSysCache(attTuple);
2907 else
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 */
2919 ereport(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;
2928 pfree(colname);
2929 return attnum;
2933 * convert_column_priv_string
2934 * Convert text string to AclMode value.
2936 static AclMode
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)},
2948 {NULL, 0}
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.
2970 Datum
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);
2976 Oid roleid;
2977 Oid databaseoid;
2978 AclMode mode;
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
2996 Datum
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);
3001 Oid roleid;
3002 Oid databaseoid;
3003 AclMode mode;
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.
3020 Datum
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);
3026 Oid roleid;
3027 AclMode mode;
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,
3035 roleid, mode,
3036 &is_missing);
3038 if (is_missing)
3039 PG_RETURN_NULL();
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
3050 Datum
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);
3055 Oid roleid;
3056 AclMode mode;
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,
3064 roleid, mode,
3065 &is_missing);
3067 if (is_missing)
3068 PG_RETURN_NULL();
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.
3078 Datum
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);
3084 Oid databaseoid;
3085 AclMode mode;
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.
3101 Datum
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);
3107 AclMode mode;
3108 AclResult aclresult;
3109 bool is_missing = false;
3111 mode = convert_database_priv_string(priv_type_text);
3113 aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3114 roleid, mode,
3115 &is_missing);
3117 if (is_missing)
3118 PG_RETURN_NULL();
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
3130 static 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.
3142 static AclMode
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)},
3154 {NULL, 0}
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.
3176 Datum
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);
3182 Oid roleid;
3183 Oid fdwid;
3184 AclMode mode;
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
3202 Datum
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);
3207 Oid roleid;
3208 Oid fdwid;
3209 AclMode mode;
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.
3226 Datum
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);
3232 Oid roleid;
3233 AclMode mode;
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,
3241 roleid, mode,
3242 &is_missing);
3244 if (is_missing)
3245 PG_RETURN_NULL();
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
3256 Datum
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);
3261 Oid roleid;
3262 AclMode mode;
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,
3270 roleid, mode,
3271 &is_missing);
3273 if (is_missing)
3274 PG_RETURN_NULL();
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.
3284 Datum
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);
3290 Oid fdwid;
3291 AclMode mode;
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.
3307 Datum
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);
3313 AclMode mode;
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,
3320 roleid, mode,
3321 &is_missing);
3323 if (is_missing)
3324 PG_RETURN_NULL();
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
3336 static 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.
3348 static AclMode
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)},
3354 {NULL, 0}
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.
3376 Datum
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);
3382 Oid roleid;
3383 Oid functionoid;
3384 AclMode mode;
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
3402 Datum
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);
3407 Oid roleid;
3408 Oid functionoid;
3409 AclMode mode;
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.
3426 Datum
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);
3432 Oid roleid;
3433 AclMode mode;
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,
3441 roleid, mode,
3442 &is_missing);
3444 if (is_missing)
3445 PG_RETURN_NULL();
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
3456 Datum
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);
3461 Oid roleid;
3462 AclMode mode;
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,
3470 roleid, mode,
3471 &is_missing);
3473 if (is_missing)
3474 PG_RETURN_NULL();
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.
3484 Datum
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);
3490 Oid functionoid;
3491 AclMode mode;
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.
3507 Datum
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);
3513 AclMode mode;
3514 AclResult aclresult;
3515 bool is_missing = false;
3517 mode = convert_function_priv_string(priv_type_text);
3519 aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3520 roleid, mode,
3521 &is_missing);
3523 if (is_missing)
3524 PG_RETURN_NULL();
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
3536 static Oid
3537 convert_function_name(text *functionname)
3539 char *funcname = text_to_cstring(functionname);
3540 Oid oid;
3542 oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
3543 CStringGetDatum(funcname)));
3545 if (!OidIsValid(oid))
3546 ereport(ERROR,
3547 (errcode(ERRCODE_UNDEFINED_FUNCTION),
3548 errmsg("function \"%s\" does not exist", funcname)));
3550 return oid;
3554 * convert_function_priv_string
3555 * Convert text string to AclMode value.
3557 static AclMode
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)},
3563 {NULL, 0}
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.
3585 Datum
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);
3591 Oid roleid;
3592 Oid languageoid;
3593 AclMode mode;
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
3611 Datum
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);
3616 Oid roleid;
3617 Oid languageoid;
3618 AclMode mode;
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.
3635 Datum
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);
3641 Oid roleid;
3642 AclMode mode;
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,
3650 roleid, mode,
3651 &is_missing);
3653 if (is_missing)
3654 PG_RETURN_NULL();
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
3665 Datum
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);
3670 Oid roleid;
3671 AclMode mode;
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,
3679 roleid, mode,
3680 &is_missing);
3682 if (is_missing)
3683 PG_RETURN_NULL();
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.
3693 Datum
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);
3699 Oid languageoid;
3700 AclMode mode;
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.
3716 Datum
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);
3722 AclMode mode;
3723 AclResult aclresult;
3724 bool is_missing = false;
3726 mode = convert_language_priv_string(priv_type_text);
3728 aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3729 roleid, mode,
3730 &is_missing);
3732 if (is_missing)
3733 PG_RETURN_NULL();
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
3745 static 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.
3757 static AclMode
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)},
3763 {NULL, 0}
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.
3785 Datum
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);
3791 Oid roleid;
3792 Oid schemaoid;
3793 AclMode mode;
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
3811 Datum
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);
3816 Oid roleid;
3817 Oid schemaoid;
3818 AclMode mode;
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.
3835 Datum
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);
3841 Oid roleid;
3842 AclMode mode;
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,
3850 roleid, mode,
3851 &is_missing);
3853 if (is_missing)
3854 PG_RETURN_NULL();
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
3865 Datum
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);
3870 Oid roleid;
3871 AclMode mode;
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,
3879 roleid, mode,
3880 &is_missing);
3882 if (is_missing)
3883 PG_RETURN_NULL();
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.
3893 Datum
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);
3899 Oid schemaoid;
3900 AclMode mode;
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.
3916 Datum
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);
3922 AclMode mode;
3923 AclResult aclresult;
3924 bool is_missing = false;
3926 mode = convert_schema_priv_string(priv_type_text);
3928 aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3929 roleid, mode,
3930 &is_missing);
3932 if (is_missing)
3933 PG_RETURN_NULL();
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
3945 static 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.
3957 static AclMode
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)},
3965 {NULL, 0}
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.
3987 Datum
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);
3993 Oid roleid;
3994 Oid serverid;
3995 AclMode mode;
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
4013 Datum
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);
4018 Oid roleid;
4019 Oid serverid;
4020 AclMode mode;
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.
4037 Datum
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);
4043 Oid roleid;
4044 AclMode mode;
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,
4052 roleid, mode,
4053 &is_missing);
4055 if (is_missing)
4056 PG_RETURN_NULL();
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
4067 Datum
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);
4072 Oid roleid;
4073 AclMode mode;
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,
4081 roleid, mode,
4082 &is_missing);
4084 if (is_missing)
4085 PG_RETURN_NULL();
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.
4095 Datum
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);
4101 Oid serverid;
4102 AclMode mode;
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.
4118 Datum
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);
4124 AclMode mode;
4125 AclResult aclresult;
4126 bool is_missing = false;
4128 mode = convert_server_priv_string(priv_type_text);
4130 aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4131 roleid, mode,
4132 &is_missing);
4134 if (is_missing)
4135 PG_RETURN_NULL();
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
4147 static 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.
4159 static AclMode
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)},
4165 {NULL, 0}
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.
4187 Datum
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);
4193 Oid roleid;
4194 Oid tablespaceoid;
4195 AclMode mode;
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
4213 Datum
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);
4218 Oid roleid;
4219 Oid tablespaceoid;
4220 AclMode mode;
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.
4237 Datum
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);
4243 Oid roleid;
4244 AclMode mode;
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,
4252 roleid, mode,
4253 &is_missing);
4255 if (is_missing)
4256 PG_RETURN_NULL();
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
4267 Datum
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);
4272 Oid roleid;
4273 AclMode mode;
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,
4281 roleid, mode,
4282 &is_missing);
4284 if (is_missing)
4285 PG_RETURN_NULL();
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.
4295 Datum
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);
4301 Oid tablespaceoid;
4302 AclMode mode;
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.
4318 Datum
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);
4324 AclMode mode;
4325 AclResult aclresult;
4326 bool is_missing = false;
4328 mode = convert_tablespace_priv_string(priv_type_text);
4330 aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4331 roleid, mode,
4332 &is_missing);
4334 if (is_missing)
4335 PG_RETURN_NULL();
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
4347 static 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.
4359 static AclMode
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)},
4365 {NULL, 0}
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.
4386 Datum
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);
4392 Oid roleid;
4393 Oid typeoid;
4394 AclMode mode;
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
4412 Datum
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);
4417 Oid roleid;
4418 Oid typeoid;
4419 AclMode mode;
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.
4436 Datum
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);
4442 Oid roleid;
4443 AclMode mode;
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,
4451 roleid, mode,
4452 &is_missing);
4454 if (is_missing)
4455 PG_RETURN_NULL();
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
4466 Datum
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);
4471 Oid roleid;
4472 AclMode mode;
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,
4480 roleid, mode,
4481 &is_missing);
4483 if (is_missing)
4484 PG_RETURN_NULL();
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.
4494 Datum
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);
4500 Oid typeoid;
4501 AclMode mode;
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.
4517 Datum
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);
4523 AclMode mode;
4524 AclResult aclresult;
4525 bool is_missing = false;
4527 mode = convert_type_priv_string(priv_type_text);
4529 aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4530 roleid, mode,
4531 &is_missing);
4533 if (is_missing)
4534 PG_RETURN_NULL();
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
4546 static Oid
4547 convert_type_name(text *typename)
4549 char *typname = text_to_cstring(typename);
4550 Oid oid;
4552 oid = DatumGetObjectId(DirectFunctionCall1(regtypein,
4553 CStringGetDatum(typname)));
4555 if (!OidIsValid(oid))
4556 ereport(ERROR,
4557 (errcode(ERRCODE_UNDEFINED_OBJECT),
4558 errmsg("type \"%s\" does not exist", typname)));
4560 return oid;
4564 * convert_type_priv_string
4565 * Convert text string to AclMode value.
4567 static AclMode
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)},
4573 {NULL, 0}
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.
4595 static bool
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.
4608 Datum
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
4624 Datum
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
4636 * text priv name.
4638 Datum
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.
4656 static AclMode
4657 convert_parameter_priv_string(text *priv_text)
4659 static const priv_map parameter_priv_map[] = {
4660 {"SET", ACL_SET},
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)},
4664 {NULL, 0}
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.
4681 * has_lo_priv_byid
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.
4686 static bool
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)
4693 snapshot = NULL;
4694 else
4695 snapshot = GetActiveSnapshot();
4697 if (!LargeObjectExistsWithSnapshot(lobjId, snapshot))
4699 Assert(is_missing != NULL);
4700 *is_missing = true;
4701 return false;
4704 if (lo_compat_privileges)
4705 return true;
4707 aclresult = pg_largeobject_aclcheck_snapshot(lobjId,
4708 roleid,
4709 priv,
4710 snapshot);
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.
4719 Datum
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);
4726 AclMode mode;
4727 bool is_missing = false;
4728 bool result;
4730 mode = convert_largeobject_priv_string(priv_type_text);
4731 result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4733 if (is_missing)
4734 PG_RETURN_NULL();
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
4745 Datum
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);
4751 AclMode mode;
4752 bool is_missing = false;
4753 bool result;
4755 mode = convert_largeobject_priv_string(priv_type_text);
4756 result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4758 if (is_missing)
4759 PG_RETURN_NULL();
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.
4769 Datum
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);
4775 AclMode mode;
4776 bool is_missing = false;
4777 bool result;
4779 mode = convert_largeobject_priv_string(priv_type_text);
4780 result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4782 if (is_missing)
4783 PG_RETURN_NULL();
4785 PG_RETURN_BOOL(result);
4789 * convert_largeobject_priv_string
4790 * Convert text string to AclMode value.
4792 static AclMode
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)},
4800 {NULL, 0}
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.
4821 Datum
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);
4827 Oid roleid;
4828 Oid roleoid;
4829 AclMode mode;
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);
4842 * pg_has_role_name
4843 * Check user privileges on a role given
4844 * name rolename and text priv name.
4845 * current_user is assumed
4847 Datum
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);
4852 Oid roleid;
4853 Oid roleoid;
4854 AclMode mode;
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.
4871 Datum
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);
4877 Oid roleid;
4878 AclMode mode;
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);
4890 * pg_has_role_id
4891 * Check user privileges on a role given
4892 * role oid, and text priv name.
4893 * current_user is assumed
4895 Datum
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);
4900 Oid roleid;
4901 AclMode mode;
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.
4917 Datum
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);
4923 Oid roleoid;
4924 AclMode mode;
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);
4936 * pg_has_role_id_id
4937 * Check user privileges on a role given
4938 * roleid, role oid, and text priv name.
4940 Datum
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);
4946 AclMode mode;
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.
4970 static AclMode
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},
4976 {"SET", ACL_SET},
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)},
4983 {NULL, 0}
4986 return convert_any_priv_string(priv_type_text, role_priv_map);
4990 * pg_role_aclcheck
4991 * Quick-and-dirty support for pg_has_role
4993 static AclResult
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))
4999 return ACLCHECK_OK;
5001 if (mode & ACL_CREATE)
5003 if (is_member_of_role(roleid, role_oid))
5004 return ACLCHECK_OK;
5006 if (mode & ACL_USAGE)
5008 if (has_privs_of_role(roleid, role_oid))
5009 return ACLCHECK_OK;
5011 if (mode & ACL_SET)
5013 if (member_can_set_role(roleid, role_oid))
5014 return ACLCHECK_OK;
5016 return ACLCHECK_NO_PRIV;
5021 * initialization function (called by InitPostgres)
5023 void
5024 initialize_acl(void)
5026 if (!IsBootstrapProcessingMode())
5028 cached_db_hash =
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,
5039 (Datum) 0);
5040 CacheRegisterSyscacheCallback(AUTHOID,
5041 RoleMembershipCacheCallback,
5042 (Datum) 0);
5043 CacheRegisterSyscacheCallback(DATABASEOID,
5044 RoleMembershipCacheCallback,
5045 (Datum) 0);
5050 * RoleMembershipCacheCallback
5051 * Syscache inval callback function
5053 static void
5054 RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
5056 if (cacheid == DATABASEOID &&
5057 hashvalue != cached_db_hash &&
5058 hashvalue != 0)
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
5086 * existing list.
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
5094 * function.
5096 if (*bf == NULL &&
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
5106 * exists.
5108 roles_list = lappend_oid(roles_list, role);
5109 if (*bf)
5110 bloom_add_element(*bf, roleptr, sizeof(Oid));
5113 return roles_list;
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.
5135 static List *
5136 roles_is_member_of(Oid roleid, enum RoleRecurseType type,
5137 Oid admin_of, Oid *admin_role)
5139 Oid dba;
5140 List *roles_list;
5141 ListCell *l;
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))
5161 dba = InvalidOid;
5162 else
5164 HeapTuple dbtup;
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
5176 * resulting list.
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);
5189 CatCList *memlist;
5190 int i;
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)
5211 continue;
5213 /* If we're supposed to ignore non-SET grants, do so. */
5214 if (type == ROLERECURSE_SETROLE && !form->set_option)
5215 continue;
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.
5235 if (bf)
5236 bloom_free(bf);
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.
5267 bool
5268 has_privs_of_role(Oid member, Oid role)
5270 /* Fast path for simple case */
5271 if (member == role)
5272 return true;
5274 /* Superusers have every privilege, so are part of every role */
5275 if (superuser_arg(member))
5276 return true;
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,
5283 InvalidOid, NULL),
5284 role);
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.
5301 bool
5302 member_can_set_role(Oid member, Oid role)
5304 /* Fast path for simple case */
5305 if (member == role)
5306 return true;
5308 /* Superusers have every privilege, so can always SET ROLE */
5309 if (superuser_arg(member))
5310 return true;
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,
5317 InvalidOid, NULL),
5318 role);
5322 * Permission violation error unless able to SET ROLE to target role.
5324 void
5325 check_can_set_role(Oid member, Oid role)
5327 if (!member_can_set_role(member, role))
5328 ereport(ERROR,
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.
5347 bool
5348 is_member_of_role(Oid member, Oid role)
5350 /* Fast path for simple case */
5351 if (member == role)
5352 return true;
5354 /* Superusers have every privilege, so are part of every role */
5355 if (superuser_arg(member))
5356 return true;
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,
5363 InvalidOid, NULL),
5364 role);
5368 * Is member a member of role, not considering superuserness?
5370 * This is identical to is_member_of_role except we ignore superuser
5371 * status.
5373 * Do not use this for privilege checking, instead use has_privs_of_role()
5375 bool
5376 is_member_of_role_nosuper(Oid member, Oid role)
5378 /* Fast path for simple case */
5379 if (member == role)
5380 return true;
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,
5387 InvalidOid, NULL),
5388 role);
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,
5395 * or a superuser?
5397 bool
5398 is_admin_of_role(Oid member, Oid role)
5400 Oid admin_role;
5402 if (superuser_arg(member))
5403 return true;
5405 /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5406 if (member == role)
5407 return false;
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)
5425 Oid admin_role;
5427 /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5428 if (member == role)
5429 return InvalidOid;
5431 (void) roles_is_member_of(member, ROLERECURSE_PRIVS, role, &admin_role);
5432 return admin_role;
5436 /* does what it says ... */
5437 static int
5438 count_one_bits(AclMode mask)
5440 int nbits = 0;
5442 /* this code relies on AclMode being an unsigned type */
5443 while (mask)
5445 if (mask & 1)
5446 nbits++;
5447 mask >>= 1;
5449 return nbits;
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.
5477 void
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);
5483 List *roles_list;
5484 int nrights;
5485 ListCell *l;
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
5491 * the object owner.
5493 if (roleId == ownerId || superuser_arg(roleId))
5495 *grantorId = ownerId;
5496 *grantOptions = needed_goptions;
5497 return;
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,
5507 InvalidOid, NULL);
5509 /* initialize candidate result as default */
5510 *grantorId = roleId;
5511 *grantOptions = ACL_NO_RIGHTS;
5512 nrights = 0;
5514 foreach(l, roles_list)
5516 Oid otherrole = lfirst_oid(l);
5517 AclMode otherprivs;
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;
5526 return;
5530 * If it has just some of the needed privileges, remember best
5531 * candidate.
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)
5556 Oid oid;
5558 oid = GetSysCacheOid1(AUTHNAME, Anum_pg_authid_oid,
5559 CStringGetDatum(rolname));
5560 if (!OidIsValid(oid) && !missing_ok)
5561 ereport(ERROR,
5562 (errcode(ERRCODE_UNDEFINED_OBJECT),
5563 errmsg("role \"%s\" does not exist", rolname)));
5564 return oid;
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)
5590 Oid oid;
5592 switch (role->roletype)
5594 case ROLESPEC_CSTRING:
5595 Assert(role->rolename);
5596 oid = get_role_oid(role->rolename, missing_ok);
5597 break;
5599 case ROLESPEC_CURRENT_ROLE:
5600 case ROLESPEC_CURRENT_USER:
5601 oid = GetUserId();
5602 break;
5604 case ROLESPEC_SESSION_USER:
5605 oid = GetSessionUserId();
5606 break;
5608 case ROLESPEC_PUBLIC:
5609 ereport(ERROR,
5610 (errcode(ERRCODE_UNDEFINED_OBJECT),
5611 errmsg("role \"%s\" does not exist", "public")));
5612 oid = InvalidOid; /* make compiler happy */
5613 break;
5615 default:
5616 elog(ERROR, "unexpected role type %d", role->roletype);
5619 return oid;
5623 * Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
5624 * Caller must ReleaseSysCache when done with the result tuple.
5626 HeapTuple
5627 get_rolespec_tuple(const RoleSpec *role)
5629 HeapTuple tuple;
5631 switch (role->roletype)
5633 case ROLESPEC_CSTRING:
5634 Assert(role->rolename);
5635 tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolename));
5636 if (!HeapTupleIsValid(tuple))
5637 ereport(ERROR,
5638 (errcode(ERRCODE_UNDEFINED_OBJECT),
5639 errmsg("role \"%s\" does not exist", role->rolename)));
5640 break;
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());
5647 break;
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());
5653 break;
5655 case ROLESPEC_PUBLIC:
5656 ereport(ERROR,
5657 (errcode(ERRCODE_UNDEFINED_OBJECT),
5658 errmsg("role \"%s\" does not exist", "public")));
5659 tuple = NULL; /* make compiler happy */
5660 break;
5662 default:
5663 elog(ERROR, "unexpected role type %d", role->roletype);
5666 return tuple;
5670 * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
5672 char *
5673 get_rolespec_name(const RoleSpec *role)
5675 HeapTuple tp;
5676 Form_pg_authid authForm;
5677 char *rolename;
5679 tp = get_rolespec_tuple(role);
5680 authForm = (Form_pg_authid) GETSTRUCT(tp);
5681 rolename = pstrdup(NameStr(authForm->rolname));
5682 ReleaseSysCache(tp);
5684 return rolename;
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.
5694 void
5695 check_rolespec_name(const RoleSpec *role, const char *detail_msg)
5697 if (!role)
5698 return;
5700 if (role->roletype != ROLESPEC_CSTRING)
5701 return;
5703 if (IsReservedName(role->rolename))
5705 if (detail_msg)
5706 ereport(ERROR,
5707 (errcode(ERRCODE_RESERVED_NAME),
5708 errmsg("role name \"%s\" is reserved",
5709 role->rolename),
5710 errdetail_internal("%s", detail_msg)));
5711 else
5712 ereport(ERROR,
5713 (errcode(ERRCODE_RESERVED_NAME),
5714 errmsg("role name \"%s\" is reserved",
5715 role->rolename)));