Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * acl.c
4 : * Basic access control list data structures manipulation routines.
5 : *
6 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/utils/adt/acl.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include <ctype.h>
18 :
19 : #include "access/htup_details.h"
20 : #include "bootstrap/bootstrap.h"
21 : #include "catalog/catalog.h"
22 : #include "catalog/namespace.h"
23 : #include "catalog/pg_auth_members.h"
24 : #include "catalog/pg_authid.h"
25 : #include "catalog/pg_class.h"
26 : #include "catalog/pg_database.h"
27 : #include "catalog/pg_foreign_data_wrapper.h"
28 : #include "catalog/pg_foreign_server.h"
29 : #include "catalog/pg_language.h"
30 : #include "catalog/pg_largeobject.h"
31 : #include "catalog/pg_namespace.h"
32 : #include "catalog/pg_proc.h"
33 : #include "catalog/pg_tablespace.h"
34 : #include "catalog/pg_type.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 "port/pg_bitutils.h"
44 : #include "storage/large_object.h"
45 : #include "utils/acl.h"
46 : #include "utils/array.h"
47 : #include "utils/builtins.h"
48 : #include "utils/catcache.h"
49 : #include "utils/inval.h"
50 : #include "utils/lsyscache.h"
51 : #include "utils/memutils.h"
52 : #include "utils/snapmgr.h"
53 : #include "utils/syscache.h"
54 : #include "utils/varlena.h"
55 :
56 : typedef struct
57 : {
58 : const char *name;
59 : AclMode value;
60 : } priv_map;
61 :
62 : /*
63 : * We frequently need to test whether a given role is a member of some other
64 : * role. In most of these tests the "given role" is the same, namely the
65 : * active current user. So we can optimize it by keeping cached lists of all
66 : * the roles the "given role" is a member of, directly or indirectly.
67 : *
68 : * Possibly this mechanism should be generalized to allow caching membership
69 : * info for multiple roles?
70 : *
71 : * Each element of cached_roles is an OID list of constituent roles for the
72 : * corresponding element of cached_role (always including the cached_role
73 : * itself). There's a separate cache for each RoleRecurseType, with the
74 : * corresponding semantics.
75 : */
76 : enum RoleRecurseType
77 : {
78 : ROLERECURSE_MEMBERS = 0, /* recurse unconditionally */
79 : ROLERECURSE_PRIVS = 1, /* recurse through inheritable grants */
80 : ROLERECURSE_SETROLE = 2 /* recurse through grants with set_option */
81 : };
82 : static Oid cached_role[] = {InvalidOid, InvalidOid, InvalidOid};
83 : static List *cached_roles[] = {NIL, NIL, NIL};
84 : static uint32 cached_db_hash;
85 :
86 : /*
87 : * If the list of roles gathered by roles_is_member_of() grows larger than the
88 : * below threshold, a Bloom filter is created to speed up list membership
89 : * checks. This threshold is set arbitrarily high to avoid the overhead of
90 : * creating the Bloom filter until it seems likely to provide a net benefit.
91 : */
92 : #define ROLES_LIST_BLOOM_THRESHOLD 1024
93 :
94 : static const char *getid(const char *s, char *n, Node *escontext);
95 : static void putid(char *p, const char *s);
96 : static Acl *allocacl(int n);
97 : static void check_acl(const Acl *acl);
98 : static const char *aclparse(const char *s, AclItem *aip, Node *escontext);
99 : static bool aclitem_match(const AclItem *a1, const AclItem *a2);
100 : static int aclitemComparator(const void *arg1, const void *arg2);
101 : static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
102 : Oid ownerId);
103 : static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
104 : Oid ownerId, DropBehavior behavior);
105 :
106 : static AclMode convert_any_priv_string(text *priv_type_text,
107 : const priv_map *privileges);
108 :
109 : static Oid convert_table_name(text *tablename);
110 : static AclMode convert_table_priv_string(text *priv_type_text);
111 : static AclMode convert_sequence_priv_string(text *priv_type_text);
112 : static AttrNumber convert_column_name(Oid tableoid, text *column);
113 : static AclMode convert_column_priv_string(text *priv_type_text);
114 : static Oid convert_database_name(text *databasename);
115 : static AclMode convert_database_priv_string(text *priv_type_text);
116 : static Oid convert_foreign_data_wrapper_name(text *fdwname);
117 : static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text);
118 : static Oid convert_function_name(text *functionname);
119 : static AclMode convert_function_priv_string(text *priv_type_text);
120 : static Oid convert_language_name(text *languagename);
121 : static AclMode convert_language_priv_string(text *priv_type_text);
122 : static Oid convert_schema_name(text *schemaname);
123 : static AclMode convert_schema_priv_string(text *priv_type_text);
124 : static Oid convert_server_name(text *servername);
125 : static AclMode convert_server_priv_string(text *priv_type_text);
126 : static Oid convert_tablespace_name(text *tablespacename);
127 : static AclMode convert_tablespace_priv_string(text *priv_type_text);
128 : static Oid convert_type_name(text *typename);
129 : static AclMode convert_type_priv_string(text *priv_type_text);
130 : static AclMode convert_parameter_priv_string(text *priv_text);
131 : static AclMode convert_largeobject_priv_string(text *priv_type_text);
132 : static AclMode convert_role_priv_string(text *priv_type_text);
133 : static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
134 :
135 : static void RoleMembershipCacheCallback(Datum arg, SysCacheIdentifier cacheid,
136 : uint32 hashvalue);
137 :
138 :
139 : /*
140 : * Test whether an identifier char can be left unquoted in ACLs.
141 : *
142 : * Formerly, we used isalnum() even on non-ASCII characters, resulting in
143 : * unportable behavior. To ensure dump compatibility with old versions,
144 : * we now treat high-bit-set characters as always requiring quoting during
145 : * putid(), but getid() will always accept them without quotes.
146 : */
147 : static inline bool
148 9280249 : is_safe_acl_char(unsigned char c, bool is_getid)
149 : {
150 9280249 : if (IS_HIGHBIT_SET(c))
151 0 : return is_getid;
152 9280249 : return isalnum(c) || c == '_';
153 : }
154 :
155 : /*
156 : * getid
157 : * Consumes the first alphanumeric string (identifier) found in string
158 : * 's', ignoring any leading white space. If it finds a double quote
159 : * it returns the word inside the quotes.
160 : *
161 : * RETURNS:
162 : * the string position in 's' that points to the next non-space character
163 : * in 's', after any quotes. Also:
164 : * - loads the identifier into 'n'. (If no identifier is found, 'n'
165 : * contains an empty string.) 'n' must be NAMEDATALEN bytes.
166 : *
167 : * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
168 : * in which case we log the error there and return NULL.
169 : */
170 : static const char *
171 5027 : getid(const char *s, char *n, Node *escontext)
172 : {
173 5027 : int len = 0;
174 5027 : bool in_quotes = false;
175 :
176 : Assert(s && n);
177 :
178 5027 : while (isspace((unsigned char) *s))
179 0 : s++;
180 5027 : for (;
181 49108 : *s != '\0' &&
182 48390 : (in_quotes || *s == '"' || is_safe_acl_char(*s, true));
183 44081 : s++)
184 : {
185 44081 : if (*s == '"')
186 : {
187 150 : if (!in_quotes)
188 : {
189 71 : in_quotes = true;
190 71 : continue;
191 : }
192 : /* safe to look at next char (could be '\0' though) */
193 79 : if (*(s + 1) != '"')
194 : {
195 71 : in_quotes = false;
196 71 : continue;
197 : }
198 : /* it's an escaped double quote; skip the escaping char */
199 8 : s++;
200 : }
201 :
202 : /* Add the character to the string */
203 43939 : if (len >= NAMEDATALEN - 1)
204 0 : ereturn(escontext, NULL,
205 : (errcode(ERRCODE_NAME_TOO_LONG),
206 : errmsg("identifier too long"),
207 : errdetail("Identifier must be less than %d characters.",
208 : NAMEDATALEN)));
209 :
210 43939 : n[len++] = *s;
211 : }
212 5027 : n[len] = '\0';
213 5027 : while (isspace((unsigned char) *s))
214 0 : s++;
215 5027 : return s;
216 : }
217 :
218 : /*
219 : * Write a role name at *p, adding double quotes if needed.
220 : * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
221 : * This needs to be kept in sync with dequoteAclUserName in pg_dump/dumputils.c
222 : */
223 : static void
224 1115210 : putid(char *p, const char *s)
225 : {
226 : const char *src;
227 1115210 : bool safe = true;
228 :
229 : /* Detect whether we need to use double quotes */
230 10346933 : for (src = s; *src; src++)
231 : {
232 9231930 : if (!is_safe_acl_char(*src, false))
233 : {
234 207 : safe = false;
235 207 : break;
236 : }
237 : }
238 1115210 : if (!safe)
239 207 : *p++ = '"';
240 10348764 : for (src = s; *src; src++)
241 : {
242 : /* A double quote character in a username is encoded as "" */
243 9233554 : if (*src == '"')
244 207 : *p++ = '"';
245 9233554 : *p++ = *src;
246 : }
247 1115210 : if (!safe)
248 207 : *p++ = '"';
249 1115210 : *p = '\0';
250 1115210 : }
251 :
252 : /*
253 : * aclparse
254 : * Consumes and parses an ACL specification of the form:
255 : * [group|user] [A-Za-z0-9]*=[rwaR]*
256 : * from string 's', ignoring any leading white space or white space
257 : * between the optional id type keyword (group|user) and the actual
258 : * ACL specification.
259 : *
260 : * The group|user decoration is unnecessary in the roles world,
261 : * but we still accept it for backward compatibility.
262 : *
263 : * This routine is called by the parser as well as aclitemin(), hence
264 : * the added generality.
265 : *
266 : * In bootstrap mode, we consult a hard-wired list of role names
267 : * (see bootstrap.c) rather than trying to access the catalogs.
268 : *
269 : * RETURNS:
270 : * the string position in 's' immediately following the ACL
271 : * specification. Also:
272 : * - loads the structure pointed to by 'aip' with the appropriate
273 : * UID/GID, id type identifier and mode type values.
274 : *
275 : * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
276 : * in which case we log the error there and return NULL.
277 : */
278 : static const char *
279 4940 : aclparse(const char *s, AclItem *aip, Node *escontext)
280 : {
281 : AclMode privs,
282 : goption,
283 : read;
284 : char name[NAMEDATALEN];
285 : char name2[NAMEDATALEN];
286 :
287 : Assert(s && aip);
288 :
289 4940 : s = getid(s, name, escontext);
290 4940 : if (s == NULL)
291 0 : return NULL;
292 4940 : if (*s != '=')
293 : {
294 : /* we just read a keyword, not a name */
295 0 : if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
296 0 : ereturn(escontext, NULL,
297 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
298 : errmsg("unrecognized key word: \"%s\"", name),
299 : errhint("ACL key word must be \"group\" or \"user\".")));
300 : /* move s to the name beyond the keyword */
301 0 : s = getid(s, name, escontext);
302 0 : if (s == NULL)
303 0 : return NULL;
304 0 : if (name[0] == '\0')
305 0 : ereturn(escontext, NULL,
306 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
307 : errmsg("missing name"),
308 : errhint("A name must follow the \"group\" or \"user\" key word.")));
309 : }
310 :
311 4940 : if (*s != '=')
312 0 : ereturn(escontext, NULL,
313 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
314 : errmsg("missing \"=\" sign")));
315 :
316 4940 : privs = goption = ACL_NO_RIGHTS;
317 :
318 9892 : for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
319 : {
320 4960 : switch (*s)
321 : {
322 8 : case '*':
323 8 : goption |= read;
324 8 : break;
325 0 : case ACL_INSERT_CHR:
326 0 : read = ACL_INSERT;
327 0 : break;
328 91 : case ACL_SELECT_CHR:
329 91 : read = ACL_SELECT;
330 91 : break;
331 0 : case ACL_UPDATE_CHR:
332 0 : read = ACL_UPDATE;
333 0 : break;
334 0 : case ACL_DELETE_CHR:
335 0 : read = ACL_DELETE;
336 0 : break;
337 0 : case ACL_TRUNCATE_CHR:
338 0 : read = ACL_TRUNCATE;
339 0 : break;
340 0 : case ACL_REFERENCES_CHR:
341 0 : read = ACL_REFERENCES;
342 0 : break;
343 0 : case ACL_TRIGGER_CHR:
344 0 : read = ACL_TRIGGER;
345 0 : break;
346 4845 : case ACL_EXECUTE_CHR:
347 4845 : read = ACL_EXECUTE;
348 4845 : break;
349 4 : case ACL_USAGE_CHR:
350 4 : read = ACL_USAGE;
351 4 : break;
352 4 : case ACL_CREATE_CHR:
353 4 : read = ACL_CREATE;
354 4 : break;
355 0 : case ACL_CREATE_TEMP_CHR:
356 0 : read = ACL_CREATE_TEMP;
357 0 : break;
358 0 : case ACL_CONNECT_CHR:
359 0 : read = ACL_CONNECT;
360 0 : break;
361 0 : case ACL_SET_CHR:
362 0 : read = ACL_SET;
363 0 : break;
364 0 : case ACL_ALTER_SYSTEM_CHR:
365 0 : read = ACL_ALTER_SYSTEM;
366 0 : break;
367 0 : case ACL_MAINTAIN_CHR:
368 0 : read = ACL_MAINTAIN;
369 0 : break;
370 8 : default:
371 8 : ereturn(escontext, NULL,
372 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
373 : errmsg("invalid mode character: must be one of \"%s\"",
374 : ACL_ALL_RIGHTS_STR)));
375 : }
376 :
377 4952 : privs |= read;
378 : }
379 :
380 4932 : if (name[0] == '\0')
381 59 : aip->ai_grantee = ACL_ID_PUBLIC;
382 : else
383 : {
384 4873 : if (IsBootstrapProcessingMode())
385 4845 : aip->ai_grantee = boot_get_role_oid(name);
386 : else
387 28 : aip->ai_grantee = get_role_oid(name, true);
388 4873 : if (!OidIsValid(aip->ai_grantee))
389 0 : ereturn(escontext, NULL,
390 : (errcode(ERRCODE_UNDEFINED_OBJECT),
391 : errmsg("role \"%s\" does not exist", name)));
392 : }
393 :
394 : /*
395 : * XXX Allow a degree of backward compatibility by defaulting the grantor
396 : * to the superuser. We condone that practice in the catalog .dat files
397 : * (i.e., in bootstrap mode) for brevity; otherwise, issue a warning.
398 : */
399 4932 : if (*s == '/')
400 : {
401 87 : s = getid(s + 1, name2, escontext);
402 87 : if (s == NULL)
403 0 : return NULL;
404 87 : if (name2[0] == '\0')
405 12 : ereturn(escontext, NULL,
406 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
407 : errmsg("a name must follow the \"/\" sign")));
408 75 : if (IsBootstrapProcessingMode())
409 0 : aip->ai_grantor = boot_get_role_oid(name2);
410 : else
411 75 : aip->ai_grantor = get_role_oid(name2, true);
412 75 : if (!OidIsValid(aip->ai_grantor))
413 8 : ereturn(escontext, NULL,
414 : (errcode(ERRCODE_UNDEFINED_OBJECT),
415 : errmsg("role \"%s\" does not exist", name2)));
416 : }
417 : else
418 : {
419 4845 : aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
420 4845 : if (!IsBootstrapProcessingMode())
421 0 : ereport(WARNING,
422 : (errcode(ERRCODE_INVALID_GRANTOR),
423 : errmsg("defaulting grantor to user ID %u",
424 : BOOTSTRAP_SUPERUSERID)));
425 : }
426 :
427 4912 : ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
428 :
429 4912 : return s;
430 : }
431 :
432 : /*
433 : * allocacl
434 : * Allocates storage for a new Acl with 'n' entries.
435 : *
436 : * RETURNS:
437 : * the new Acl
438 : */
439 : static Acl *
440 462433 : allocacl(int n)
441 : {
442 : Acl *new_acl;
443 : Size size;
444 :
445 462433 : if (n < 0)
446 0 : elog(ERROR, "invalid size: %d", n);
447 462433 : size = ACL_N_SIZE(n);
448 462433 : new_acl = (Acl *) palloc0(size);
449 462433 : SET_VARSIZE(new_acl, size);
450 462433 : new_acl->ndim = 1;
451 462433 : new_acl->dataoffset = 0; /* we never put in any nulls */
452 462433 : new_acl->elemtype = ACLITEMOID;
453 462433 : ARR_LBOUND(new_acl)[0] = 1;
454 462433 : ARR_DIMS(new_acl)[0] = n;
455 462433 : return new_acl;
456 : }
457 :
458 : /*
459 : * Create a zero-entry ACL
460 : */
461 : Acl *
462 43 : make_empty_acl(void)
463 : {
464 43 : return allocacl(0);
465 : }
466 :
467 : /*
468 : * Copy an ACL
469 : */
470 : Acl *
471 11648 : aclcopy(const Acl *orig_acl)
472 : {
473 : Acl *result_acl;
474 :
475 11648 : result_acl = allocacl(ACL_NUM(orig_acl));
476 :
477 11648 : memcpy(ACL_DAT(result_acl),
478 11648 : ACL_DAT(orig_acl),
479 11648 : ACL_NUM(orig_acl) * sizeof(AclItem));
480 :
481 11648 : return result_acl;
482 : }
483 :
484 : /*
485 : * Concatenate two ACLs
486 : *
487 : * This is a bit cheesy, since we may produce an ACL with redundant entries.
488 : * Be careful what the result is used for!
489 : */
490 : Acl *
491 28432 : aclconcat(const Acl *left_acl, const Acl *right_acl)
492 : {
493 : Acl *result_acl;
494 :
495 28432 : result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
496 :
497 28432 : memcpy(ACL_DAT(result_acl),
498 28432 : ACL_DAT(left_acl),
499 28432 : ACL_NUM(left_acl) * sizeof(AclItem));
500 :
501 28432 : memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
502 28432 : ACL_DAT(right_acl),
503 28432 : ACL_NUM(right_acl) * sizeof(AclItem));
504 :
505 28432 : return result_acl;
506 : }
507 :
508 : /*
509 : * Merge two ACLs
510 : *
511 : * This produces a properly merged ACL with no redundant entries.
512 : * Returns NULL on NULL input.
513 : */
514 : Acl *
515 140 : aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
516 : {
517 : Acl *result_acl;
518 : AclItem *aip;
519 : int i,
520 : num;
521 :
522 : /* Check for cases where one or both are empty/null */
523 140 : if (left_acl == NULL || ACL_NUM(left_acl) == 0)
524 : {
525 0 : if (right_acl == NULL || ACL_NUM(right_acl) == 0)
526 0 : return NULL;
527 : else
528 0 : return aclcopy(right_acl);
529 : }
530 : else
531 : {
532 140 : if (right_acl == NULL || ACL_NUM(right_acl) == 0)
533 92 : return aclcopy(left_acl);
534 : }
535 :
536 : /* Merge them the hard way, one item at a time */
537 48 : result_acl = aclcopy(left_acl);
538 :
539 48 : aip = ACL_DAT(right_acl);
540 48 : num = ACL_NUM(right_acl);
541 :
542 120 : for (i = 0; i < num; i++, aip++)
543 : {
544 : Acl *tmp_acl;
545 :
546 72 : tmp_acl = aclupdate(result_acl, aip, ACL_MODECHG_ADD,
547 : ownerId, DROP_RESTRICT);
548 72 : pfree(result_acl);
549 72 : result_acl = tmp_acl;
550 : }
551 :
552 48 : return result_acl;
553 : }
554 :
555 : /*
556 : * Sort the items in an ACL (into an arbitrary but consistent order)
557 : */
558 : void
559 590 : aclitemsort(Acl *acl)
560 : {
561 590 : if (acl != NULL && ACL_NUM(acl) > 1)
562 171 : qsort(ACL_DAT(acl), ACL_NUM(acl), sizeof(AclItem), aclitemComparator);
563 590 : }
564 :
565 : /*
566 : * Check if two ACLs are exactly equal
567 : *
568 : * This will not detect equality if the two arrays contain the same items
569 : * in different orders. To handle that case, sort both inputs first,
570 : * using aclitemsort().
571 : */
572 : bool
573 363 : aclequal(const Acl *left_acl, const Acl *right_acl)
574 : {
575 : /* Check for cases where one or both are empty/null */
576 363 : if (left_acl == NULL || ACL_NUM(left_acl) == 0)
577 : {
578 1 : if (right_acl == NULL || ACL_NUM(right_acl) == 0)
579 1 : return true;
580 : else
581 0 : return false;
582 : }
583 : else
584 : {
585 362 : if (right_acl == NULL || ACL_NUM(right_acl) == 0)
586 34 : return false;
587 : }
588 :
589 328 : if (ACL_NUM(left_acl) != ACL_NUM(right_acl))
590 149 : return false;
591 :
592 179 : if (memcmp(ACL_DAT(left_acl),
593 179 : ACL_DAT(right_acl),
594 179 : ACL_NUM(left_acl) * sizeof(AclItem)) == 0)
595 86 : return true;
596 :
597 93 : return false;
598 : }
599 :
600 : /*
601 : * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
602 : */
603 : static void
604 194266 : check_acl(const Acl *acl)
605 : {
606 194266 : if (ARR_ELEMTYPE(acl) != ACLITEMOID)
607 0 : ereport(ERROR,
608 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
609 : errmsg("ACL array contains wrong data type")));
610 194266 : if (ARR_NDIM(acl) != 1)
611 0 : ereport(ERROR,
612 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
613 : errmsg("ACL arrays must be one-dimensional")));
614 194266 : if (ARR_HASNULL(acl))
615 0 : ereport(ERROR,
616 : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
617 : errmsg("ACL arrays must not contain null values")));
618 194266 : }
619 :
620 : /*
621 : * aclitemin
622 : * Allocates storage for, and fills in, a new AclItem given a string
623 : * 's' that contains an ACL specification. See aclparse for details.
624 : *
625 : * RETURNS:
626 : * the new AclItem
627 : */
628 : Datum
629 4940 : aclitemin(PG_FUNCTION_ARGS)
630 : {
631 4940 : const char *s = PG_GETARG_CSTRING(0);
632 4940 : Node *escontext = fcinfo->context;
633 : AclItem *aip;
634 :
635 4940 : aip = palloc_object(AclItem);
636 :
637 4940 : s = aclparse(s, aip, escontext);
638 4936 : if (s == NULL)
639 24 : PG_RETURN_NULL();
640 :
641 4912 : while (isspace((unsigned char) *s))
642 0 : ++s;
643 4912 : if (*s)
644 0 : ereturn(escontext, (Datum) 0,
645 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
646 : errmsg("extra garbage at the end of the ACL specification")));
647 :
648 4912 : PG_RETURN_ACLITEM_P(aip);
649 : }
650 :
651 : /*
652 : * aclitemout
653 : * Allocates storage for, and fills in, a new null-delimited string
654 : * containing a formatted ACL specification. See aclparse for details.
655 : *
656 : * In bootstrap mode, this is called for debug printouts (initdb -d).
657 : * We could ask bootstrap.c to provide an inverse of boot_get_role_oid(),
658 : * but it seems at least as useful to just print numeric role OIDs.
659 : *
660 : * RETURNS:
661 : * the new string
662 : */
663 : Datum
664 712302 : aclitemout(PG_FUNCTION_ARGS)
665 : {
666 712302 : AclItem *aip = PG_GETARG_ACLITEM_P(0);
667 : char *p;
668 : char *out;
669 : HeapTuple htup;
670 : unsigned i;
671 :
672 712302 : out = palloc(strlen("=/") +
673 : 2 * N_ACL_RIGHTS +
674 : 2 * (2 * NAMEDATALEN + 2) +
675 : 1);
676 :
677 712302 : p = out;
678 712302 : *p = '\0';
679 :
680 712302 : if (aip->ai_grantee != ACL_ID_PUBLIC)
681 : {
682 402908 : if (!IsBootstrapProcessingMode())
683 402908 : htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantee));
684 : else
685 0 : htup = NULL;
686 402908 : if (HeapTupleIsValid(htup))
687 : {
688 402908 : putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
689 402908 : ReleaseSysCache(htup);
690 : }
691 : else
692 : {
693 : /* No such entry, or bootstrap mode: print numeric OID */
694 0 : sprintf(p, "%u", aip->ai_grantee);
695 : }
696 : }
697 4086612 : while (*p)
698 3374310 : ++p;
699 :
700 712302 : *p++ = '=';
701 :
702 11396832 : for (i = 0; i < N_ACL_RIGHTS; ++i)
703 : {
704 10684530 : if (ACLITEM_GET_PRIVS(*aip) & (UINT64CONST(1) << i))
705 1921529 : *p++ = ACL_ALL_RIGHTS_STR[i];
706 10684530 : if (ACLITEM_GET_GOPTIONS(*aip) & (UINT64CONST(1) << i))
707 195 : *p++ = '*';
708 : }
709 :
710 712302 : *p++ = '/';
711 712302 : *p = '\0';
712 :
713 712302 : if (!IsBootstrapProcessingMode())
714 712302 : htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantor));
715 : else
716 0 : htup = NULL;
717 712302 : if (HeapTupleIsValid(htup))
718 : {
719 712302 : putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
720 712302 : ReleaseSysCache(htup);
721 : }
722 : else
723 : {
724 : /* No such entry, or bootstrap mode: print numeric OID */
725 0 : sprintf(p, "%u", aip->ai_grantor);
726 : }
727 :
728 712302 : PG_RETURN_CSTRING(out);
729 : }
730 :
731 : /*
732 : * aclitem_match
733 : * Two AclItems are considered to match iff they have the same
734 : * grantee and grantor; the privileges are ignored.
735 : */
736 : static bool
737 16943 : aclitem_match(const AclItem *a1, const AclItem *a2)
738 : {
739 20812 : return a1->ai_grantee == a2->ai_grantee &&
740 3869 : a1->ai_grantor == a2->ai_grantor;
741 : }
742 :
743 : /*
744 : * aclitemComparator
745 : * qsort comparison function for AclItems
746 : */
747 : static int
748 183 : aclitemComparator(const void *arg1, const void *arg2)
749 : {
750 183 : const AclItem *a1 = (const AclItem *) arg1;
751 183 : const AclItem *a2 = (const AclItem *) arg2;
752 :
753 183 : if (a1->ai_grantee > a2->ai_grantee)
754 28 : return 1;
755 155 : if (a1->ai_grantee < a2->ai_grantee)
756 155 : return -1;
757 0 : if (a1->ai_grantor > a2->ai_grantor)
758 0 : return 1;
759 0 : if (a1->ai_grantor < a2->ai_grantor)
760 0 : return -1;
761 0 : if (a1->ai_privs > a2->ai_privs)
762 0 : return 1;
763 0 : if (a1->ai_privs < a2->ai_privs)
764 0 : return -1;
765 0 : return 0;
766 : }
767 :
768 : /*
769 : * aclitem equality operator
770 : */
771 : Datum
772 136995 : aclitem_eq(PG_FUNCTION_ARGS)
773 : {
774 136995 : AclItem *a1 = PG_GETARG_ACLITEM_P(0);
775 136995 : AclItem *a2 = PG_GETARG_ACLITEM_P(1);
776 : bool result;
777 :
778 400214 : result = a1->ai_privs == a2->ai_privs &&
779 260129 : a1->ai_grantee == a2->ai_grantee &&
780 123134 : a1->ai_grantor == a2->ai_grantor;
781 136995 : PG_RETURN_BOOL(result);
782 : }
783 :
784 : /*
785 : * aclitem hash function
786 : *
787 : * We make aclitems hashable not so much because anyone is likely to hash
788 : * them, as because we want array equality to work on aclitem arrays, and
789 : * with the typcache mechanism we must have a hash or btree opclass.
790 : */
791 : Datum
792 16096 : hash_aclitem(PG_FUNCTION_ARGS)
793 : {
794 16096 : AclItem *a = PG_GETARG_ACLITEM_P(0);
795 :
796 : /* not very bright, but avoids any issue of padding in struct */
797 16096 : PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
798 : }
799 :
800 : /*
801 : * 64-bit hash function for aclitem.
802 : *
803 : * Similar to hash_aclitem, but accepts a seed and returns a uint64 value.
804 : */
805 : Datum
806 8 : hash_aclitem_extended(PG_FUNCTION_ARGS)
807 : {
808 8 : AclItem *a = PG_GETARG_ACLITEM_P(0);
809 8 : uint64 seed = PG_GETARG_INT64(1);
810 8 : uint32 sum = (uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor);
811 :
812 8 : return (seed == 0) ? UInt64GetDatum(sum) : hash_uint32_extended(sum, seed);
813 : }
814 :
815 : /*
816 : * acldefault() --- create an ACL describing default access permissions
817 : *
818 : * Change this routine if you want to alter the default access policy for
819 : * newly-created objects (or any object with a NULL acl entry). When
820 : * you make a change here, don't forget to update the GRANT man page,
821 : * which explains all the default permissions.
822 : *
823 : * Note that these are the hard-wired "defaults" that are used in the
824 : * absence of any pg_default_acl entry.
825 : */
826 : Acl *
827 380773 : acldefault(ObjectType objtype, Oid ownerId)
828 : {
829 : AclMode world_default;
830 : AclMode owner_default;
831 : int nacl;
832 : Acl *acl;
833 : AclItem *aip;
834 :
835 380773 : switch (objtype)
836 : {
837 28204 : case OBJECT_COLUMN:
838 : /* by default, columns have no extra privileges */
839 28204 : world_default = ACL_NO_RIGHTS;
840 28204 : owner_default = ACL_NO_RIGHTS;
841 28204 : break;
842 116822 : case OBJECT_TABLE:
843 116822 : world_default = ACL_NO_RIGHTS;
844 116822 : owner_default = ACL_ALL_RIGHTS_RELATION;
845 116822 : break;
846 800 : case OBJECT_SEQUENCE:
847 800 : world_default = ACL_NO_RIGHTS;
848 800 : owner_default = ACL_ALL_RIGHTS_SEQUENCE;
849 800 : break;
850 738 : case OBJECT_DATABASE:
851 : /* for backwards compatibility, grant some rights by default */
852 738 : world_default = ACL_CREATE_TEMP | ACL_CONNECT;
853 738 : owner_default = ACL_ALL_RIGHTS_DATABASE;
854 738 : break;
855 35031 : case OBJECT_FUNCTION:
856 : /* Grant EXECUTE by default, for now */
857 35031 : world_default = ACL_EXECUTE;
858 35031 : owner_default = ACL_ALL_RIGHTS_FUNCTION;
859 35031 : break;
860 516 : case OBJECT_LANGUAGE:
861 : /* Grant USAGE by default, for now */
862 516 : world_default = ACL_USAGE;
863 516 : owner_default = ACL_ALL_RIGHTS_LANGUAGE;
864 516 : break;
865 216 : case OBJECT_LARGEOBJECT:
866 216 : world_default = ACL_NO_RIGHTS;
867 216 : owner_default = ACL_ALL_RIGHTS_LARGEOBJECT;
868 216 : break;
869 2275 : case OBJECT_SCHEMA:
870 2275 : world_default = ACL_NO_RIGHTS;
871 2275 : owner_default = ACL_ALL_RIGHTS_SCHEMA;
872 2275 : break;
873 44 : case OBJECT_TABLESPACE:
874 44 : world_default = ACL_NO_RIGHTS;
875 44 : owner_default = ACL_ALL_RIGHTS_TABLESPACE;
876 44 : break;
877 87 : case OBJECT_FDW:
878 87 : world_default = ACL_NO_RIGHTS;
879 87 : owner_default = ACL_ALL_RIGHTS_FDW;
880 87 : break;
881 179 : case OBJECT_FOREIGN_SERVER:
882 179 : world_default = ACL_NO_RIGHTS;
883 179 : owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
884 179 : break;
885 195697 : case OBJECT_DOMAIN:
886 : case OBJECT_TYPE:
887 195697 : world_default = ACL_USAGE;
888 195697 : owner_default = ACL_ALL_RIGHTS_TYPE;
889 195697 : break;
890 142 : case OBJECT_PARAMETER_ACL:
891 142 : world_default = ACL_NO_RIGHTS;
892 142 : owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
893 142 : break;
894 22 : case OBJECT_PROPGRAPH:
895 22 : world_default = ACL_NO_RIGHTS;
896 22 : owner_default = ACL_ALL_RIGHTS_PROPGRAPH;
897 22 : break;
898 0 : default:
899 0 : elog(ERROR, "unrecognized object type: %d", (int) objtype);
900 : world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
901 : owner_default = ACL_NO_RIGHTS;
902 : break;
903 : }
904 :
905 380773 : nacl = 0;
906 380773 : if (world_default != ACL_NO_RIGHTS)
907 231982 : nacl++;
908 380773 : if (owner_default != ACL_NO_RIGHTS)
909 352569 : nacl++;
910 :
911 380773 : acl = allocacl(nacl);
912 380773 : aip = ACL_DAT(acl);
913 :
914 380773 : if (world_default != ACL_NO_RIGHTS)
915 : {
916 231982 : aip->ai_grantee = ACL_ID_PUBLIC;
917 231982 : aip->ai_grantor = ownerId;
918 231982 : ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
919 231982 : aip++;
920 : }
921 :
922 : /*
923 : * Note that the owner's entry shows all ordinary privileges but no grant
924 : * options. This is because his grant options come "from the system" and
925 : * not from his own efforts. (The SQL spec says that the owner's rights
926 : * come from a "_SYSTEM" authid.) However, we do consider that the
927 : * owner's ordinary privileges are self-granted; this lets him revoke
928 : * them. We implement the owner's grant options without any explicit
929 : * "_SYSTEM"-like ACL entry, by internally special-casing the owner
930 : * wherever we are testing grant options.
931 : */
932 380773 : if (owner_default != ACL_NO_RIGHTS)
933 : {
934 352569 : aip->ai_grantee = ownerId;
935 352569 : aip->ai_grantor = ownerId;
936 352569 : ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
937 : }
938 :
939 380773 : return acl;
940 : }
941 :
942 :
943 : /*
944 : * SQL-accessible version of acldefault(). Hackish mapping from "char" type to
945 : * OBJECT_* values.
946 : */
947 : Datum
948 302376 : acldefault_sql(PG_FUNCTION_ARGS)
949 : {
950 302376 : char objtypec = PG_GETARG_CHAR(0);
951 302376 : Oid owner = PG_GETARG_OID(1);
952 302376 : ObjectType objtype = 0;
953 :
954 302376 : switch (objtypec)
955 : {
956 0 : case 'c':
957 0 : objtype = OBJECT_COLUMN;
958 0 : break;
959 100397 : case 'r':
960 100397 : objtype = OBJECT_TABLE;
961 100397 : break;
962 650 : case 's':
963 650 : objtype = OBJECT_SEQUENCE;
964 650 : break;
965 160 : case 'd':
966 160 : objtype = OBJECT_DATABASE;
967 160 : break;
968 6108 : case 'f':
969 6108 : objtype = OBJECT_FUNCTION;
970 6108 : break;
971 304 : case 'l':
972 304 : objtype = OBJECT_LANGUAGE;
973 304 : break;
974 98 : case 'L':
975 98 : objtype = OBJECT_LARGEOBJECT;
976 98 : break;
977 1767 : case 'n':
978 1767 : objtype = OBJECT_SCHEMA;
979 1767 : break;
980 41 : case 'p':
981 41 : objtype = OBJECT_PARAMETER_ACL;
982 41 : break;
983 32 : case 't':
984 32 : objtype = OBJECT_TABLESPACE;
985 32 : break;
986 71 : case 'F':
987 71 : objtype = OBJECT_FDW;
988 71 : break;
989 75 : case 'S':
990 75 : objtype = OBJECT_FOREIGN_SERVER;
991 75 : break;
992 192673 : case 'T':
993 192673 : objtype = OBJECT_TYPE;
994 192673 : break;
995 0 : default:
996 0 : elog(ERROR, "unrecognized object type abbreviation: %c", objtypec);
997 : }
998 :
999 302376 : PG_RETURN_ACL_P(acldefault(objtype, owner));
1000 : }
1001 :
1002 :
1003 : /*
1004 : * Update an ACL array to add or remove specified privileges.
1005 : *
1006 : * old_acl: the input ACL array
1007 : * mod_aip: defines the privileges to be added, removed, or substituted
1008 : * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
1009 : * ownerId: Oid of object owner
1010 : * behavior: RESTRICT or CASCADE behavior for recursive removal
1011 : *
1012 : * ownerid and behavior are only relevant when the update operation specifies
1013 : * deletion of grant options.
1014 : *
1015 : * The result is a modified copy; the input object is not changed.
1016 : *
1017 : * NB: caller is responsible for having detoasted the input ACL, if needed.
1018 : */
1019 : Acl *
1020 41433 : aclupdate(const Acl *old_acl, const AclItem *mod_aip,
1021 : int modechg, Oid ownerId, DropBehavior behavior)
1022 : {
1023 41433 : Acl *new_acl = NULL;
1024 : AclItem *old_aip,
1025 41433 : *new_aip = NULL;
1026 : AclMode old_rights,
1027 : old_goptions,
1028 : new_rights,
1029 : new_goptions;
1030 : int dst,
1031 : num;
1032 :
1033 : /* Caller probably already checked old_acl, but be safe */
1034 41433 : check_acl(old_acl);
1035 :
1036 : /* If granting grant options, check for circularity */
1037 41433 : if (modechg != ACL_MODECHG_DEL &&
1038 10108 : ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
1039 77 : check_circularity(old_acl, mod_aip, ownerId);
1040 :
1041 41433 : num = ACL_NUM(old_acl);
1042 41433 : old_aip = ACL_DAT(old_acl);
1043 :
1044 : /*
1045 : * Search the ACL for an existing entry for this grantee and grantor. If
1046 : * one exists, just modify the entry in-place (well, in the same position,
1047 : * since we actually return a copy); otherwise, insert the new entry at
1048 : * the end.
1049 : */
1050 :
1051 54527 : for (dst = 0; dst < num; ++dst)
1052 : {
1053 16930 : if (aclitem_match(mod_aip, old_aip + dst))
1054 : {
1055 : /* found a match, so modify existing item */
1056 3836 : new_acl = allocacl(num);
1057 3836 : new_aip = ACL_DAT(new_acl);
1058 3836 : memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
1059 3836 : break;
1060 : }
1061 : }
1062 :
1063 41433 : if (dst == num)
1064 : {
1065 : /* need to append a new item */
1066 37597 : new_acl = allocacl(num + 1);
1067 37597 : new_aip = ACL_DAT(new_acl);
1068 37597 : memcpy(new_aip, old_aip, num * sizeof(AclItem));
1069 :
1070 : /* initialize the new entry with no permissions */
1071 37597 : new_aip[dst].ai_grantee = mod_aip->ai_grantee;
1072 37597 : new_aip[dst].ai_grantor = mod_aip->ai_grantor;
1073 37597 : ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
1074 : ACL_NO_RIGHTS, ACL_NO_RIGHTS);
1075 37597 : num++; /* set num to the size of new_acl */
1076 : }
1077 :
1078 41433 : old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
1079 41433 : old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
1080 :
1081 : /* apply the specified permissions change */
1082 41433 : switch (modechg)
1083 : {
1084 10108 : case ACL_MODECHG_ADD:
1085 10108 : ACLITEM_SET_RIGHTS(new_aip[dst],
1086 : old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
1087 10108 : break;
1088 31325 : case ACL_MODECHG_DEL:
1089 31325 : ACLITEM_SET_RIGHTS(new_aip[dst],
1090 : old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
1091 31325 : break;
1092 0 : case ACL_MODECHG_EQL:
1093 0 : ACLITEM_SET_RIGHTS(new_aip[dst],
1094 : ACLITEM_GET_RIGHTS(*mod_aip));
1095 0 : break;
1096 : }
1097 :
1098 41433 : new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
1099 41433 : new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
1100 :
1101 : /*
1102 : * If the adjusted entry has no permissions, delete it from the list.
1103 : */
1104 41433 : if (new_rights == ACL_NO_RIGHTS)
1105 : {
1106 31128 : memmove(new_aip + dst,
1107 31128 : new_aip + dst + 1,
1108 31128 : (num - dst - 1) * sizeof(AclItem));
1109 : /* Adjust array size to be 'num - 1' items */
1110 31128 : ARR_DIMS(new_acl)[0] = num - 1;
1111 31128 : SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
1112 : }
1113 :
1114 : /*
1115 : * Remove abandoned privileges (cascading revoke). Currently we can only
1116 : * handle this when the grantee is not PUBLIC.
1117 : */
1118 41433 : if ((old_goptions & ~new_goptions) != 0)
1119 : {
1120 : Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
1121 59 : new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
1122 59 : (old_goptions & ~new_goptions),
1123 : ownerId, behavior);
1124 : }
1125 :
1126 41425 : return new_acl;
1127 : }
1128 :
1129 : /*
1130 : * Update an ACL array to reflect a change of owner to the parent object
1131 : *
1132 : * old_acl: the input ACL array (must not be NULL)
1133 : * oldOwnerId: Oid of the old object owner
1134 : * newOwnerId: Oid of the new object owner
1135 : *
1136 : * The result is a modified copy; the input object is not changed.
1137 : *
1138 : * NB: caller is responsible for having detoasted the input ACL, if needed.
1139 : *
1140 : * Note: the name of this function is a bit of a misnomer, since it will
1141 : * happily make the specified role substitution whether the old role is
1142 : * really the owner of the parent object or merely mentioned in its ACL.
1143 : * But the vast majority of callers use it in connection with ALTER OWNER
1144 : * operations, so we'll keep the name.
1145 : */
1146 : Acl *
1147 92 : aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
1148 : {
1149 : Acl *new_acl;
1150 : AclItem *new_aip;
1151 : AclItem *old_aip;
1152 : AclItem *dst_aip;
1153 : AclItem *src_aip;
1154 : AclItem *targ_aip;
1155 92 : bool newpresent = false;
1156 : int dst,
1157 : src,
1158 : targ,
1159 : num;
1160 :
1161 92 : check_acl(old_acl);
1162 :
1163 : /*
1164 : * Make a copy of the given ACL, substituting new owner ID for old
1165 : * wherever it appears as either grantor or grantee. Also note if the new
1166 : * owner ID is already present.
1167 : */
1168 92 : num = ACL_NUM(old_acl);
1169 92 : old_aip = ACL_DAT(old_acl);
1170 92 : new_acl = allocacl(num);
1171 92 : new_aip = ACL_DAT(new_acl);
1172 92 : memcpy(new_aip, old_aip, num * sizeof(AclItem));
1173 261 : for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
1174 : {
1175 169 : if (dst_aip->ai_grantor == oldOwnerId)
1176 169 : dst_aip->ai_grantor = newOwnerId;
1177 0 : else if (dst_aip->ai_grantor == newOwnerId)
1178 0 : newpresent = true;
1179 169 : if (dst_aip->ai_grantee == oldOwnerId)
1180 90 : dst_aip->ai_grantee = newOwnerId;
1181 79 : else if (dst_aip->ai_grantee == newOwnerId)
1182 13 : newpresent = true;
1183 : }
1184 :
1185 : /*
1186 : * If the old ACL contained any references to the new owner, then we may
1187 : * now have generated an ACL containing duplicate entries. Find them and
1188 : * merge them so that there are not duplicates. (This is relatively
1189 : * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
1190 : * be the normal case.)
1191 : *
1192 : * To simplify deletion of duplicate entries, we temporarily leave them in
1193 : * the array but set their privilege masks to zero; when we reach such an
1194 : * entry it's just skipped. (Thus, a side effect of this code will be to
1195 : * remove privilege-free entries, should there be any in the input.) dst
1196 : * is the next output slot, targ is the currently considered input slot
1197 : * (always >= dst), and src scans entries to the right of targ looking for
1198 : * duplicates. Once an entry has been emitted to dst it is known
1199 : * duplicate-free and need not be considered anymore.
1200 : */
1201 92 : if (newpresent)
1202 : {
1203 13 : dst = 0;
1204 39 : for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
1205 : {
1206 : /* ignore if deleted in an earlier pass */
1207 26 : if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
1208 13 : continue;
1209 : /* find and merge any duplicates */
1210 26 : for (src = targ + 1, src_aip = targ_aip + 1; src < num;
1211 13 : src++, src_aip++)
1212 : {
1213 13 : if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
1214 0 : continue;
1215 13 : if (aclitem_match(targ_aip, src_aip))
1216 : {
1217 13 : ACLITEM_SET_RIGHTS(*targ_aip,
1218 : ACLITEM_GET_RIGHTS(*targ_aip) |
1219 : ACLITEM_GET_RIGHTS(*src_aip));
1220 : /* mark the duplicate deleted */
1221 13 : ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
1222 : }
1223 : }
1224 : /* and emit to output */
1225 13 : new_aip[dst] = *targ_aip;
1226 13 : dst++;
1227 : }
1228 : /* Adjust array size to be 'dst' items */
1229 13 : ARR_DIMS(new_acl)[0] = dst;
1230 13 : SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
1231 : }
1232 :
1233 92 : return new_acl;
1234 : }
1235 :
1236 :
1237 : /*
1238 : * When granting grant options, we must disallow attempts to set up circular
1239 : * chains of grant options. Suppose A (the object owner) grants B some
1240 : * privileges with grant option, and B re-grants them to C. If C could
1241 : * grant the privileges to B as well, then A would be unable to effectively
1242 : * revoke the privileges from B, since recursive_revoke would consider that
1243 : * B still has 'em from C.
1244 : *
1245 : * We check for this by recursively deleting all grant options belonging to
1246 : * the target grantee, and then seeing if the would-be grantor still has the
1247 : * grant option or not.
1248 : */
1249 : static void
1250 77 : check_circularity(const Acl *old_acl, const AclItem *mod_aip,
1251 : Oid ownerId)
1252 : {
1253 : Acl *acl;
1254 : AclItem *aip;
1255 : int i,
1256 : num;
1257 : AclMode own_privs;
1258 :
1259 77 : check_acl(old_acl);
1260 :
1261 : /*
1262 : * For now, grant options can only be granted to roles, not PUBLIC.
1263 : * Otherwise we'd have to work a bit harder here.
1264 : */
1265 : Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
1266 :
1267 : /* The owner always has grant options, no need to check */
1268 77 : if (mod_aip->ai_grantor == ownerId)
1269 65 : return;
1270 :
1271 : /* Make a working copy */
1272 12 : acl = allocacl(ACL_NUM(old_acl));
1273 12 : memcpy(acl, old_acl, ACL_SIZE(old_acl));
1274 :
1275 : /* Zap all grant options of target grantee, plus what depends on 'em */
1276 16 : cc_restart:
1277 16 : num = ACL_NUM(acl);
1278 16 : aip = ACL_DAT(acl);
1279 64 : for (i = 0; i < num; i++)
1280 : {
1281 52 : if (aip[i].ai_grantee == mod_aip->ai_grantee &&
1282 4 : ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
1283 : {
1284 : Acl *new_acl;
1285 :
1286 : /* We'll actually zap ordinary privs too, but no matter */
1287 4 : new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
1288 : ownerId, DROP_CASCADE);
1289 :
1290 4 : pfree(acl);
1291 4 : acl = new_acl;
1292 :
1293 4 : goto cc_restart;
1294 : }
1295 : }
1296 :
1297 : /* Now we can compute grantor's independently-derived privileges */
1298 12 : own_privs = aclmask(acl,
1299 12 : mod_aip->ai_grantor,
1300 : ownerId,
1301 12 : ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
1302 : ACLMASK_ALL);
1303 12 : own_privs = ACL_OPTION_TO_PRIVS(own_privs);
1304 :
1305 12 : if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
1306 0 : ereport(ERROR,
1307 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1308 : errmsg("grant options cannot be granted back to your own grantor")));
1309 :
1310 12 : pfree(acl);
1311 : }
1312 :
1313 :
1314 : /*
1315 : * Ensure that no privilege is "abandoned". A privilege is abandoned
1316 : * if the user that granted the privilege loses the grant option. (So
1317 : * the chain through which it was granted is broken.) Either the
1318 : * abandoned privileges are revoked as well, or an error message is
1319 : * printed, depending on the drop behavior option.
1320 : *
1321 : * acl: the input ACL list
1322 : * grantee: the user from whom some grant options have been revoked
1323 : * revoke_privs: the grant options being revoked
1324 : * ownerId: Oid of object owner
1325 : * behavior: RESTRICT or CASCADE behavior for recursive removal
1326 : *
1327 : * The input Acl object is pfree'd if replaced.
1328 : */
1329 : static Acl *
1330 59 : recursive_revoke(Acl *acl,
1331 : Oid grantee,
1332 : AclMode revoke_privs,
1333 : Oid ownerId,
1334 : DropBehavior behavior)
1335 : {
1336 : AclMode still_has;
1337 : AclItem *aip;
1338 : int i,
1339 : num;
1340 :
1341 59 : check_acl(acl);
1342 :
1343 : /* The owner can never truly lose grant options, so short-circuit */
1344 59 : if (grantee == ownerId)
1345 0 : return acl;
1346 :
1347 : /* The grantee might still have some grant options via another grantor */
1348 59 : still_has = aclmask(acl, grantee, ownerId,
1349 : ACL_GRANT_OPTION_FOR(revoke_privs),
1350 : ACLMASK_ALL);
1351 59 : revoke_privs &= ~ACL_OPTION_TO_PRIVS(still_has);
1352 59 : if (revoke_privs == ACL_NO_RIGHTS)
1353 4 : return acl;
1354 :
1355 55 : restart:
1356 79 : num = ACL_NUM(acl);
1357 79 : aip = ACL_DAT(acl);
1358 256 : for (i = 0; i < num; i++)
1359 : {
1360 209 : if (aip[i].ai_grantor == grantee
1361 32 : && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1362 : {
1363 : AclItem mod_acl;
1364 : Acl *new_acl;
1365 :
1366 32 : if (behavior == DROP_RESTRICT)
1367 8 : ereport(ERROR,
1368 : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1369 : errmsg("dependent privileges exist"),
1370 : errhint("Use CASCADE to revoke them too.")));
1371 :
1372 24 : mod_acl.ai_grantor = grantee;
1373 24 : mod_acl.ai_grantee = aip[i].ai_grantee;
1374 24 : ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
1375 : revoke_privs,
1376 : revoke_privs);
1377 :
1378 24 : new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1379 : ownerId, behavior);
1380 :
1381 24 : pfree(acl);
1382 24 : acl = new_acl;
1383 :
1384 24 : goto restart;
1385 : }
1386 : }
1387 :
1388 47 : return acl;
1389 : }
1390 :
1391 :
1392 : /*
1393 : * aclmask --- compute bitmask of all privileges held by roleid.
1394 : *
1395 : * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
1396 : * held by the given roleid according to the given ACL list, ANDed
1397 : * with 'mask'. (The point of passing 'mask' is to let the routine
1398 : * exit early if all privileges of interest have been found.)
1399 : *
1400 : * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
1401 : * is known true. (This lets us exit soonest in cases where the
1402 : * caller is only going to test for zero or nonzero result.)
1403 : *
1404 : * Usage patterns:
1405 : *
1406 : * To see if any of a set of privileges are held:
1407 : * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1408 : *
1409 : * To see if all of a set of privileges are held:
1410 : * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1411 : *
1412 : * To determine exactly which of a set of privileges are held:
1413 : * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1414 : */
1415 : AclMode
1416 91475 : aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1417 : AclMode mask, AclMaskHow how)
1418 : {
1419 : AclMode result;
1420 : AclMode remaining;
1421 : AclItem *aidat;
1422 : int i,
1423 : num;
1424 :
1425 : /*
1426 : * Null ACL should not happen, since caller should have inserted
1427 : * appropriate default
1428 : */
1429 91475 : if (acl == NULL)
1430 0 : elog(ERROR, "null ACL");
1431 :
1432 91475 : check_acl(acl);
1433 :
1434 : /* Quick exit for mask == 0 */
1435 91475 : if (mask == 0)
1436 46 : return 0;
1437 :
1438 91429 : result = 0;
1439 :
1440 : /* Owner always implicitly has all grant options */
1441 91553 : if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1442 124 : has_privs_of_role(roleid, ownerId))
1443 : {
1444 4 : result = mask & ACLITEM_ALL_GOPTION_BITS;
1445 4 : if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1446 4 : return result;
1447 : }
1448 :
1449 91425 : num = ACL_NUM(acl);
1450 91425 : aidat = ACL_DAT(acl);
1451 :
1452 : /*
1453 : * Check privileges granted directly to roleid or to public
1454 : */
1455 142771 : for (i = 0; i < num; i++)
1456 : {
1457 131609 : AclItem *aidata = &aidat[i];
1458 :
1459 131609 : if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1460 61861 : aidata->ai_grantee == roleid)
1461 : {
1462 82358 : result |= aidata->ai_privs & mask;
1463 82358 : if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1464 80263 : return result;
1465 : }
1466 : }
1467 :
1468 : /*
1469 : * Check privileges granted indirectly via role memberships. We do this in
1470 : * a separate pass to minimize expensive indirect membership tests. In
1471 : * particular, it's worth testing whether a given ACL entry grants any
1472 : * privileges still of interest before we perform the has_privs_of_role
1473 : * test.
1474 : */
1475 11162 : remaining = mask & ~result;
1476 25329 : for (i = 0; i < num; i++)
1477 : {
1478 14358 : AclItem *aidata = &aidat[i];
1479 :
1480 14358 : if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1481 13770 : aidata->ai_grantee == roleid)
1482 1995 : continue; /* already checked it */
1483 :
1484 24003 : if ((aidata->ai_privs & remaining) &&
1485 11640 : has_privs_of_role(roleid, aidata->ai_grantee))
1486 : {
1487 191 : result |= aidata->ai_privs & mask;
1488 191 : if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1489 191 : return result;
1490 0 : remaining = mask & ~result;
1491 : }
1492 : }
1493 :
1494 10971 : return result;
1495 : }
1496 :
1497 :
1498 : /*
1499 : * aclmask_direct --- compute bitmask of all privileges held by roleid.
1500 : *
1501 : * This is exactly like aclmask() except that we consider only privileges
1502 : * held *directly* by roleid, not those inherited via role membership.
1503 : */
1504 : static AclMode
1505 380 : aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1506 : AclMode mask, AclMaskHow how)
1507 : {
1508 : AclMode result;
1509 : AclItem *aidat;
1510 : int i,
1511 : num;
1512 :
1513 : /*
1514 : * Null ACL should not happen, since caller should have inserted
1515 : * appropriate default
1516 : */
1517 380 : if (acl == NULL)
1518 0 : elog(ERROR, "null ACL");
1519 :
1520 380 : check_acl(acl);
1521 :
1522 : /* Quick exit for mask == 0 */
1523 380 : if (mask == 0)
1524 0 : return 0;
1525 :
1526 380 : result = 0;
1527 :
1528 : /* Owner always implicitly has all grant options */
1529 380 : if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1530 : roleid == ownerId)
1531 : {
1532 8 : result = mask & ACLITEM_ALL_GOPTION_BITS;
1533 8 : if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1534 8 : return result;
1535 : }
1536 :
1537 372 : num = ACL_NUM(acl);
1538 372 : aidat = ACL_DAT(acl);
1539 :
1540 : /*
1541 : * Check privileges granted directly to roleid (and not to public)
1542 : */
1543 1616 : for (i = 0; i < num; i++)
1544 : {
1545 1384 : AclItem *aidata = &aidat[i];
1546 :
1547 1384 : if (aidata->ai_grantee == roleid)
1548 : {
1549 296 : result |= aidata->ai_privs & mask;
1550 296 : if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1551 140 : return result;
1552 : }
1553 : }
1554 :
1555 232 : return result;
1556 : }
1557 :
1558 :
1559 : /*
1560 : * aclmembers
1561 : * Find out all the roleids mentioned in an Acl.
1562 : * Note that we do not distinguish grantors from grantees.
1563 : *
1564 : * *roleids is set to point to a palloc'd array containing distinct OIDs
1565 : * in sorted order. The length of the array is the function result.
1566 : */
1567 : int
1568 49768 : aclmembers(const Acl *acl, Oid **roleids)
1569 : {
1570 : Oid *list;
1571 : const AclItem *acldat;
1572 : int i,
1573 : j;
1574 :
1575 49768 : if (acl == NULL || ACL_NUM(acl) == 0)
1576 : {
1577 28258 : *roleids = NULL;
1578 28258 : return 0;
1579 : }
1580 :
1581 21510 : check_acl(acl);
1582 :
1583 : /* Allocate the worst-case space requirement */
1584 21510 : list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1585 21510 : acldat = ACL_DAT(acl);
1586 :
1587 : /*
1588 : * Walk the ACL collecting mentioned RoleIds.
1589 : */
1590 21510 : j = 0;
1591 56340 : for (i = 0; i < ACL_NUM(acl); i++)
1592 : {
1593 34830 : const AclItem *ai = &acldat[i];
1594 :
1595 34830 : if (ai->ai_grantee != ACL_ID_PUBLIC)
1596 23795 : list[j++] = ai->ai_grantee;
1597 : /* grantor is currently never PUBLIC, but let's check anyway */
1598 34830 : if (ai->ai_grantor != ACL_ID_PUBLIC)
1599 34830 : list[j++] = ai->ai_grantor;
1600 : }
1601 :
1602 : /* Sort the array */
1603 21510 : qsort(list, j, sizeof(Oid), oid_cmp);
1604 :
1605 : /*
1606 : * We could repalloc the array down to minimum size, but it's hardly worth
1607 : * it since it's only transient memory.
1608 : */
1609 21510 : *roleids = list;
1610 :
1611 : /* Remove duplicates from the array */
1612 21510 : return qunique(list, j, sizeof(Oid), oid_cmp);
1613 : }
1614 :
1615 :
1616 : /*
1617 : * aclinsert (exported function)
1618 : */
1619 : Datum
1620 0 : aclinsert(PG_FUNCTION_ARGS)
1621 : {
1622 0 : ereport(ERROR,
1623 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1624 : errmsg("aclinsert is no longer supported")));
1625 :
1626 : PG_RETURN_NULL(); /* keep compiler quiet */
1627 : }
1628 :
1629 : Datum
1630 0 : aclremove(PG_FUNCTION_ARGS)
1631 : {
1632 0 : ereport(ERROR,
1633 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1634 : errmsg("aclremove is no longer supported")));
1635 :
1636 : PG_RETURN_NULL(); /* keep compiler quiet */
1637 : }
1638 :
1639 : Datum
1640 0 : aclcontains(PG_FUNCTION_ARGS)
1641 : {
1642 0 : Acl *acl = PG_GETARG_ACL_P(0);
1643 0 : AclItem *aip = PG_GETARG_ACLITEM_P(1);
1644 : AclItem *aidat;
1645 : int i,
1646 : num;
1647 :
1648 0 : check_acl(acl);
1649 0 : num = ACL_NUM(acl);
1650 0 : aidat = ACL_DAT(acl);
1651 0 : for (i = 0; i < num; ++i)
1652 : {
1653 0 : if (aip->ai_grantee == aidat[i].ai_grantee &&
1654 0 : aip->ai_grantor == aidat[i].ai_grantor &&
1655 0 : (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
1656 0 : PG_RETURN_BOOL(true);
1657 : }
1658 0 : PG_RETURN_BOOL(false);
1659 : }
1660 :
1661 : Datum
1662 24 : makeaclitem(PG_FUNCTION_ARGS)
1663 : {
1664 24 : Oid grantee = PG_GETARG_OID(0);
1665 24 : Oid grantor = PG_GETARG_OID(1);
1666 24 : text *privtext = PG_GETARG_TEXT_PP(2);
1667 24 : bool goption = PG_GETARG_BOOL(3);
1668 : AclItem *result;
1669 : AclMode priv;
1670 : static const priv_map any_priv_map[] = {
1671 : {"SELECT", ACL_SELECT},
1672 : {"INSERT", ACL_INSERT},
1673 : {"UPDATE", ACL_UPDATE},
1674 : {"DELETE", ACL_DELETE},
1675 : {"TRUNCATE", ACL_TRUNCATE},
1676 : {"REFERENCES", ACL_REFERENCES},
1677 : {"TRIGGER", ACL_TRIGGER},
1678 : {"EXECUTE", ACL_EXECUTE},
1679 : {"USAGE", ACL_USAGE},
1680 : {"CREATE", ACL_CREATE},
1681 : {"TEMP", ACL_CREATE_TEMP},
1682 : {"TEMPORARY", ACL_CREATE_TEMP},
1683 : {"CONNECT", ACL_CONNECT},
1684 : {"SET", ACL_SET},
1685 : {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
1686 : {"MAINTAIN", ACL_MAINTAIN},
1687 : {NULL, 0}
1688 : };
1689 :
1690 24 : priv = convert_any_priv_string(privtext, any_priv_map);
1691 :
1692 20 : result = palloc_object(AclItem);
1693 :
1694 20 : result->ai_grantee = grantee;
1695 20 : result->ai_grantor = grantor;
1696 :
1697 20 : ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1698 : (goption ? priv : ACL_NO_RIGHTS));
1699 :
1700 20 : PG_RETURN_ACLITEM_P(result);
1701 : }
1702 :
1703 :
1704 : /*
1705 : * convert_any_priv_string: recognize privilege strings for has_foo_privilege
1706 : *
1707 : * We accept a comma-separated list of case-insensitive privilege names,
1708 : * producing a bitmask of the OR'd privilege bits. We are liberal about
1709 : * whitespace between items, not so much about whitespace within items.
1710 : * The allowed privilege names are given as an array of priv_map structs,
1711 : * terminated by one with a NULL name pointer.
1712 : */
1713 : static AclMode
1714 429195 : convert_any_priv_string(text *priv_type_text,
1715 : const priv_map *privileges)
1716 : {
1717 429195 : AclMode result = 0;
1718 429195 : char *priv_type = text_to_cstring(priv_type_text);
1719 : char *chunk;
1720 : char *next_chunk;
1721 :
1722 : /* We rely on priv_type being a private, modifiable string */
1723 858397 : for (chunk = priv_type; chunk; chunk = next_chunk)
1724 : {
1725 : int chunk_len;
1726 : const priv_map *this_priv;
1727 :
1728 : /* Split string at commas */
1729 429221 : next_chunk = strchr(chunk, ',');
1730 429221 : if (next_chunk)
1731 28 : *next_chunk++ = '\0';
1732 :
1733 : /* Drop leading/trailing whitespace in this chunk */
1734 429252 : while (*chunk && isspace((unsigned char) *chunk))
1735 31 : chunk++;
1736 429221 : chunk_len = strlen(chunk);
1737 429236 : while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
1738 15 : chunk_len--;
1739 429221 : chunk[chunk_len] = '\0';
1740 :
1741 : /* Match to the privileges list */
1742 430463 : for (this_priv = privileges; this_priv->name; this_priv++)
1743 : {
1744 430444 : if (pg_strcasecmp(this_priv->name, chunk) == 0)
1745 : {
1746 429202 : result |= this_priv->value;
1747 429202 : break;
1748 : }
1749 : }
1750 429221 : if (!this_priv->name)
1751 19 : ereport(ERROR,
1752 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1753 : errmsg("unrecognized privilege type: \"%s\"", chunk)));
1754 : }
1755 :
1756 429176 : pfree(priv_type);
1757 429176 : return result;
1758 : }
1759 :
1760 :
1761 : static const char *
1762 329372 : convert_aclright_to_string(int aclright)
1763 : {
1764 329372 : switch (aclright)
1765 : {
1766 39159 : case ACL_INSERT:
1767 39159 : return "INSERT";
1768 54901 : case ACL_SELECT:
1769 54901 : return "SELECT";
1770 39440 : case ACL_UPDATE:
1771 39440 : return "UPDATE";
1772 39087 : case ACL_DELETE:
1773 39087 : return "DELETE";
1774 39159 : case ACL_TRUNCATE:
1775 39159 : return "TRUNCATE";
1776 39159 : case ACL_REFERENCES:
1777 39159 : return "REFERENCES";
1778 39159 : case ACL_TRIGGER:
1779 39159 : return "TRIGGER";
1780 41 : case ACL_EXECUTE:
1781 41 : return "EXECUTE";
1782 108 : case ACL_USAGE:
1783 108 : return "USAGE";
1784 0 : case ACL_CREATE:
1785 0 : return "CREATE";
1786 0 : case ACL_CREATE_TEMP:
1787 0 : return "TEMPORARY";
1788 0 : case ACL_CONNECT:
1789 0 : return "CONNECT";
1790 0 : case ACL_SET:
1791 0 : return "SET";
1792 0 : case ACL_ALTER_SYSTEM:
1793 0 : return "ALTER SYSTEM";
1794 39159 : case ACL_MAINTAIN:
1795 39159 : return "MAINTAIN";
1796 0 : default:
1797 0 : elog(ERROR, "unrecognized aclright: %d", aclright);
1798 : return NULL;
1799 : }
1800 : }
1801 :
1802 :
1803 : /*----------
1804 : * Convert an aclitem[] to a table.
1805 : *
1806 : * Example:
1807 : *
1808 : * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
1809 : *
1810 : * returns the table
1811 : *
1812 : * {{ OID(joe), 0::OID, 'SELECT', false },
1813 : * { OID(joe), OID(foo), 'INSERT', true },
1814 : * { OID(joe), OID(foo), 'UPDATE', false }}
1815 : *----------
1816 : */
1817 : Datum
1818 368612 : aclexplode(PG_FUNCTION_ARGS)
1819 : {
1820 368612 : Acl *acl = PG_GETARG_ACL_P(0);
1821 : FuncCallContext *funcctx;
1822 : int *idx;
1823 : AclItem *aidat;
1824 :
1825 368612 : if (SRF_IS_FIRSTCALL())
1826 : {
1827 : TupleDesc tupdesc;
1828 : MemoryContext oldcontext;
1829 :
1830 39240 : check_acl(acl);
1831 :
1832 39240 : funcctx = SRF_FIRSTCALL_INIT();
1833 39240 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1834 :
1835 : /*
1836 : * build tupdesc for result tuples (matches out parameters in pg_proc
1837 : * entry)
1838 : */
1839 39240 : tupdesc = CreateTemplateTupleDesc(4);
1840 39240 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
1841 : OIDOID, -1, 0);
1842 39240 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
1843 : OIDOID, -1, 0);
1844 39240 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
1845 : TEXTOID, -1, 0);
1846 39240 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
1847 : BOOLOID, -1, 0);
1848 :
1849 39240 : TupleDescFinalize(tupdesc);
1850 39240 : funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1851 :
1852 : /* allocate memory for user context */
1853 39240 : idx = palloc_array(int, 2);
1854 39240 : idx[0] = 0; /* ACL array item index */
1855 39240 : idx[1] = -1; /* privilege type counter */
1856 39240 : funcctx->user_fctx = idx;
1857 :
1858 39240 : MemoryContextSwitchTo(oldcontext);
1859 : }
1860 :
1861 368612 : funcctx = SRF_PERCALL_SETUP();
1862 368612 : idx = (int *) funcctx->user_fctx;
1863 368612 : aidat = ACL_DAT(acl);
1864 :
1865 : /* need test here in case acl has no items */
1866 865815 : while (idx[0] < ACL_NUM(acl))
1867 : {
1868 : AclItem *aidata;
1869 : AclMode priv_bit;
1870 :
1871 865815 : idx[1]++;
1872 865815 : if (idx[1] == N_ACL_RIGHTS)
1873 : {
1874 55105 : idx[1] = 0;
1875 55105 : idx[0]++;
1876 55105 : if (idx[0] >= ACL_NUM(acl)) /* done */
1877 39240 : break;
1878 : }
1879 826575 : aidata = &aidat[idx[0]];
1880 826575 : priv_bit = UINT64CONST(1) << idx[1];
1881 :
1882 826575 : if (ACLITEM_GET_PRIVS(*aidata) & priv_bit)
1883 : {
1884 : Datum result;
1885 : Datum values[4];
1886 329372 : bool nulls[4] = {0};
1887 : HeapTuple tuple;
1888 :
1889 329372 : values[0] = ObjectIdGetDatum(aidata->ai_grantor);
1890 329372 : values[1] = ObjectIdGetDatum(aidata->ai_grantee);
1891 329372 : values[2] = CStringGetTextDatum(convert_aclright_to_string(priv_bit));
1892 329372 : values[3] = BoolGetDatum((ACLITEM_GET_GOPTIONS(*aidata) & priv_bit) != 0);
1893 :
1894 329372 : tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1895 329372 : result = HeapTupleGetDatum(tuple);
1896 :
1897 329372 : SRF_RETURN_NEXT(funcctx, result);
1898 : }
1899 : }
1900 :
1901 39240 : SRF_RETURN_DONE(funcctx);
1902 : }
1903 :
1904 :
1905 : /*
1906 : * has_table_privilege variants
1907 : * These are all named "has_table_privilege" at the SQL level.
1908 : * They take various combinations of relation name, relation OID,
1909 : * user name, user OID, or implicit user = current_user.
1910 : *
1911 : * The result is a boolean value: true if user has the indicated
1912 : * privilege, false if not. The variants that take a relation OID
1913 : * return NULL if the OID doesn't exist (rather than failing, as
1914 : * they did before Postgres 8.4).
1915 : */
1916 :
1917 : /*
1918 : * has_table_privilege_name_name
1919 : * Check user privileges on a table given
1920 : * name username, text tablename, and text priv name.
1921 : */
1922 : Datum
1923 144 : has_table_privilege_name_name(PG_FUNCTION_ARGS)
1924 : {
1925 144 : Name rolename = PG_GETARG_NAME(0);
1926 144 : text *tablename = PG_GETARG_TEXT_PP(1);
1927 144 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
1928 : Oid roleid;
1929 : Oid tableoid;
1930 : AclMode mode;
1931 : AclResult aclresult;
1932 :
1933 144 : roleid = get_role_oid_or_public(NameStr(*rolename));
1934 140 : tableoid = convert_table_name(tablename);
1935 140 : mode = convert_table_priv_string(priv_type_text);
1936 :
1937 140 : aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1938 :
1939 140 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1940 : }
1941 :
1942 : /*
1943 : * has_table_privilege_name
1944 : * Check user privileges on a table given
1945 : * text tablename and text priv name.
1946 : * current_user is assumed
1947 : */
1948 : Datum
1949 44 : has_table_privilege_name(PG_FUNCTION_ARGS)
1950 : {
1951 44 : text *tablename = PG_GETARG_TEXT_PP(0);
1952 44 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
1953 : Oid roleid;
1954 : Oid tableoid;
1955 : AclMode mode;
1956 : AclResult aclresult;
1957 :
1958 44 : roleid = GetUserId();
1959 44 : tableoid = convert_table_name(tablename);
1960 40 : mode = convert_table_priv_string(priv_type_text);
1961 :
1962 36 : aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1963 :
1964 36 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1965 : }
1966 :
1967 : /*
1968 : * has_table_privilege_name_id
1969 : * Check user privileges on a table given
1970 : * name usename, table oid, and text priv name.
1971 : */
1972 : Datum
1973 12 : has_table_privilege_name_id(PG_FUNCTION_ARGS)
1974 : {
1975 12 : Name username = PG_GETARG_NAME(0);
1976 12 : Oid tableoid = PG_GETARG_OID(1);
1977 12 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
1978 : Oid roleid;
1979 : AclMode mode;
1980 : AclResult aclresult;
1981 12 : bool is_missing = false;
1982 :
1983 12 : roleid = get_role_oid_or_public(NameStr(*username));
1984 12 : mode = convert_table_priv_string(priv_type_text);
1985 :
1986 12 : aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
1987 :
1988 12 : if (is_missing)
1989 0 : PG_RETURN_NULL();
1990 :
1991 12 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1992 : }
1993 :
1994 : /*
1995 : * has_table_privilege_id
1996 : * Check user privileges on a table given
1997 : * table oid, and text priv name.
1998 : * current_user is assumed
1999 : */
2000 : Datum
2001 77 : has_table_privilege_id(PG_FUNCTION_ARGS)
2002 : {
2003 77 : Oid tableoid = PG_GETARG_OID(0);
2004 77 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
2005 : Oid roleid;
2006 : AclMode mode;
2007 : AclResult aclresult;
2008 77 : bool is_missing = false;
2009 :
2010 77 : roleid = GetUserId();
2011 77 : mode = convert_table_priv_string(priv_type_text);
2012 :
2013 77 : aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2014 :
2015 77 : if (is_missing)
2016 5 : PG_RETURN_NULL();
2017 :
2018 72 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2019 : }
2020 :
2021 : /*
2022 : * has_table_privilege_id_name
2023 : * Check user privileges on a table given
2024 : * roleid, text tablename, and text priv name.
2025 : */
2026 : Datum
2027 28 : has_table_privilege_id_name(PG_FUNCTION_ARGS)
2028 : {
2029 28 : Oid roleid = PG_GETARG_OID(0);
2030 28 : text *tablename = PG_GETARG_TEXT_PP(1);
2031 28 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2032 : Oid tableoid;
2033 : AclMode mode;
2034 : AclResult aclresult;
2035 :
2036 28 : tableoid = convert_table_name(tablename);
2037 28 : mode = convert_table_priv_string(priv_type_text);
2038 :
2039 28 : aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2040 :
2041 28 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2042 : }
2043 :
2044 : /*
2045 : * has_table_privilege_id_id
2046 : * Check user privileges on a table given
2047 : * roleid, table oid, and text priv name.
2048 : */
2049 : Datum
2050 24 : has_table_privilege_id_id(PG_FUNCTION_ARGS)
2051 : {
2052 24 : Oid roleid = PG_GETARG_OID(0);
2053 24 : Oid tableoid = PG_GETARG_OID(1);
2054 24 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2055 : AclMode mode;
2056 : AclResult aclresult;
2057 24 : bool is_missing = false;
2058 :
2059 24 : mode = convert_table_priv_string(priv_type_text);
2060 :
2061 24 : aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2062 :
2063 24 : if (is_missing)
2064 0 : PG_RETURN_NULL();
2065 :
2066 24 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2067 : }
2068 :
2069 : /*
2070 : * Support routines for has_table_privilege family.
2071 : */
2072 :
2073 : /*
2074 : * Given a table name expressed as a string, look it up and return Oid
2075 : */
2076 : static Oid
2077 256 : convert_table_name(text *tablename)
2078 : {
2079 : RangeVar *relrv;
2080 :
2081 256 : relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2082 :
2083 : /* We might not even have permissions on this relation; don't lock it. */
2084 256 : return RangeVarGetRelid(relrv, NoLock, false);
2085 : }
2086 :
2087 : /*
2088 : * convert_table_priv_string
2089 : * Convert text string to AclMode value.
2090 : */
2091 : static AclMode
2092 321 : convert_table_priv_string(text *priv_type_text)
2093 : {
2094 : static const priv_map table_priv_map[] = {
2095 : {"SELECT", ACL_SELECT},
2096 : {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2097 : {"INSERT", ACL_INSERT},
2098 : {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2099 : {"UPDATE", ACL_UPDATE},
2100 : {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2101 : {"DELETE", ACL_DELETE},
2102 : {"DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE)},
2103 : {"TRUNCATE", ACL_TRUNCATE},
2104 : {"TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE)},
2105 : {"REFERENCES", ACL_REFERENCES},
2106 : {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2107 : {"TRIGGER", ACL_TRIGGER},
2108 : {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
2109 : {"MAINTAIN", ACL_MAINTAIN},
2110 : {"MAINTAIN WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_MAINTAIN)},
2111 : {NULL, 0}
2112 : };
2113 :
2114 321 : return convert_any_priv_string(priv_type_text, table_priv_map);
2115 : }
2116 :
2117 : /*
2118 : * has_sequence_privilege variants
2119 : * These are all named "has_sequence_privilege" at the SQL level.
2120 : * They take various combinations of relation name, relation OID,
2121 : * user name, user OID, or implicit user = current_user.
2122 : *
2123 : * The result is a boolean value: true if user has the indicated
2124 : * privilege, false if not. The variants that take a relation OID
2125 : * return NULL if the OID doesn't exist.
2126 : */
2127 :
2128 : /*
2129 : * has_sequence_privilege_name_name
2130 : * Check user privileges on a sequence given
2131 : * name username, text sequencename, and text priv name.
2132 : */
2133 : Datum
2134 12 : has_sequence_privilege_name_name(PG_FUNCTION_ARGS)
2135 : {
2136 12 : Name rolename = PG_GETARG_NAME(0);
2137 12 : text *sequencename = PG_GETARG_TEXT_PP(1);
2138 12 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2139 : Oid roleid;
2140 : Oid sequenceoid;
2141 : AclMode mode;
2142 : AclResult aclresult;
2143 :
2144 12 : roleid = get_role_oid_or_public(NameStr(*rolename));
2145 12 : mode = convert_sequence_priv_string(priv_type_text);
2146 8 : sequenceoid = convert_table_name(sequencename);
2147 8 : if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2148 4 : ereport(ERROR,
2149 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2150 : errmsg("\"%s\" is not a sequence",
2151 : text_to_cstring(sequencename))));
2152 :
2153 4 : aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2154 :
2155 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2156 : }
2157 :
2158 : /*
2159 : * has_sequence_privilege_name
2160 : * Check user privileges on a sequence given
2161 : * text sequencename and text priv name.
2162 : * current_user is assumed
2163 : */
2164 : Datum
2165 4 : has_sequence_privilege_name(PG_FUNCTION_ARGS)
2166 : {
2167 4 : text *sequencename = PG_GETARG_TEXT_PP(0);
2168 4 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
2169 : Oid roleid;
2170 : Oid sequenceoid;
2171 : AclMode mode;
2172 : AclResult aclresult;
2173 :
2174 4 : roleid = GetUserId();
2175 4 : mode = convert_sequence_priv_string(priv_type_text);
2176 4 : sequenceoid = convert_table_name(sequencename);
2177 4 : if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2178 0 : ereport(ERROR,
2179 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2180 : errmsg("\"%s\" is not a sequence",
2181 : text_to_cstring(sequencename))));
2182 :
2183 4 : aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2184 :
2185 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2186 : }
2187 :
2188 : /*
2189 : * has_sequence_privilege_name_id
2190 : * Check user privileges on a sequence given
2191 : * name usename, sequence oid, and text priv name.
2192 : */
2193 : Datum
2194 0 : has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
2195 : {
2196 0 : Name username = PG_GETARG_NAME(0);
2197 0 : Oid sequenceoid = PG_GETARG_OID(1);
2198 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2199 : Oid roleid;
2200 : AclMode mode;
2201 : AclResult aclresult;
2202 : char relkind;
2203 0 : bool is_missing = false;
2204 :
2205 0 : roleid = get_role_oid_or_public(NameStr(*username));
2206 0 : mode = convert_sequence_priv_string(priv_type_text);
2207 0 : relkind = get_rel_relkind(sequenceoid);
2208 0 : if (relkind == '\0')
2209 0 : PG_RETURN_NULL();
2210 0 : else if (relkind != RELKIND_SEQUENCE)
2211 0 : ereport(ERROR,
2212 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2213 : errmsg("\"%s\" is not a sequence",
2214 : get_rel_name(sequenceoid))));
2215 :
2216 0 : aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2217 :
2218 0 : if (is_missing)
2219 0 : PG_RETURN_NULL();
2220 :
2221 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2222 : }
2223 :
2224 : /*
2225 : * has_sequence_privilege_id
2226 : * Check user privileges on a sequence given
2227 : * sequence oid, and text priv name.
2228 : * current_user is assumed
2229 : */
2230 : Datum
2231 0 : has_sequence_privilege_id(PG_FUNCTION_ARGS)
2232 : {
2233 0 : Oid sequenceoid = PG_GETARG_OID(0);
2234 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
2235 : Oid roleid;
2236 : AclMode mode;
2237 : AclResult aclresult;
2238 : char relkind;
2239 0 : bool is_missing = false;
2240 :
2241 0 : roleid = GetUserId();
2242 0 : mode = convert_sequence_priv_string(priv_type_text);
2243 0 : relkind = get_rel_relkind(sequenceoid);
2244 0 : if (relkind == '\0')
2245 0 : PG_RETURN_NULL();
2246 0 : else if (relkind != RELKIND_SEQUENCE)
2247 0 : ereport(ERROR,
2248 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2249 : errmsg("\"%s\" is not a sequence",
2250 : get_rel_name(sequenceoid))));
2251 :
2252 0 : aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2253 :
2254 0 : if (is_missing)
2255 0 : PG_RETURN_NULL();
2256 :
2257 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2258 : }
2259 :
2260 : /*
2261 : * has_sequence_privilege_id_name
2262 : * Check user privileges on a sequence given
2263 : * roleid, text sequencename, and text priv name.
2264 : */
2265 : Datum
2266 0 : has_sequence_privilege_id_name(PG_FUNCTION_ARGS)
2267 : {
2268 0 : Oid roleid = PG_GETARG_OID(0);
2269 0 : text *sequencename = PG_GETARG_TEXT_PP(1);
2270 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2271 : Oid sequenceoid;
2272 : AclMode mode;
2273 : AclResult aclresult;
2274 :
2275 0 : mode = convert_sequence_priv_string(priv_type_text);
2276 0 : sequenceoid = convert_table_name(sequencename);
2277 0 : if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
2278 0 : ereport(ERROR,
2279 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2280 : errmsg("\"%s\" is not a sequence",
2281 : text_to_cstring(sequencename))));
2282 :
2283 0 : aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
2284 :
2285 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2286 : }
2287 :
2288 : /*
2289 : * has_sequence_privilege_id_id
2290 : * Check user privileges on a sequence given
2291 : * roleid, sequence oid, and text priv name.
2292 : */
2293 : Datum
2294 0 : has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
2295 : {
2296 0 : Oid roleid = PG_GETARG_OID(0);
2297 0 : Oid sequenceoid = PG_GETARG_OID(1);
2298 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2299 : AclMode mode;
2300 : AclResult aclresult;
2301 : char relkind;
2302 0 : bool is_missing = false;
2303 :
2304 0 : mode = convert_sequence_priv_string(priv_type_text);
2305 0 : relkind = get_rel_relkind(sequenceoid);
2306 0 : if (relkind == '\0')
2307 0 : PG_RETURN_NULL();
2308 0 : else if (relkind != RELKIND_SEQUENCE)
2309 0 : ereport(ERROR,
2310 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2311 : errmsg("\"%s\" is not a sequence",
2312 : get_rel_name(sequenceoid))));
2313 :
2314 0 : aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
2315 :
2316 0 : if (is_missing)
2317 0 : PG_RETURN_NULL();
2318 :
2319 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2320 : }
2321 :
2322 : /*
2323 : * convert_sequence_priv_string
2324 : * Convert text string to AclMode value.
2325 : */
2326 : static AclMode
2327 16 : convert_sequence_priv_string(text *priv_type_text)
2328 : {
2329 : static const priv_map sequence_priv_map[] = {
2330 : {"USAGE", ACL_USAGE},
2331 : {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
2332 : {"SELECT", ACL_SELECT},
2333 : {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2334 : {"UPDATE", ACL_UPDATE},
2335 : {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2336 : {NULL, 0}
2337 : };
2338 :
2339 16 : return convert_any_priv_string(priv_type_text, sequence_priv_map);
2340 : }
2341 :
2342 :
2343 : /*
2344 : * has_any_column_privilege variants
2345 : * These are all named "has_any_column_privilege" at the SQL level.
2346 : * They take various combinations of relation name, relation OID,
2347 : * user name, user OID, or implicit user = current_user.
2348 : *
2349 : * The result is a boolean value: true if user has the indicated
2350 : * privilege for any column of the table, false if not. The variants
2351 : * that take a relation OID return NULL if the OID doesn't exist.
2352 : */
2353 :
2354 : /*
2355 : * has_any_column_privilege_name_name
2356 : * Check user privileges on any column of a table given
2357 : * name username, text tablename, and text priv name.
2358 : */
2359 : Datum
2360 0 : has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
2361 : {
2362 0 : Name rolename = PG_GETARG_NAME(0);
2363 0 : text *tablename = PG_GETARG_TEXT_PP(1);
2364 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2365 : Oid roleid;
2366 : Oid tableoid;
2367 : AclMode mode;
2368 : AclResult aclresult;
2369 :
2370 0 : roleid = get_role_oid_or_public(NameStr(*rolename));
2371 0 : tableoid = convert_table_name(tablename);
2372 0 : mode = convert_column_priv_string(priv_type_text);
2373 :
2374 : /* First check at table level, then examine each column if needed */
2375 0 : aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2376 0 : if (aclresult != ACLCHECK_OK)
2377 0 : aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2378 : ACLMASK_ANY);
2379 :
2380 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2381 : }
2382 :
2383 : /*
2384 : * has_any_column_privilege_name
2385 : * Check user privileges on any column of a table given
2386 : * text tablename and text priv name.
2387 : * current_user is assumed
2388 : */
2389 : Datum
2390 0 : has_any_column_privilege_name(PG_FUNCTION_ARGS)
2391 : {
2392 0 : text *tablename = PG_GETARG_TEXT_PP(0);
2393 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
2394 : Oid roleid;
2395 : Oid tableoid;
2396 : AclMode mode;
2397 : AclResult aclresult;
2398 :
2399 0 : roleid = GetUserId();
2400 0 : tableoid = convert_table_name(tablename);
2401 0 : mode = convert_column_priv_string(priv_type_text);
2402 :
2403 : /* First check at table level, then examine each column if needed */
2404 0 : aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2405 0 : if (aclresult != ACLCHECK_OK)
2406 0 : aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2407 : ACLMASK_ANY);
2408 :
2409 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2410 : }
2411 :
2412 : /*
2413 : * has_any_column_privilege_name_id
2414 : * Check user privileges on any column of a table given
2415 : * name usename, table oid, and text priv name.
2416 : */
2417 : Datum
2418 0 : has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
2419 : {
2420 0 : Name username = PG_GETARG_NAME(0);
2421 0 : Oid tableoid = PG_GETARG_OID(1);
2422 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2423 : Oid roleid;
2424 : AclMode mode;
2425 : AclResult aclresult;
2426 0 : bool is_missing = false;
2427 :
2428 0 : roleid = get_role_oid_or_public(NameStr(*username));
2429 0 : mode = convert_column_priv_string(priv_type_text);
2430 :
2431 : /* First check at table level, then examine each column if needed */
2432 0 : aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2433 0 : if (aclresult != ACLCHECK_OK)
2434 : {
2435 0 : if (is_missing)
2436 0 : PG_RETURN_NULL();
2437 0 : aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2438 : ACLMASK_ANY, &is_missing);
2439 0 : if (is_missing)
2440 0 : PG_RETURN_NULL();
2441 : }
2442 :
2443 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2444 : }
2445 :
2446 : /*
2447 : * has_any_column_privilege_id
2448 : * Check user privileges on any column of a table given
2449 : * table oid, and text priv name.
2450 : * current_user is assumed
2451 : */
2452 : Datum
2453 0 : has_any_column_privilege_id(PG_FUNCTION_ARGS)
2454 : {
2455 0 : Oid tableoid = PG_GETARG_OID(0);
2456 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
2457 : Oid roleid;
2458 : AclMode mode;
2459 : AclResult aclresult;
2460 0 : bool is_missing = false;
2461 :
2462 0 : roleid = GetUserId();
2463 0 : mode = convert_column_priv_string(priv_type_text);
2464 :
2465 : /* First check at table level, then examine each column if needed */
2466 0 : aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2467 0 : if (aclresult != ACLCHECK_OK)
2468 : {
2469 0 : if (is_missing)
2470 0 : PG_RETURN_NULL();
2471 0 : aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2472 : ACLMASK_ANY, &is_missing);
2473 0 : if (is_missing)
2474 0 : PG_RETURN_NULL();
2475 : }
2476 :
2477 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2478 : }
2479 :
2480 : /*
2481 : * has_any_column_privilege_id_name
2482 : * Check user privileges on any column of a table given
2483 : * roleid, text tablename, and text priv name.
2484 : */
2485 : Datum
2486 0 : has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
2487 : {
2488 0 : Oid roleid = PG_GETARG_OID(0);
2489 0 : text *tablename = PG_GETARG_TEXT_PP(1);
2490 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2491 : Oid tableoid;
2492 : AclMode mode;
2493 : AclResult aclresult;
2494 :
2495 0 : tableoid = convert_table_name(tablename);
2496 0 : mode = convert_column_priv_string(priv_type_text);
2497 :
2498 : /* First check at table level, then examine each column if needed */
2499 0 : aclresult = pg_class_aclcheck(tableoid, roleid, mode);
2500 0 : if (aclresult != ACLCHECK_OK)
2501 0 : aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
2502 : ACLMASK_ANY);
2503 :
2504 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2505 : }
2506 :
2507 : /*
2508 : * has_any_column_privilege_id_id
2509 : * Check user privileges on any column of a table given
2510 : * roleid, table oid, and text priv name.
2511 : */
2512 : Datum
2513 0 : has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
2514 : {
2515 0 : Oid roleid = PG_GETARG_OID(0);
2516 0 : Oid tableoid = PG_GETARG_OID(1);
2517 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2518 : AclMode mode;
2519 : AclResult aclresult;
2520 0 : bool is_missing = false;
2521 :
2522 0 : mode = convert_column_priv_string(priv_type_text);
2523 :
2524 : /* First check at table level, then examine each column if needed */
2525 0 : aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2526 0 : if (aclresult != ACLCHECK_OK)
2527 : {
2528 0 : if (is_missing)
2529 0 : PG_RETURN_NULL();
2530 0 : aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
2531 : ACLMASK_ANY, &is_missing);
2532 0 : if (is_missing)
2533 0 : PG_RETURN_NULL();
2534 : }
2535 :
2536 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2537 : }
2538 :
2539 :
2540 : /*
2541 : * has_column_privilege variants
2542 : * These are all named "has_column_privilege" at the SQL level.
2543 : * They take various combinations of relation name, relation OID,
2544 : * column name, column attnum, user name, user OID, or
2545 : * implicit user = current_user.
2546 : *
2547 : * The result is a boolean value: true if user has the indicated
2548 : * privilege, false if not. The variants that take a relation OID
2549 : * return NULL (rather than throwing an error) if that relation OID
2550 : * doesn't exist. Likewise, the variants that take an integer attnum
2551 : * return NULL (rather than throwing an error) if there is no such
2552 : * pg_attribute entry. All variants return NULL if an attisdropped
2553 : * column is selected. These rules are meant to avoid unnecessary
2554 : * failures in queries that scan pg_attribute.
2555 : */
2556 :
2557 : /*
2558 : * column_privilege_check: check column privileges, but don't throw an error
2559 : * for dropped column or table
2560 : *
2561 : * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
2562 : */
2563 : static int
2564 363018 : column_privilege_check(Oid tableoid, AttrNumber attnum,
2565 : Oid roleid, AclMode mode)
2566 : {
2567 : AclResult aclresult;
2568 363018 : bool is_missing = false;
2569 :
2570 : /*
2571 : * If convert_column_name failed, we can just return -1 immediately.
2572 : */
2573 363018 : if (attnum == InvalidAttrNumber)
2574 8 : return -1;
2575 :
2576 : /*
2577 : * Check for column-level privileges first. This serves in part as a check
2578 : * on whether the column even exists, so we need to do it before checking
2579 : * table-level privilege.
2580 : */
2581 363010 : aclresult = pg_attribute_aclcheck_ext(tableoid, attnum, roleid,
2582 : mode, &is_missing);
2583 363010 : if (aclresult == ACLCHECK_OK)
2584 3913 : return 1;
2585 359097 : else if (is_missing)
2586 28 : return -1;
2587 :
2588 : /* Next check if we have the privilege at the table level */
2589 359069 : aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
2590 359069 : if (aclresult == ACLCHECK_OK)
2591 356269 : return 1;
2592 2800 : else if (is_missing)
2593 0 : return -1;
2594 : else
2595 2800 : return 0;
2596 : }
2597 :
2598 : /*
2599 : * has_column_privilege_name_name_name
2600 : * Check user privileges on a column given
2601 : * name username, text tablename, text colname, and text priv name.
2602 : */
2603 : Datum
2604 0 : has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
2605 : {
2606 0 : Name rolename = PG_GETARG_NAME(0);
2607 0 : text *tablename = PG_GETARG_TEXT_PP(1);
2608 0 : text *column = PG_GETARG_TEXT_PP(2);
2609 0 : text *priv_type_text = PG_GETARG_TEXT_PP(3);
2610 : Oid roleid;
2611 : Oid tableoid;
2612 : AttrNumber colattnum;
2613 : AclMode mode;
2614 : int privresult;
2615 :
2616 0 : roleid = get_role_oid_or_public(NameStr(*rolename));
2617 0 : tableoid = convert_table_name(tablename);
2618 0 : colattnum = convert_column_name(tableoid, column);
2619 0 : mode = convert_column_priv_string(priv_type_text);
2620 :
2621 0 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2622 0 : if (privresult < 0)
2623 0 : PG_RETURN_NULL();
2624 0 : PG_RETURN_BOOL(privresult);
2625 : }
2626 :
2627 : /*
2628 : * has_column_privilege_name_name_attnum
2629 : * Check user privileges on a column given
2630 : * name username, text tablename, int attnum, and text priv name.
2631 : */
2632 : Datum
2633 0 : has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
2634 : {
2635 0 : Name rolename = PG_GETARG_NAME(0);
2636 0 : text *tablename = PG_GETARG_TEXT_PP(1);
2637 0 : AttrNumber colattnum = PG_GETARG_INT16(2);
2638 0 : text *priv_type_text = PG_GETARG_TEXT_PP(3);
2639 : Oid roleid;
2640 : Oid tableoid;
2641 : AclMode mode;
2642 : int privresult;
2643 :
2644 0 : roleid = get_role_oid_or_public(NameStr(*rolename));
2645 0 : tableoid = convert_table_name(tablename);
2646 0 : mode = convert_column_priv_string(priv_type_text);
2647 :
2648 0 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2649 0 : if (privresult < 0)
2650 0 : PG_RETURN_NULL();
2651 0 : PG_RETURN_BOOL(privresult);
2652 : }
2653 :
2654 : /*
2655 : * has_column_privilege_name_id_name
2656 : * Check user privileges on a column given
2657 : * name username, table oid, text colname, and text priv name.
2658 : */
2659 : Datum
2660 0 : has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
2661 : {
2662 0 : Name username = PG_GETARG_NAME(0);
2663 0 : Oid tableoid = PG_GETARG_OID(1);
2664 0 : text *column = PG_GETARG_TEXT_PP(2);
2665 0 : text *priv_type_text = PG_GETARG_TEXT_PP(3);
2666 : Oid roleid;
2667 : AttrNumber colattnum;
2668 : AclMode mode;
2669 : int privresult;
2670 :
2671 0 : roleid = get_role_oid_or_public(NameStr(*username));
2672 0 : colattnum = convert_column_name(tableoid, column);
2673 0 : mode = convert_column_priv_string(priv_type_text);
2674 :
2675 0 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2676 0 : if (privresult < 0)
2677 0 : PG_RETURN_NULL();
2678 0 : PG_RETURN_BOOL(privresult);
2679 : }
2680 :
2681 : /*
2682 : * has_column_privilege_name_id_attnum
2683 : * Check user privileges on a column given
2684 : * name username, table oid, int attnum, and text priv name.
2685 : */
2686 : Datum
2687 0 : has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
2688 : {
2689 0 : Name username = PG_GETARG_NAME(0);
2690 0 : Oid tableoid = PG_GETARG_OID(1);
2691 0 : AttrNumber colattnum = PG_GETARG_INT16(2);
2692 0 : text *priv_type_text = PG_GETARG_TEXT_PP(3);
2693 : Oid roleid;
2694 : AclMode mode;
2695 : int privresult;
2696 :
2697 0 : roleid = get_role_oid_or_public(NameStr(*username));
2698 0 : mode = convert_column_priv_string(priv_type_text);
2699 :
2700 0 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2701 0 : if (privresult < 0)
2702 0 : PG_RETURN_NULL();
2703 0 : PG_RETURN_BOOL(privresult);
2704 : }
2705 :
2706 : /*
2707 : * has_column_privilege_id_name_name
2708 : * Check user privileges on a column given
2709 : * oid roleid, text tablename, text colname, and text priv name.
2710 : */
2711 : Datum
2712 0 : has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
2713 : {
2714 0 : Oid roleid = PG_GETARG_OID(0);
2715 0 : text *tablename = PG_GETARG_TEXT_PP(1);
2716 0 : text *column = PG_GETARG_TEXT_PP(2);
2717 0 : text *priv_type_text = PG_GETARG_TEXT_PP(3);
2718 : Oid tableoid;
2719 : AttrNumber colattnum;
2720 : AclMode mode;
2721 : int privresult;
2722 :
2723 0 : tableoid = convert_table_name(tablename);
2724 0 : colattnum = convert_column_name(tableoid, column);
2725 0 : mode = convert_column_priv_string(priv_type_text);
2726 :
2727 0 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2728 0 : if (privresult < 0)
2729 0 : PG_RETURN_NULL();
2730 0 : PG_RETURN_BOOL(privresult);
2731 : }
2732 :
2733 : /*
2734 : * has_column_privilege_id_name_attnum
2735 : * Check user privileges on a column given
2736 : * oid roleid, text tablename, int attnum, and text priv name.
2737 : */
2738 : Datum
2739 0 : has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
2740 : {
2741 0 : Oid roleid = PG_GETARG_OID(0);
2742 0 : text *tablename = PG_GETARG_TEXT_PP(1);
2743 0 : AttrNumber colattnum = PG_GETARG_INT16(2);
2744 0 : text *priv_type_text = PG_GETARG_TEXT_PP(3);
2745 : Oid tableoid;
2746 : AclMode mode;
2747 : int privresult;
2748 :
2749 0 : tableoid = convert_table_name(tablename);
2750 0 : mode = convert_column_priv_string(priv_type_text);
2751 :
2752 0 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2753 0 : if (privresult < 0)
2754 0 : PG_RETURN_NULL();
2755 0 : PG_RETURN_BOOL(privresult);
2756 : }
2757 :
2758 : /*
2759 : * has_column_privilege_id_id_name
2760 : * Check user privileges on a column given
2761 : * oid roleid, table oid, text colname, and text priv name.
2762 : */
2763 : Datum
2764 0 : has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
2765 : {
2766 0 : Oid roleid = PG_GETARG_OID(0);
2767 0 : Oid tableoid = PG_GETARG_OID(1);
2768 0 : text *column = PG_GETARG_TEXT_PP(2);
2769 0 : text *priv_type_text = PG_GETARG_TEXT_PP(3);
2770 : AttrNumber colattnum;
2771 : AclMode mode;
2772 : int privresult;
2773 :
2774 0 : colattnum = convert_column_name(tableoid, column);
2775 0 : mode = convert_column_priv_string(priv_type_text);
2776 :
2777 0 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2778 0 : if (privresult < 0)
2779 0 : PG_RETURN_NULL();
2780 0 : PG_RETURN_BOOL(privresult);
2781 : }
2782 :
2783 : /*
2784 : * has_column_privilege_id_id_attnum
2785 : * Check user privileges on a column given
2786 : * oid roleid, table oid, int attnum, and text priv name.
2787 : */
2788 : Datum
2789 0 : has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
2790 : {
2791 0 : Oid roleid = PG_GETARG_OID(0);
2792 0 : Oid tableoid = PG_GETARG_OID(1);
2793 0 : AttrNumber colattnum = PG_GETARG_INT16(2);
2794 0 : text *priv_type_text = PG_GETARG_TEXT_PP(3);
2795 : AclMode mode;
2796 : int privresult;
2797 :
2798 0 : mode = convert_column_priv_string(priv_type_text);
2799 :
2800 0 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2801 0 : if (privresult < 0)
2802 0 : PG_RETURN_NULL();
2803 0 : PG_RETURN_BOOL(privresult);
2804 : }
2805 :
2806 : /*
2807 : * has_column_privilege_name_name
2808 : * Check user privileges on a column given
2809 : * text tablename, text colname, and text priv name.
2810 : * current_user is assumed
2811 : */
2812 : Datum
2813 12 : has_column_privilege_name_name(PG_FUNCTION_ARGS)
2814 : {
2815 12 : text *tablename = PG_GETARG_TEXT_PP(0);
2816 12 : text *column = PG_GETARG_TEXT_PP(1);
2817 12 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2818 : Oid roleid;
2819 : Oid tableoid;
2820 : AttrNumber colattnum;
2821 : AclMode mode;
2822 : int privresult;
2823 :
2824 12 : roleid = GetUserId();
2825 12 : tableoid = convert_table_name(tablename);
2826 12 : colattnum = convert_column_name(tableoid, column);
2827 4 : mode = convert_column_priv_string(priv_type_text);
2828 :
2829 4 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2830 4 : if (privresult < 0)
2831 4 : PG_RETURN_NULL();
2832 0 : PG_RETURN_BOOL(privresult);
2833 : }
2834 :
2835 : /*
2836 : * has_column_privilege_name_attnum
2837 : * Check user privileges on a column given
2838 : * text tablename, int attnum, and text priv name.
2839 : * current_user is assumed
2840 : */
2841 : Datum
2842 20 : has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
2843 : {
2844 20 : text *tablename = PG_GETARG_TEXT_PP(0);
2845 20 : AttrNumber colattnum = PG_GETARG_INT16(1);
2846 20 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2847 : Oid roleid;
2848 : Oid tableoid;
2849 : AclMode mode;
2850 : int privresult;
2851 :
2852 20 : roleid = GetUserId();
2853 20 : tableoid = convert_table_name(tablename);
2854 20 : mode = convert_column_priv_string(priv_type_text);
2855 :
2856 20 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2857 20 : if (privresult < 0)
2858 20 : PG_RETURN_NULL();
2859 0 : PG_RETURN_BOOL(privresult);
2860 : }
2861 :
2862 : /*
2863 : * has_column_privilege_id_name
2864 : * Check user privileges on a column given
2865 : * table oid, text colname, and text priv name.
2866 : * current_user is assumed
2867 : */
2868 : Datum
2869 4 : has_column_privilege_id_name(PG_FUNCTION_ARGS)
2870 : {
2871 4 : Oid tableoid = PG_GETARG_OID(0);
2872 4 : text *column = PG_GETARG_TEXT_PP(1);
2873 4 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2874 : Oid roleid;
2875 : AttrNumber colattnum;
2876 : AclMode mode;
2877 : int privresult;
2878 :
2879 4 : roleid = GetUserId();
2880 4 : colattnum = convert_column_name(tableoid, column);
2881 4 : mode = convert_column_priv_string(priv_type_text);
2882 :
2883 4 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2884 4 : if (privresult < 0)
2885 4 : PG_RETURN_NULL();
2886 0 : PG_RETURN_BOOL(privresult);
2887 : }
2888 :
2889 : /*
2890 : * has_column_privilege_id_attnum
2891 : * Check user privileges on a column given
2892 : * table oid, int attnum, and text priv name.
2893 : * current_user is assumed
2894 : */
2895 : Datum
2896 362990 : has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
2897 : {
2898 362990 : Oid tableoid = PG_GETARG_OID(0);
2899 362990 : AttrNumber colattnum = PG_GETARG_INT16(1);
2900 362990 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
2901 : Oid roleid;
2902 : AclMode mode;
2903 : int privresult;
2904 :
2905 362990 : roleid = GetUserId();
2906 362990 : mode = convert_column_priv_string(priv_type_text);
2907 :
2908 362990 : privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2909 362990 : if (privresult < 0)
2910 8 : PG_RETURN_NULL();
2911 362982 : PG_RETURN_BOOL(privresult);
2912 : }
2913 :
2914 : /*
2915 : * Support routines for has_column_privilege family.
2916 : */
2917 :
2918 : /*
2919 : * Given a table OID and a column name expressed as a string, look it up
2920 : * and return the column number. Returns InvalidAttrNumber in cases
2921 : * where caller should return NULL instead of failing.
2922 : */
2923 : static AttrNumber
2924 16 : convert_column_name(Oid tableoid, text *column)
2925 : {
2926 : char *colname;
2927 : HeapTuple attTuple;
2928 : AttrNumber attnum;
2929 :
2930 16 : colname = text_to_cstring(column);
2931 :
2932 : /*
2933 : * We don't use get_attnum() here because it will report that dropped
2934 : * columns don't exist. We need to treat dropped columns differently from
2935 : * nonexistent columns.
2936 : */
2937 16 : attTuple = SearchSysCache2(ATTNAME,
2938 : ObjectIdGetDatum(tableoid),
2939 : CStringGetDatum(colname));
2940 16 : if (HeapTupleIsValid(attTuple))
2941 : {
2942 : Form_pg_attribute attributeForm;
2943 :
2944 4 : attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
2945 : /* We want to return NULL for dropped columns */
2946 4 : if (attributeForm->attisdropped)
2947 4 : attnum = InvalidAttrNumber;
2948 : else
2949 0 : attnum = attributeForm->attnum;
2950 4 : ReleaseSysCache(attTuple);
2951 : }
2952 : else
2953 : {
2954 12 : char *tablename = get_rel_name(tableoid);
2955 :
2956 : /*
2957 : * If the table OID is bogus, or it's just been dropped, we'll get
2958 : * NULL back. In such cases we want has_column_privilege to return
2959 : * NULL too, so just return InvalidAttrNumber.
2960 : */
2961 12 : if (tablename != NULL)
2962 : {
2963 : /* tableoid exists, colname does not, so throw error */
2964 8 : ereport(ERROR,
2965 : (errcode(ERRCODE_UNDEFINED_COLUMN),
2966 : errmsg("column \"%s\" of relation \"%s\" does not exist",
2967 : colname, tablename)));
2968 : }
2969 : /* tableoid doesn't exist, so act like attisdropped case */
2970 4 : attnum = InvalidAttrNumber;
2971 : }
2972 :
2973 8 : pfree(colname);
2974 8 : return attnum;
2975 : }
2976 :
2977 : /*
2978 : * convert_column_priv_string
2979 : * Convert text string to AclMode value.
2980 : */
2981 : static AclMode
2982 363018 : convert_column_priv_string(text *priv_type_text)
2983 : {
2984 : static const priv_map column_priv_map[] = {
2985 : {"SELECT", ACL_SELECT},
2986 : {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
2987 : {"INSERT", ACL_INSERT},
2988 : {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
2989 : {"UPDATE", ACL_UPDATE},
2990 : {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
2991 : {"REFERENCES", ACL_REFERENCES},
2992 : {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
2993 : {NULL, 0}
2994 : };
2995 :
2996 363018 : return convert_any_priv_string(priv_type_text, column_priv_map);
2997 : }
2998 :
2999 :
3000 : /*
3001 : * has_database_privilege variants
3002 : * These are all named "has_database_privilege" at the SQL level.
3003 : * They take various combinations of database name, database OID,
3004 : * user name, user OID, or implicit user = current_user.
3005 : *
3006 : * The result is a boolean value: true if user has the indicated
3007 : * privilege, false if not, or NULL if object doesn't exist.
3008 : */
3009 :
3010 : /*
3011 : * has_database_privilege_name_name
3012 : * Check user privileges on a database given
3013 : * name username, text databasename, and text priv name.
3014 : */
3015 : Datum
3016 0 : has_database_privilege_name_name(PG_FUNCTION_ARGS)
3017 : {
3018 0 : Name username = PG_GETARG_NAME(0);
3019 0 : text *databasename = PG_GETARG_TEXT_PP(1);
3020 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3021 : Oid roleid;
3022 : Oid databaseoid;
3023 : AclMode mode;
3024 : AclResult aclresult;
3025 :
3026 0 : roleid = get_role_oid_or_public(NameStr(*username));
3027 0 : databaseoid = convert_database_name(databasename);
3028 0 : mode = convert_database_priv_string(priv_type_text);
3029 :
3030 0 : aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3031 :
3032 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3033 : }
3034 :
3035 : /*
3036 : * has_database_privilege_name
3037 : * Check user privileges on a database given
3038 : * text databasename and text priv name.
3039 : * current_user is assumed
3040 : */
3041 : Datum
3042 0 : has_database_privilege_name(PG_FUNCTION_ARGS)
3043 : {
3044 0 : text *databasename = PG_GETARG_TEXT_PP(0);
3045 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3046 : Oid roleid;
3047 : Oid databaseoid;
3048 : AclMode mode;
3049 : AclResult aclresult;
3050 :
3051 0 : roleid = GetUserId();
3052 0 : databaseoid = convert_database_name(databasename);
3053 0 : mode = convert_database_priv_string(priv_type_text);
3054 :
3055 0 : aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3056 :
3057 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3058 : }
3059 :
3060 : /*
3061 : * has_database_privilege_name_id
3062 : * Check user privileges on a database given
3063 : * name usename, database oid, and text priv name.
3064 : */
3065 : Datum
3066 0 : has_database_privilege_name_id(PG_FUNCTION_ARGS)
3067 : {
3068 0 : Name username = PG_GETARG_NAME(0);
3069 0 : Oid databaseoid = PG_GETARG_OID(1);
3070 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3071 : Oid roleid;
3072 : AclMode mode;
3073 : AclResult aclresult;
3074 0 : bool is_missing = false;
3075 :
3076 0 : roleid = get_role_oid_or_public(NameStr(*username));
3077 0 : mode = convert_database_priv_string(priv_type_text);
3078 :
3079 0 : aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3080 : roleid, mode,
3081 : &is_missing);
3082 :
3083 0 : if (is_missing)
3084 0 : PG_RETURN_NULL();
3085 :
3086 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3087 : }
3088 :
3089 : /*
3090 : * has_database_privilege_id
3091 : * Check user privileges on a database given
3092 : * database oid, and text priv name.
3093 : * current_user is assumed
3094 : */
3095 : Datum
3096 0 : has_database_privilege_id(PG_FUNCTION_ARGS)
3097 : {
3098 0 : Oid databaseoid = PG_GETARG_OID(0);
3099 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3100 : Oid roleid;
3101 : AclMode mode;
3102 : AclResult aclresult;
3103 0 : bool is_missing = false;
3104 :
3105 0 : roleid = GetUserId();
3106 0 : mode = convert_database_priv_string(priv_type_text);
3107 :
3108 0 : aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3109 : roleid, mode,
3110 : &is_missing);
3111 :
3112 0 : if (is_missing)
3113 0 : PG_RETURN_NULL();
3114 :
3115 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3116 : }
3117 :
3118 : /*
3119 : * has_database_privilege_id_name
3120 : * Check user privileges on a database given
3121 : * roleid, text databasename, and text priv name.
3122 : */
3123 : Datum
3124 0 : has_database_privilege_id_name(PG_FUNCTION_ARGS)
3125 : {
3126 0 : Oid roleid = PG_GETARG_OID(0);
3127 0 : text *databasename = PG_GETARG_TEXT_PP(1);
3128 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3129 : Oid databaseoid;
3130 : AclMode mode;
3131 : AclResult aclresult;
3132 :
3133 0 : databaseoid = convert_database_name(databasename);
3134 0 : mode = convert_database_priv_string(priv_type_text);
3135 :
3136 0 : aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
3137 :
3138 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3139 : }
3140 :
3141 : /*
3142 : * has_database_privilege_id_id
3143 : * Check user privileges on a database given
3144 : * roleid, database oid, and text priv name.
3145 : */
3146 : Datum
3147 0 : has_database_privilege_id_id(PG_FUNCTION_ARGS)
3148 : {
3149 0 : Oid roleid = PG_GETARG_OID(0);
3150 0 : Oid databaseoid = PG_GETARG_OID(1);
3151 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3152 : AclMode mode;
3153 : AclResult aclresult;
3154 0 : bool is_missing = false;
3155 :
3156 0 : mode = convert_database_priv_string(priv_type_text);
3157 :
3158 0 : aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
3159 : roleid, mode,
3160 : &is_missing);
3161 :
3162 0 : if (is_missing)
3163 0 : PG_RETURN_NULL();
3164 :
3165 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3166 : }
3167 :
3168 : /*
3169 : * Support routines for has_database_privilege family.
3170 : */
3171 :
3172 : /*
3173 : * Given a database name expressed as a string, look it up and return Oid
3174 : */
3175 : static Oid
3176 0 : convert_database_name(text *databasename)
3177 : {
3178 0 : char *dbname = text_to_cstring(databasename);
3179 :
3180 0 : return get_database_oid(dbname, false);
3181 : }
3182 :
3183 : /*
3184 : * convert_database_priv_string
3185 : * Convert text string to AclMode value.
3186 : */
3187 : static AclMode
3188 0 : convert_database_priv_string(text *priv_type_text)
3189 : {
3190 : static const priv_map database_priv_map[] = {
3191 : {"CREATE", ACL_CREATE},
3192 : {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
3193 : {"TEMPORARY", ACL_CREATE_TEMP},
3194 : {"TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
3195 : {"TEMP", ACL_CREATE_TEMP},
3196 : {"TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
3197 : {"CONNECT", ACL_CONNECT},
3198 : {"CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT)},
3199 : {NULL, 0}
3200 : };
3201 :
3202 0 : return convert_any_priv_string(priv_type_text, database_priv_map);
3203 : }
3204 :
3205 :
3206 : /*
3207 : * has_foreign_data_wrapper_privilege variants
3208 : * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
3209 : * They take various combinations of foreign-data wrapper name,
3210 : * fdw OID, user name, user OID, or implicit user = current_user.
3211 : *
3212 : * The result is a boolean value: true if user has the indicated
3213 : * privilege, false if not.
3214 : */
3215 :
3216 : /*
3217 : * has_foreign_data_wrapper_privilege_name_name
3218 : * Check user privileges on a foreign-data wrapper given
3219 : * name username, text fdwname, and text priv name.
3220 : */
3221 : Datum
3222 8 : has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
3223 : {
3224 8 : Name username = PG_GETARG_NAME(0);
3225 8 : text *fdwname = PG_GETARG_TEXT_PP(1);
3226 8 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3227 : Oid roleid;
3228 : Oid fdwid;
3229 : AclMode mode;
3230 : AclResult aclresult;
3231 :
3232 8 : roleid = get_role_oid_or_public(NameStr(*username));
3233 8 : fdwid = convert_foreign_data_wrapper_name(fdwname);
3234 8 : mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3235 :
3236 8 : aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3237 :
3238 8 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3239 : }
3240 :
3241 : /*
3242 : * has_foreign_data_wrapper_privilege_name
3243 : * Check user privileges on a foreign-data wrapper given
3244 : * text fdwname and text priv name.
3245 : * current_user is assumed
3246 : */
3247 : Datum
3248 4 : has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
3249 : {
3250 4 : text *fdwname = PG_GETARG_TEXT_PP(0);
3251 4 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3252 : Oid roleid;
3253 : Oid fdwid;
3254 : AclMode mode;
3255 : AclResult aclresult;
3256 :
3257 4 : roleid = GetUserId();
3258 4 : fdwid = convert_foreign_data_wrapper_name(fdwname);
3259 4 : mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3260 :
3261 4 : aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3262 :
3263 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3264 : }
3265 :
3266 : /*
3267 : * has_foreign_data_wrapper_privilege_name_id
3268 : * Check user privileges on a foreign-data wrapper given
3269 : * name usename, foreign-data wrapper oid, and text priv name.
3270 : */
3271 : Datum
3272 4 : has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
3273 : {
3274 4 : Name username = PG_GETARG_NAME(0);
3275 4 : Oid fdwid = PG_GETARG_OID(1);
3276 4 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3277 : Oid roleid;
3278 : AclMode mode;
3279 : AclResult aclresult;
3280 4 : bool is_missing = false;
3281 :
3282 4 : roleid = get_role_oid_or_public(NameStr(*username));
3283 4 : mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3284 :
3285 4 : aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3286 : roleid, mode,
3287 : &is_missing);
3288 :
3289 4 : if (is_missing)
3290 0 : PG_RETURN_NULL();
3291 :
3292 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3293 : }
3294 :
3295 : /*
3296 : * has_foreign_data_wrapper_privilege_id
3297 : * Check user privileges on a foreign-data wrapper given
3298 : * foreign-data wrapper oid, and text priv name.
3299 : * current_user is assumed
3300 : */
3301 : Datum
3302 4 : has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
3303 : {
3304 4 : Oid fdwid = PG_GETARG_OID(0);
3305 4 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3306 : Oid roleid;
3307 : AclMode mode;
3308 : AclResult aclresult;
3309 4 : bool is_missing = false;
3310 :
3311 4 : roleid = GetUserId();
3312 4 : mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3313 :
3314 4 : aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3315 : roleid, mode,
3316 : &is_missing);
3317 :
3318 4 : if (is_missing)
3319 0 : PG_RETURN_NULL();
3320 :
3321 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3322 : }
3323 :
3324 : /*
3325 : * has_foreign_data_wrapper_privilege_id_name
3326 : * Check user privileges on a foreign-data wrapper given
3327 : * roleid, text fdwname, and text priv name.
3328 : */
3329 : Datum
3330 4 : has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
3331 : {
3332 4 : Oid roleid = PG_GETARG_OID(0);
3333 4 : text *fdwname = PG_GETARG_TEXT_PP(1);
3334 4 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3335 : Oid fdwid;
3336 : AclMode mode;
3337 : AclResult aclresult;
3338 :
3339 4 : fdwid = convert_foreign_data_wrapper_name(fdwname);
3340 4 : mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3341 :
3342 4 : aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
3343 :
3344 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3345 : }
3346 :
3347 : /*
3348 : * has_foreign_data_wrapper_privilege_id_id
3349 : * Check user privileges on a foreign-data wrapper given
3350 : * roleid, fdw oid, and text priv name.
3351 : */
3352 : Datum
3353 4 : has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
3354 : {
3355 4 : Oid roleid = PG_GETARG_OID(0);
3356 4 : Oid fdwid = PG_GETARG_OID(1);
3357 4 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3358 : AclMode mode;
3359 : AclResult aclresult;
3360 4 : bool is_missing = false;
3361 :
3362 4 : mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
3363 :
3364 4 : aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
3365 : roleid, mode,
3366 : &is_missing);
3367 :
3368 4 : if (is_missing)
3369 0 : PG_RETURN_NULL();
3370 :
3371 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3372 : }
3373 :
3374 : /*
3375 : * Support routines for has_foreign_data_wrapper_privilege family.
3376 : */
3377 :
3378 : /*
3379 : * Given a FDW name expressed as a string, look it up and return Oid
3380 : */
3381 : static Oid
3382 16 : convert_foreign_data_wrapper_name(text *fdwname)
3383 : {
3384 16 : char *fdwstr = text_to_cstring(fdwname);
3385 :
3386 16 : return get_foreign_data_wrapper_oid(fdwstr, false);
3387 : }
3388 :
3389 : /*
3390 : * convert_foreign_data_wrapper_priv_string
3391 : * Convert text string to AclMode value.
3392 : */
3393 : static AclMode
3394 28 : convert_foreign_data_wrapper_priv_string(text *priv_type_text)
3395 : {
3396 : static const priv_map foreign_data_wrapper_priv_map[] = {
3397 : {"USAGE", ACL_USAGE},
3398 : {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3399 : {NULL, 0}
3400 : };
3401 :
3402 28 : return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
3403 : }
3404 :
3405 :
3406 : /*
3407 : * has_function_privilege variants
3408 : * These are all named "has_function_privilege" at the SQL level.
3409 : * They take various combinations of function name, function OID,
3410 : * user name, user OID, or implicit user = current_user.
3411 : *
3412 : * The result is a boolean value: true if user has the indicated
3413 : * privilege, false if not, or NULL if object doesn't exist.
3414 : */
3415 :
3416 : /*
3417 : * has_function_privilege_name_name
3418 : * Check user privileges on a function given
3419 : * name username, text functionname, and text priv name.
3420 : */
3421 : Datum
3422 120 : has_function_privilege_name_name(PG_FUNCTION_ARGS)
3423 : {
3424 120 : Name username = PG_GETARG_NAME(0);
3425 120 : text *functionname = PG_GETARG_TEXT_PP(1);
3426 120 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3427 : Oid roleid;
3428 : Oid functionoid;
3429 : AclMode mode;
3430 : AclResult aclresult;
3431 :
3432 120 : roleid = get_role_oid_or_public(NameStr(*username));
3433 120 : functionoid = convert_function_name(functionname);
3434 120 : mode = convert_function_priv_string(priv_type_text);
3435 :
3436 120 : aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3437 :
3438 120 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3439 : }
3440 :
3441 : /*
3442 : * has_function_privilege_name
3443 : * Check user privileges on a function given
3444 : * text functionname and text priv name.
3445 : * current_user is assumed
3446 : */
3447 : Datum
3448 0 : has_function_privilege_name(PG_FUNCTION_ARGS)
3449 : {
3450 0 : text *functionname = PG_GETARG_TEXT_PP(0);
3451 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3452 : Oid roleid;
3453 : Oid functionoid;
3454 : AclMode mode;
3455 : AclResult aclresult;
3456 :
3457 0 : roleid = GetUserId();
3458 0 : functionoid = convert_function_name(functionname);
3459 0 : mode = convert_function_priv_string(priv_type_text);
3460 :
3461 0 : aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3462 :
3463 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3464 : }
3465 :
3466 : /*
3467 : * has_function_privilege_name_id
3468 : * Check user privileges on a function given
3469 : * name usename, function oid, and text priv name.
3470 : */
3471 : Datum
3472 0 : has_function_privilege_name_id(PG_FUNCTION_ARGS)
3473 : {
3474 0 : Name username = PG_GETARG_NAME(0);
3475 0 : Oid functionoid = PG_GETARG_OID(1);
3476 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3477 : Oid roleid;
3478 : AclMode mode;
3479 : AclResult aclresult;
3480 0 : bool is_missing = false;
3481 :
3482 0 : roleid = get_role_oid_or_public(NameStr(*username));
3483 0 : mode = convert_function_priv_string(priv_type_text);
3484 :
3485 0 : aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3486 : roleid, mode,
3487 : &is_missing);
3488 :
3489 0 : if (is_missing)
3490 0 : PG_RETURN_NULL();
3491 :
3492 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3493 : }
3494 :
3495 : /*
3496 : * has_function_privilege_id
3497 : * Check user privileges on a function given
3498 : * function oid, and text priv name.
3499 : * current_user is assumed
3500 : */
3501 : Datum
3502 0 : has_function_privilege_id(PG_FUNCTION_ARGS)
3503 : {
3504 0 : Oid functionoid = PG_GETARG_OID(0);
3505 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3506 : Oid roleid;
3507 : AclMode mode;
3508 : AclResult aclresult;
3509 0 : bool is_missing = false;
3510 :
3511 0 : roleid = GetUserId();
3512 0 : mode = convert_function_priv_string(priv_type_text);
3513 :
3514 0 : aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3515 : roleid, mode,
3516 : &is_missing);
3517 :
3518 0 : if (is_missing)
3519 0 : PG_RETURN_NULL();
3520 :
3521 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3522 : }
3523 :
3524 : /*
3525 : * has_function_privilege_id_name
3526 : * Check user privileges on a function given
3527 : * roleid, text functionname, and text priv name.
3528 : */
3529 : Datum
3530 0 : has_function_privilege_id_name(PG_FUNCTION_ARGS)
3531 : {
3532 0 : Oid roleid = PG_GETARG_OID(0);
3533 0 : text *functionname = PG_GETARG_TEXT_PP(1);
3534 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3535 : Oid functionoid;
3536 : AclMode mode;
3537 : AclResult aclresult;
3538 :
3539 0 : functionoid = convert_function_name(functionname);
3540 0 : mode = convert_function_priv_string(priv_type_text);
3541 :
3542 0 : aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
3543 :
3544 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3545 : }
3546 :
3547 : /*
3548 : * has_function_privilege_id_id
3549 : * Check user privileges on a function given
3550 : * roleid, function oid, and text priv name.
3551 : */
3552 : Datum
3553 0 : has_function_privilege_id_id(PG_FUNCTION_ARGS)
3554 : {
3555 0 : Oid roleid = PG_GETARG_OID(0);
3556 0 : Oid functionoid = PG_GETARG_OID(1);
3557 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3558 : AclMode mode;
3559 : AclResult aclresult;
3560 0 : bool is_missing = false;
3561 :
3562 0 : mode = convert_function_priv_string(priv_type_text);
3563 :
3564 0 : aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
3565 : roleid, mode,
3566 : &is_missing);
3567 :
3568 0 : if (is_missing)
3569 0 : PG_RETURN_NULL();
3570 :
3571 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3572 : }
3573 :
3574 : /*
3575 : * Support routines for has_function_privilege family.
3576 : */
3577 :
3578 : /*
3579 : * Given a function name expressed as a string, look it up and return Oid
3580 : */
3581 : static Oid
3582 120 : convert_function_name(text *functionname)
3583 : {
3584 120 : char *funcname = text_to_cstring(functionname);
3585 : Oid oid;
3586 :
3587 120 : oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
3588 : CStringGetDatum(funcname)));
3589 :
3590 120 : if (!OidIsValid(oid))
3591 0 : ereport(ERROR,
3592 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
3593 : errmsg("function \"%s\" does not exist", funcname)));
3594 :
3595 120 : return oid;
3596 : }
3597 :
3598 : /*
3599 : * convert_function_priv_string
3600 : * Convert text string to AclMode value.
3601 : */
3602 : static AclMode
3603 120 : convert_function_priv_string(text *priv_type_text)
3604 : {
3605 : static const priv_map function_priv_map[] = {
3606 : {"EXECUTE", ACL_EXECUTE},
3607 : {"EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE)},
3608 : {NULL, 0}
3609 : };
3610 :
3611 120 : return convert_any_priv_string(priv_type_text, function_priv_map);
3612 : }
3613 :
3614 :
3615 : /*
3616 : * has_language_privilege variants
3617 : * These are all named "has_language_privilege" at the SQL level.
3618 : * They take various combinations of language name, language OID,
3619 : * user name, user OID, or implicit user = current_user.
3620 : *
3621 : * The result is a boolean value: true if user has the indicated
3622 : * privilege, false if not, or NULL if object doesn't exist.
3623 : */
3624 :
3625 : /*
3626 : * has_language_privilege_name_name
3627 : * Check user privileges on a language given
3628 : * name username, text languagename, and text priv name.
3629 : */
3630 : Datum
3631 0 : has_language_privilege_name_name(PG_FUNCTION_ARGS)
3632 : {
3633 0 : Name username = PG_GETARG_NAME(0);
3634 0 : text *languagename = PG_GETARG_TEXT_PP(1);
3635 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3636 : Oid roleid;
3637 : Oid languageoid;
3638 : AclMode mode;
3639 : AclResult aclresult;
3640 :
3641 0 : roleid = get_role_oid_or_public(NameStr(*username));
3642 0 : languageoid = convert_language_name(languagename);
3643 0 : mode = convert_language_priv_string(priv_type_text);
3644 :
3645 0 : aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3646 :
3647 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3648 : }
3649 :
3650 : /*
3651 : * has_language_privilege_name
3652 : * Check user privileges on a language given
3653 : * text languagename and text priv name.
3654 : * current_user is assumed
3655 : */
3656 : Datum
3657 0 : has_language_privilege_name(PG_FUNCTION_ARGS)
3658 : {
3659 0 : text *languagename = PG_GETARG_TEXT_PP(0);
3660 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3661 : Oid roleid;
3662 : Oid languageoid;
3663 : AclMode mode;
3664 : AclResult aclresult;
3665 :
3666 0 : roleid = GetUserId();
3667 0 : languageoid = convert_language_name(languagename);
3668 0 : mode = convert_language_priv_string(priv_type_text);
3669 :
3670 0 : aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3671 :
3672 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3673 : }
3674 :
3675 : /*
3676 : * has_language_privilege_name_id
3677 : * Check user privileges on a language given
3678 : * name usename, language oid, and text priv name.
3679 : */
3680 : Datum
3681 0 : has_language_privilege_name_id(PG_FUNCTION_ARGS)
3682 : {
3683 0 : Name username = PG_GETARG_NAME(0);
3684 0 : Oid languageoid = PG_GETARG_OID(1);
3685 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3686 : Oid roleid;
3687 : AclMode mode;
3688 : AclResult aclresult;
3689 0 : bool is_missing = false;
3690 :
3691 0 : roleid = get_role_oid_or_public(NameStr(*username));
3692 0 : mode = convert_language_priv_string(priv_type_text);
3693 :
3694 0 : aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3695 : roleid, mode,
3696 : &is_missing);
3697 :
3698 0 : if (is_missing)
3699 0 : PG_RETURN_NULL();
3700 :
3701 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3702 : }
3703 :
3704 : /*
3705 : * has_language_privilege_id
3706 : * Check user privileges on a language given
3707 : * language oid, and text priv name.
3708 : * current_user is assumed
3709 : */
3710 : Datum
3711 0 : has_language_privilege_id(PG_FUNCTION_ARGS)
3712 : {
3713 0 : Oid languageoid = PG_GETARG_OID(0);
3714 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3715 : Oid roleid;
3716 : AclMode mode;
3717 : AclResult aclresult;
3718 0 : bool is_missing = false;
3719 :
3720 0 : roleid = GetUserId();
3721 0 : mode = convert_language_priv_string(priv_type_text);
3722 :
3723 0 : aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3724 : roleid, mode,
3725 : &is_missing);
3726 :
3727 0 : if (is_missing)
3728 0 : PG_RETURN_NULL();
3729 :
3730 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3731 : }
3732 :
3733 : /*
3734 : * has_language_privilege_id_name
3735 : * Check user privileges on a language given
3736 : * roleid, text languagename, and text priv name.
3737 : */
3738 : Datum
3739 0 : has_language_privilege_id_name(PG_FUNCTION_ARGS)
3740 : {
3741 0 : Oid roleid = PG_GETARG_OID(0);
3742 0 : text *languagename = PG_GETARG_TEXT_PP(1);
3743 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3744 : Oid languageoid;
3745 : AclMode mode;
3746 : AclResult aclresult;
3747 :
3748 0 : languageoid = convert_language_name(languagename);
3749 0 : mode = convert_language_priv_string(priv_type_text);
3750 :
3751 0 : aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
3752 :
3753 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3754 : }
3755 :
3756 : /*
3757 : * has_language_privilege_id_id
3758 : * Check user privileges on a language given
3759 : * roleid, language oid, and text priv name.
3760 : */
3761 : Datum
3762 0 : has_language_privilege_id_id(PG_FUNCTION_ARGS)
3763 : {
3764 0 : Oid roleid = PG_GETARG_OID(0);
3765 0 : Oid languageoid = PG_GETARG_OID(1);
3766 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3767 : AclMode mode;
3768 : AclResult aclresult;
3769 0 : bool is_missing = false;
3770 :
3771 0 : mode = convert_language_priv_string(priv_type_text);
3772 :
3773 0 : aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
3774 : roleid, mode,
3775 : &is_missing);
3776 :
3777 0 : if (is_missing)
3778 0 : PG_RETURN_NULL();
3779 :
3780 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3781 : }
3782 :
3783 : /*
3784 : * Support routines for has_language_privilege family.
3785 : */
3786 :
3787 : /*
3788 : * Given a language name expressed as a string, look it up and return Oid
3789 : */
3790 : static Oid
3791 0 : convert_language_name(text *languagename)
3792 : {
3793 0 : char *langname = text_to_cstring(languagename);
3794 :
3795 0 : return get_language_oid(langname, false);
3796 : }
3797 :
3798 : /*
3799 : * convert_language_priv_string
3800 : * Convert text string to AclMode value.
3801 : */
3802 : static AclMode
3803 0 : convert_language_priv_string(text *priv_type_text)
3804 : {
3805 : static const priv_map language_priv_map[] = {
3806 : {"USAGE", ACL_USAGE},
3807 : {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
3808 : {NULL, 0}
3809 : };
3810 :
3811 0 : return convert_any_priv_string(priv_type_text, language_priv_map);
3812 : }
3813 :
3814 :
3815 : /*
3816 : * has_schema_privilege variants
3817 : * These are all named "has_schema_privilege" at the SQL level.
3818 : * They take various combinations of schema name, schema OID,
3819 : * user name, user OID, or implicit user = current_user.
3820 : *
3821 : * The result is a boolean value: true if user has the indicated
3822 : * privilege, false if not, or NULL if object doesn't exist.
3823 : */
3824 :
3825 : /*
3826 : * has_schema_privilege_name_name
3827 : * Check user privileges on a schema given
3828 : * name username, text schemaname, and text priv name.
3829 : */
3830 : Datum
3831 36 : has_schema_privilege_name_name(PG_FUNCTION_ARGS)
3832 : {
3833 36 : Name username = PG_GETARG_NAME(0);
3834 36 : text *schemaname = PG_GETARG_TEXT_PP(1);
3835 36 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3836 : Oid roleid;
3837 : Oid schemaoid;
3838 : AclMode mode;
3839 : AclResult aclresult;
3840 :
3841 36 : roleid = get_role_oid_or_public(NameStr(*username));
3842 36 : schemaoid = convert_schema_name(schemaname);
3843 36 : mode = convert_schema_priv_string(priv_type_text);
3844 :
3845 36 : aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3846 :
3847 36 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3848 : }
3849 :
3850 : /*
3851 : * has_schema_privilege_name
3852 : * Check user privileges on a schema given
3853 : * text schemaname and text priv name.
3854 : * current_user is assumed
3855 : */
3856 : Datum
3857 0 : has_schema_privilege_name(PG_FUNCTION_ARGS)
3858 : {
3859 0 : text *schemaname = PG_GETARG_TEXT_PP(0);
3860 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3861 : Oid roleid;
3862 : Oid schemaoid;
3863 : AclMode mode;
3864 : AclResult aclresult;
3865 :
3866 0 : roleid = GetUserId();
3867 0 : schemaoid = convert_schema_name(schemaname);
3868 0 : mode = convert_schema_priv_string(priv_type_text);
3869 :
3870 0 : aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3871 :
3872 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3873 : }
3874 :
3875 : /*
3876 : * has_schema_privilege_name_id
3877 : * Check user privileges on a schema given
3878 : * name usename, schema oid, and text priv name.
3879 : */
3880 : Datum
3881 0 : has_schema_privilege_name_id(PG_FUNCTION_ARGS)
3882 : {
3883 0 : Name username = PG_GETARG_NAME(0);
3884 0 : Oid schemaoid = PG_GETARG_OID(1);
3885 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3886 : Oid roleid;
3887 : AclMode mode;
3888 : AclResult aclresult;
3889 0 : bool is_missing = false;
3890 :
3891 0 : roleid = get_role_oid_or_public(NameStr(*username));
3892 0 : mode = convert_schema_priv_string(priv_type_text);
3893 :
3894 0 : aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3895 : roleid, mode,
3896 : &is_missing);
3897 :
3898 0 : if (is_missing)
3899 0 : PG_RETURN_NULL();
3900 :
3901 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3902 : }
3903 :
3904 : /*
3905 : * has_schema_privilege_id
3906 : * Check user privileges on a schema given
3907 : * schema oid, and text priv name.
3908 : * current_user is assumed
3909 : */
3910 : Datum
3911 0 : has_schema_privilege_id(PG_FUNCTION_ARGS)
3912 : {
3913 0 : Oid schemaoid = PG_GETARG_OID(0);
3914 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
3915 : Oid roleid;
3916 : AclMode mode;
3917 : AclResult aclresult;
3918 0 : bool is_missing = false;
3919 :
3920 0 : roleid = GetUserId();
3921 0 : mode = convert_schema_priv_string(priv_type_text);
3922 :
3923 0 : aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3924 : roleid, mode,
3925 : &is_missing);
3926 :
3927 0 : if (is_missing)
3928 0 : PG_RETURN_NULL();
3929 :
3930 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3931 : }
3932 :
3933 : /*
3934 : * has_schema_privilege_id_name
3935 : * Check user privileges on a schema given
3936 : * roleid, text schemaname, and text priv name.
3937 : */
3938 : Datum
3939 0 : has_schema_privilege_id_name(PG_FUNCTION_ARGS)
3940 : {
3941 0 : Oid roleid = PG_GETARG_OID(0);
3942 0 : text *schemaname = PG_GETARG_TEXT_PP(1);
3943 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3944 : Oid schemaoid;
3945 : AclMode mode;
3946 : AclResult aclresult;
3947 :
3948 0 : schemaoid = convert_schema_name(schemaname);
3949 0 : mode = convert_schema_priv_string(priv_type_text);
3950 :
3951 0 : aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
3952 :
3953 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3954 : }
3955 :
3956 : /*
3957 : * has_schema_privilege_id_id
3958 : * Check user privileges on a schema given
3959 : * roleid, schema oid, and text priv name.
3960 : */
3961 : Datum
3962 0 : has_schema_privilege_id_id(PG_FUNCTION_ARGS)
3963 : {
3964 0 : Oid roleid = PG_GETARG_OID(0);
3965 0 : Oid schemaoid = PG_GETARG_OID(1);
3966 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
3967 : AclMode mode;
3968 : AclResult aclresult;
3969 0 : bool is_missing = false;
3970 :
3971 0 : mode = convert_schema_priv_string(priv_type_text);
3972 :
3973 0 : aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
3974 : roleid, mode,
3975 : &is_missing);
3976 :
3977 0 : if (is_missing)
3978 0 : PG_RETURN_NULL();
3979 :
3980 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3981 : }
3982 :
3983 : /*
3984 : * Support routines for has_schema_privilege family.
3985 : */
3986 :
3987 : /*
3988 : * Given a schema name expressed as a string, look it up and return Oid
3989 : */
3990 : static Oid
3991 36 : convert_schema_name(text *schemaname)
3992 : {
3993 36 : char *nspname = text_to_cstring(schemaname);
3994 :
3995 36 : return get_namespace_oid(nspname, false);
3996 : }
3997 :
3998 : /*
3999 : * convert_schema_priv_string
4000 : * Convert text string to AclMode value.
4001 : */
4002 : static AclMode
4003 36 : convert_schema_priv_string(text *priv_type_text)
4004 : {
4005 : static const priv_map schema_priv_map[] = {
4006 : {"CREATE", ACL_CREATE},
4007 : {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4008 : {"USAGE", ACL_USAGE},
4009 : {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4010 : {NULL, 0}
4011 : };
4012 :
4013 36 : return convert_any_priv_string(priv_type_text, schema_priv_map);
4014 : }
4015 :
4016 :
4017 : /*
4018 : * has_server_privilege variants
4019 : * These are all named "has_server_privilege" at the SQL level.
4020 : * They take various combinations of foreign server name,
4021 : * server OID, user name, user OID, or implicit user = current_user.
4022 : *
4023 : * The result is a boolean value: true if user has the indicated
4024 : * privilege, false if not.
4025 : */
4026 :
4027 : /*
4028 : * has_server_privilege_name_name
4029 : * Check user privileges on a foreign server given
4030 : * name username, text servername, and text priv name.
4031 : */
4032 : Datum
4033 8 : has_server_privilege_name_name(PG_FUNCTION_ARGS)
4034 : {
4035 8 : Name username = PG_GETARG_NAME(0);
4036 8 : text *servername = PG_GETARG_TEXT_PP(1);
4037 8 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4038 : Oid roleid;
4039 : Oid serverid;
4040 : AclMode mode;
4041 : AclResult aclresult;
4042 :
4043 8 : roleid = get_role_oid_or_public(NameStr(*username));
4044 8 : serverid = convert_server_name(servername);
4045 8 : mode = convert_server_priv_string(priv_type_text);
4046 :
4047 8 : aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4048 :
4049 8 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4050 : }
4051 :
4052 : /*
4053 : * has_server_privilege_name
4054 : * Check user privileges on a foreign server given
4055 : * text servername and text priv name.
4056 : * current_user is assumed
4057 : */
4058 : Datum
4059 4 : has_server_privilege_name(PG_FUNCTION_ARGS)
4060 : {
4061 4 : text *servername = PG_GETARG_TEXT_PP(0);
4062 4 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4063 : Oid roleid;
4064 : Oid serverid;
4065 : AclMode mode;
4066 : AclResult aclresult;
4067 :
4068 4 : roleid = GetUserId();
4069 4 : serverid = convert_server_name(servername);
4070 4 : mode = convert_server_priv_string(priv_type_text);
4071 :
4072 4 : aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4073 :
4074 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4075 : }
4076 :
4077 : /*
4078 : * has_server_privilege_name_id
4079 : * Check user privileges on a foreign server given
4080 : * name usename, foreign server oid, and text priv name.
4081 : */
4082 : Datum
4083 4 : has_server_privilege_name_id(PG_FUNCTION_ARGS)
4084 : {
4085 4 : Name username = PG_GETARG_NAME(0);
4086 4 : Oid serverid = PG_GETARG_OID(1);
4087 4 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4088 : Oid roleid;
4089 : AclMode mode;
4090 : AclResult aclresult;
4091 4 : bool is_missing = false;
4092 :
4093 4 : roleid = get_role_oid_or_public(NameStr(*username));
4094 4 : mode = convert_server_priv_string(priv_type_text);
4095 :
4096 4 : aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4097 : roleid, mode,
4098 : &is_missing);
4099 :
4100 4 : if (is_missing)
4101 0 : PG_RETURN_NULL();
4102 :
4103 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4104 : }
4105 :
4106 : /*
4107 : * has_server_privilege_id
4108 : * Check user privileges on a foreign server given
4109 : * server oid, and text priv name.
4110 : * current_user is assumed
4111 : */
4112 : Datum
4113 52 : has_server_privilege_id(PG_FUNCTION_ARGS)
4114 : {
4115 52 : Oid serverid = PG_GETARG_OID(0);
4116 52 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4117 : Oid roleid;
4118 : AclMode mode;
4119 : AclResult aclresult;
4120 52 : bool is_missing = false;
4121 :
4122 52 : roleid = GetUserId();
4123 52 : mode = convert_server_priv_string(priv_type_text);
4124 :
4125 52 : aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4126 : roleid, mode,
4127 : &is_missing);
4128 :
4129 52 : if (is_missing)
4130 0 : PG_RETURN_NULL();
4131 :
4132 52 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4133 : }
4134 :
4135 : /*
4136 : * has_server_privilege_id_name
4137 : * Check user privileges on a foreign server given
4138 : * roleid, text servername, and text priv name.
4139 : */
4140 : Datum
4141 4 : has_server_privilege_id_name(PG_FUNCTION_ARGS)
4142 : {
4143 4 : Oid roleid = PG_GETARG_OID(0);
4144 4 : text *servername = PG_GETARG_TEXT_PP(1);
4145 4 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4146 : Oid serverid;
4147 : AclMode mode;
4148 : AclResult aclresult;
4149 :
4150 4 : serverid = convert_server_name(servername);
4151 4 : mode = convert_server_priv_string(priv_type_text);
4152 :
4153 4 : aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
4154 :
4155 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4156 : }
4157 :
4158 : /*
4159 : * has_server_privilege_id_id
4160 : * Check user privileges on a foreign server given
4161 : * roleid, server oid, and text priv name.
4162 : */
4163 : Datum
4164 4 : has_server_privilege_id_id(PG_FUNCTION_ARGS)
4165 : {
4166 4 : Oid roleid = PG_GETARG_OID(0);
4167 4 : Oid serverid = PG_GETARG_OID(1);
4168 4 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4169 : AclMode mode;
4170 : AclResult aclresult;
4171 4 : bool is_missing = false;
4172 :
4173 4 : mode = convert_server_priv_string(priv_type_text);
4174 :
4175 4 : aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
4176 : roleid, mode,
4177 : &is_missing);
4178 :
4179 4 : if (is_missing)
4180 0 : PG_RETURN_NULL();
4181 :
4182 4 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4183 : }
4184 :
4185 : /*
4186 : * Support routines for has_server_privilege family.
4187 : */
4188 :
4189 : /*
4190 : * Given a server name expressed as a string, look it up and return Oid
4191 : */
4192 : static Oid
4193 16 : convert_server_name(text *servername)
4194 : {
4195 16 : char *serverstr = text_to_cstring(servername);
4196 :
4197 16 : return get_foreign_server_oid(serverstr, false);
4198 : }
4199 :
4200 : /*
4201 : * convert_server_priv_string
4202 : * Convert text string to AclMode value.
4203 : */
4204 : static AclMode
4205 76 : convert_server_priv_string(text *priv_type_text)
4206 : {
4207 : static const priv_map server_priv_map[] = {
4208 : {"USAGE", ACL_USAGE},
4209 : {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4210 : {NULL, 0}
4211 : };
4212 :
4213 76 : return convert_any_priv_string(priv_type_text, server_priv_map);
4214 : }
4215 :
4216 :
4217 : /*
4218 : * has_tablespace_privilege variants
4219 : * These are all named "has_tablespace_privilege" at the SQL level.
4220 : * They take various combinations of tablespace name, tablespace OID,
4221 : * user name, user OID, or implicit user = current_user.
4222 : *
4223 : * The result is a boolean value: true if user has the indicated
4224 : * privilege, false if not.
4225 : */
4226 :
4227 : /*
4228 : * has_tablespace_privilege_name_name
4229 : * Check user privileges on a tablespace given
4230 : * name username, text tablespacename, and text priv name.
4231 : */
4232 : Datum
4233 0 : has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
4234 : {
4235 0 : Name username = PG_GETARG_NAME(0);
4236 0 : text *tablespacename = PG_GETARG_TEXT_PP(1);
4237 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4238 : Oid roleid;
4239 : Oid tablespaceoid;
4240 : AclMode mode;
4241 : AclResult aclresult;
4242 :
4243 0 : roleid = get_role_oid_or_public(NameStr(*username));
4244 0 : tablespaceoid = convert_tablespace_name(tablespacename);
4245 0 : mode = convert_tablespace_priv_string(priv_type_text);
4246 :
4247 0 : aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4248 :
4249 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4250 : }
4251 :
4252 : /*
4253 : * has_tablespace_privilege_name
4254 : * Check user privileges on a tablespace given
4255 : * text tablespacename and text priv name.
4256 : * current_user is assumed
4257 : */
4258 : Datum
4259 0 : has_tablespace_privilege_name(PG_FUNCTION_ARGS)
4260 : {
4261 0 : text *tablespacename = PG_GETARG_TEXT_PP(0);
4262 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4263 : Oid roleid;
4264 : Oid tablespaceoid;
4265 : AclMode mode;
4266 : AclResult aclresult;
4267 :
4268 0 : roleid = GetUserId();
4269 0 : tablespaceoid = convert_tablespace_name(tablespacename);
4270 0 : mode = convert_tablespace_priv_string(priv_type_text);
4271 :
4272 0 : aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4273 :
4274 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4275 : }
4276 :
4277 : /*
4278 : * has_tablespace_privilege_name_id
4279 : * Check user privileges on a tablespace given
4280 : * name usename, tablespace oid, and text priv name.
4281 : */
4282 : Datum
4283 0 : has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
4284 : {
4285 0 : Name username = PG_GETARG_NAME(0);
4286 0 : Oid tablespaceoid = PG_GETARG_OID(1);
4287 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4288 : Oid roleid;
4289 : AclMode mode;
4290 : AclResult aclresult;
4291 0 : bool is_missing = false;
4292 :
4293 0 : roleid = get_role_oid_or_public(NameStr(*username));
4294 0 : mode = convert_tablespace_priv_string(priv_type_text);
4295 :
4296 0 : aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4297 : roleid, mode,
4298 : &is_missing);
4299 :
4300 0 : if (is_missing)
4301 0 : PG_RETURN_NULL();
4302 :
4303 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4304 : }
4305 :
4306 : /*
4307 : * has_tablespace_privilege_id
4308 : * Check user privileges on a tablespace given
4309 : * tablespace oid, and text priv name.
4310 : * current_user is assumed
4311 : */
4312 : Datum
4313 0 : has_tablespace_privilege_id(PG_FUNCTION_ARGS)
4314 : {
4315 0 : Oid tablespaceoid = PG_GETARG_OID(0);
4316 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4317 : Oid roleid;
4318 : AclMode mode;
4319 : AclResult aclresult;
4320 0 : bool is_missing = false;
4321 :
4322 0 : roleid = GetUserId();
4323 0 : mode = convert_tablespace_priv_string(priv_type_text);
4324 :
4325 0 : aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4326 : roleid, mode,
4327 : &is_missing);
4328 :
4329 0 : if (is_missing)
4330 0 : PG_RETURN_NULL();
4331 :
4332 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4333 : }
4334 :
4335 : /*
4336 : * has_tablespace_privilege_id_name
4337 : * Check user privileges on a tablespace given
4338 : * roleid, text tablespacename, and text priv name.
4339 : */
4340 : Datum
4341 0 : has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
4342 : {
4343 0 : Oid roleid = PG_GETARG_OID(0);
4344 0 : text *tablespacename = PG_GETARG_TEXT_PP(1);
4345 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4346 : Oid tablespaceoid;
4347 : AclMode mode;
4348 : AclResult aclresult;
4349 :
4350 0 : tablespaceoid = convert_tablespace_name(tablespacename);
4351 0 : mode = convert_tablespace_priv_string(priv_type_text);
4352 :
4353 0 : aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
4354 :
4355 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4356 : }
4357 :
4358 : /*
4359 : * has_tablespace_privilege_id_id
4360 : * Check user privileges on a tablespace given
4361 : * roleid, tablespace oid, and text priv name.
4362 : */
4363 : Datum
4364 0 : has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
4365 : {
4366 0 : Oid roleid = PG_GETARG_OID(0);
4367 0 : Oid tablespaceoid = PG_GETARG_OID(1);
4368 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4369 : AclMode mode;
4370 : AclResult aclresult;
4371 0 : bool is_missing = false;
4372 :
4373 0 : mode = convert_tablespace_priv_string(priv_type_text);
4374 :
4375 0 : aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
4376 : roleid, mode,
4377 : &is_missing);
4378 :
4379 0 : if (is_missing)
4380 0 : PG_RETURN_NULL();
4381 :
4382 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4383 : }
4384 :
4385 : /*
4386 : * Support routines for has_tablespace_privilege family.
4387 : */
4388 :
4389 : /*
4390 : * Given a tablespace name expressed as a string, look it up and return Oid
4391 : */
4392 : static Oid
4393 0 : convert_tablespace_name(text *tablespacename)
4394 : {
4395 0 : char *spcname = text_to_cstring(tablespacename);
4396 :
4397 0 : return get_tablespace_oid(spcname, false);
4398 : }
4399 :
4400 : /*
4401 : * convert_tablespace_priv_string
4402 : * Convert text string to AclMode value.
4403 : */
4404 : static AclMode
4405 0 : convert_tablespace_priv_string(text *priv_type_text)
4406 : {
4407 : static const priv_map tablespace_priv_map[] = {
4408 : {"CREATE", ACL_CREATE},
4409 : {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
4410 : {NULL, 0}
4411 : };
4412 :
4413 0 : return convert_any_priv_string(priv_type_text, tablespace_priv_map);
4414 : }
4415 :
4416 : /*
4417 : * has_type_privilege variants
4418 : * These are all named "has_type_privilege" at the SQL level.
4419 : * They take various combinations of type name, type OID,
4420 : * user name, user OID, or implicit user = current_user.
4421 : *
4422 : * The result is a boolean value: true if user has the indicated
4423 : * privilege, false if not, or NULL if object doesn't exist.
4424 : */
4425 :
4426 : /*
4427 : * has_type_privilege_name_name
4428 : * Check user privileges on a type given
4429 : * name username, text typename, and text priv name.
4430 : */
4431 : Datum
4432 8 : has_type_privilege_name_name(PG_FUNCTION_ARGS)
4433 : {
4434 8 : Name username = PG_GETARG_NAME(0);
4435 8 : text *typename = PG_GETARG_TEXT_PP(1);
4436 8 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4437 : Oid roleid;
4438 : Oid typeoid;
4439 : AclMode mode;
4440 : AclResult aclresult;
4441 :
4442 8 : roleid = get_role_oid_or_public(NameStr(*username));
4443 8 : typeoid = convert_type_name(typename);
4444 8 : mode = convert_type_priv_string(priv_type_text);
4445 :
4446 8 : aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4447 :
4448 8 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4449 : }
4450 :
4451 : /*
4452 : * has_type_privilege_name
4453 : * Check user privileges on a type given
4454 : * text typename and text priv name.
4455 : * current_user is assumed
4456 : */
4457 : Datum
4458 0 : has_type_privilege_name(PG_FUNCTION_ARGS)
4459 : {
4460 0 : text *typename = PG_GETARG_TEXT_PP(0);
4461 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4462 : Oid roleid;
4463 : Oid typeoid;
4464 : AclMode mode;
4465 : AclResult aclresult;
4466 :
4467 0 : roleid = GetUserId();
4468 0 : typeoid = convert_type_name(typename);
4469 0 : mode = convert_type_priv_string(priv_type_text);
4470 :
4471 0 : aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4472 :
4473 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4474 : }
4475 :
4476 : /*
4477 : * has_type_privilege_name_id
4478 : * Check user privileges on a type given
4479 : * name usename, type oid, and text priv name.
4480 : */
4481 : Datum
4482 0 : has_type_privilege_name_id(PG_FUNCTION_ARGS)
4483 : {
4484 0 : Name username = PG_GETARG_NAME(0);
4485 0 : Oid typeoid = PG_GETARG_OID(1);
4486 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4487 : Oid roleid;
4488 : AclMode mode;
4489 : AclResult aclresult;
4490 0 : bool is_missing = false;
4491 :
4492 0 : roleid = get_role_oid_or_public(NameStr(*username));
4493 0 : mode = convert_type_priv_string(priv_type_text);
4494 :
4495 0 : aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4496 : roleid, mode,
4497 : &is_missing);
4498 :
4499 0 : if (is_missing)
4500 0 : PG_RETURN_NULL();
4501 :
4502 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4503 : }
4504 :
4505 : /*
4506 : * has_type_privilege_id
4507 : * Check user privileges on a type given
4508 : * type oid, and text priv name.
4509 : * current_user is assumed
4510 : */
4511 : Datum
4512 0 : has_type_privilege_id(PG_FUNCTION_ARGS)
4513 : {
4514 0 : Oid typeoid = PG_GETARG_OID(0);
4515 0 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4516 : Oid roleid;
4517 : AclMode mode;
4518 : AclResult aclresult;
4519 0 : bool is_missing = false;
4520 :
4521 0 : roleid = GetUserId();
4522 0 : mode = convert_type_priv_string(priv_type_text);
4523 :
4524 0 : aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4525 : roleid, mode,
4526 : &is_missing);
4527 :
4528 0 : if (is_missing)
4529 0 : PG_RETURN_NULL();
4530 :
4531 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4532 : }
4533 :
4534 : /*
4535 : * has_type_privilege_id_name
4536 : * Check user privileges on a type given
4537 : * roleid, text typename, and text priv name.
4538 : */
4539 : Datum
4540 0 : has_type_privilege_id_name(PG_FUNCTION_ARGS)
4541 : {
4542 0 : Oid roleid = PG_GETARG_OID(0);
4543 0 : text *typename = PG_GETARG_TEXT_PP(1);
4544 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4545 : Oid typeoid;
4546 : AclMode mode;
4547 : AclResult aclresult;
4548 :
4549 0 : typeoid = convert_type_name(typename);
4550 0 : mode = convert_type_priv_string(priv_type_text);
4551 :
4552 0 : aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
4553 :
4554 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4555 : }
4556 :
4557 : /*
4558 : * has_type_privilege_id_id
4559 : * Check user privileges on a type given
4560 : * roleid, type oid, and text priv name.
4561 : */
4562 : Datum
4563 0 : has_type_privilege_id_id(PG_FUNCTION_ARGS)
4564 : {
4565 0 : Oid roleid = PG_GETARG_OID(0);
4566 0 : Oid typeoid = PG_GETARG_OID(1);
4567 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4568 : AclMode mode;
4569 : AclResult aclresult;
4570 0 : bool is_missing = false;
4571 :
4572 0 : mode = convert_type_priv_string(priv_type_text);
4573 :
4574 0 : aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
4575 : roleid, mode,
4576 : &is_missing);
4577 :
4578 0 : if (is_missing)
4579 0 : PG_RETURN_NULL();
4580 :
4581 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4582 : }
4583 :
4584 : /*
4585 : * Support routines for has_type_privilege family.
4586 : */
4587 :
4588 : /*
4589 : * Given a type name expressed as a string, look it up and return Oid
4590 : */
4591 : static Oid
4592 8 : convert_type_name(text *typename)
4593 : {
4594 8 : char *typname = text_to_cstring(typename);
4595 : Oid oid;
4596 :
4597 8 : oid = DatumGetObjectId(DirectFunctionCall1(regtypein,
4598 : CStringGetDatum(typname)));
4599 :
4600 8 : if (!OidIsValid(oid))
4601 0 : ereport(ERROR,
4602 : (errcode(ERRCODE_UNDEFINED_OBJECT),
4603 : errmsg("type \"%s\" does not exist", typname)));
4604 :
4605 8 : return oid;
4606 : }
4607 :
4608 : /*
4609 : * convert_type_priv_string
4610 : * Convert text string to AclMode value.
4611 : */
4612 : static AclMode
4613 8 : convert_type_priv_string(text *priv_type_text)
4614 : {
4615 : static const priv_map type_priv_map[] = {
4616 : {"USAGE", ACL_USAGE},
4617 : {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
4618 : {NULL, 0}
4619 : };
4620 :
4621 8 : return convert_any_priv_string(priv_type_text, type_priv_map);
4622 : }
4623 :
4624 : /*
4625 : * has_parameter_privilege variants
4626 : * These are all named "has_parameter_privilege" at the SQL level.
4627 : * They take various combinations of parameter name with
4628 : * user name, user OID, or implicit user = current_user.
4629 : *
4630 : * The result is a boolean value: true if user has been granted
4631 : * the indicated privilege or false if not.
4632 : */
4633 :
4634 : /*
4635 : * has_param_priv_byname
4636 : *
4637 : * Helper function to check user privileges on a parameter given the
4638 : * role by Oid, parameter by text name, and privileges as AclMode.
4639 : */
4640 : static bool
4641 37 : has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
4642 : {
4643 37 : char *paramstr = text_to_cstring(parameter);
4644 :
4645 37 : return pg_parameter_aclcheck(paramstr, roleid, priv) == ACLCHECK_OK;
4646 : }
4647 :
4648 : /*
4649 : * has_parameter_privilege_name_name
4650 : * Check user privileges on a parameter given name username, text
4651 : * parameter, and text priv name.
4652 : */
4653 : Datum
4654 42 : has_parameter_privilege_name_name(PG_FUNCTION_ARGS)
4655 : {
4656 42 : Name username = PG_GETARG_NAME(0);
4657 42 : text *parameter = PG_GETARG_TEXT_PP(1);
4658 42 : AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
4659 35 : Oid roleid = get_role_oid_or_public(NameStr(*username));
4660 :
4661 35 : PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
4662 : }
4663 :
4664 : /*
4665 : * has_parameter_privilege_name
4666 : * Check user privileges on a parameter given text parameter and text priv
4667 : * name. current_user is assumed
4668 : */
4669 : Datum
4670 1 : has_parameter_privilege_name(PG_FUNCTION_ARGS)
4671 : {
4672 1 : text *parameter = PG_GETARG_TEXT_PP(0);
4673 1 : AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(1));
4674 :
4675 1 : PG_RETURN_BOOL(has_param_priv_byname(GetUserId(), parameter, priv));
4676 : }
4677 :
4678 : /*
4679 : * has_parameter_privilege_id_name
4680 : * Check user privileges on a parameter given roleid, text parameter, and
4681 : * text priv name.
4682 : */
4683 : Datum
4684 1 : has_parameter_privilege_id_name(PG_FUNCTION_ARGS)
4685 : {
4686 1 : Oid roleid = PG_GETARG_OID(0);
4687 1 : text *parameter = PG_GETARG_TEXT_PP(1);
4688 1 : AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
4689 :
4690 1 : PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
4691 : }
4692 :
4693 : /*
4694 : * Support routines for has_parameter_privilege family.
4695 : */
4696 :
4697 : /*
4698 : * convert_parameter_priv_string
4699 : * Convert text string to AclMode value.
4700 : */
4701 : static AclMode
4702 44 : convert_parameter_priv_string(text *priv_text)
4703 : {
4704 : static const priv_map parameter_priv_map[] = {
4705 : {"SET", ACL_SET},
4706 : {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SET)},
4707 : {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
4708 : {"ALTER SYSTEM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ALTER_SYSTEM)},
4709 : {NULL, 0}
4710 : };
4711 :
4712 44 : return convert_any_priv_string(priv_text, parameter_priv_map);
4713 : }
4714 :
4715 : /*
4716 : * has_largeobject_privilege variants
4717 : * These are all named "has_largeobject_privilege" at the SQL level.
4718 : * They take various combinations of large object OID with
4719 : * user name, user OID, or implicit user = current_user.
4720 : *
4721 : * The result is a boolean value: true if user has the indicated
4722 : * privilege, false if not, or NULL if object doesn't exist.
4723 : */
4724 :
4725 : /*
4726 : * has_lo_priv_byid
4727 : *
4728 : * Helper function to check user privileges on a large object given the
4729 : * role by Oid, large object by Oid, and privileges as AclMode.
4730 : */
4731 : static bool
4732 140 : has_lo_priv_byid(Oid roleid, Oid lobjId, AclMode priv, bool *is_missing)
4733 : {
4734 140 : Snapshot snapshot = NULL;
4735 : AclResult aclresult;
4736 :
4737 140 : if (priv & ACL_UPDATE)
4738 64 : snapshot = NULL;
4739 : else
4740 76 : snapshot = GetActiveSnapshot();
4741 :
4742 140 : if (!LargeObjectExistsWithSnapshot(lobjId, snapshot))
4743 : {
4744 : Assert(is_missing != NULL);
4745 4 : *is_missing = true;
4746 4 : return false;
4747 : }
4748 :
4749 136 : if (lo_compat_privileges)
4750 8 : return true;
4751 :
4752 128 : aclresult = pg_largeobject_aclcheck_snapshot(lobjId,
4753 : roleid,
4754 : priv,
4755 : snapshot);
4756 128 : return aclresult == ACLCHECK_OK;
4757 : }
4758 :
4759 : /*
4760 : * has_largeobject_privilege_name_id
4761 : * Check user privileges on a large object given
4762 : * name username, large object oid, and text priv name.
4763 : */
4764 : Datum
4765 56 : has_largeobject_privilege_name_id(PG_FUNCTION_ARGS)
4766 : {
4767 56 : Name username = PG_GETARG_NAME(0);
4768 56 : Oid roleid = get_role_oid_or_public(NameStr(*username));
4769 56 : Oid lobjId = PG_GETARG_OID(1);
4770 56 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4771 : AclMode mode;
4772 56 : bool is_missing = false;
4773 : bool result;
4774 :
4775 56 : mode = convert_largeobject_priv_string(priv_type_text);
4776 56 : result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4777 :
4778 56 : if (is_missing)
4779 0 : PG_RETURN_NULL();
4780 :
4781 56 : PG_RETURN_BOOL(result);
4782 : }
4783 :
4784 : /*
4785 : * has_largeobject_privilege_id
4786 : * Check user privileges on a large object given
4787 : * large object oid, and text priv name.
4788 : * current_user is assumed
4789 : */
4790 : Datum
4791 84 : has_largeobject_privilege_id(PG_FUNCTION_ARGS)
4792 : {
4793 84 : Oid lobjId = PG_GETARG_OID(0);
4794 84 : Oid roleid = GetUserId();
4795 84 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4796 : AclMode mode;
4797 84 : bool is_missing = false;
4798 : bool result;
4799 :
4800 84 : mode = convert_largeobject_priv_string(priv_type_text);
4801 84 : result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4802 :
4803 84 : if (is_missing)
4804 4 : PG_RETURN_NULL();
4805 :
4806 80 : PG_RETURN_BOOL(result);
4807 : }
4808 :
4809 : /*
4810 : * has_largeobject_privilege_id_id
4811 : * Check user privileges on a large object given
4812 : * roleid, large object oid, and text priv name.
4813 : */
4814 : Datum
4815 0 : has_largeobject_privilege_id_id(PG_FUNCTION_ARGS)
4816 : {
4817 0 : Oid roleid = PG_GETARG_OID(0);
4818 0 : Oid lobjId = PG_GETARG_OID(1);
4819 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4820 : AclMode mode;
4821 0 : bool is_missing = false;
4822 : bool result;
4823 :
4824 0 : mode = convert_largeobject_priv_string(priv_type_text);
4825 0 : result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4826 :
4827 0 : if (is_missing)
4828 0 : PG_RETURN_NULL();
4829 :
4830 0 : PG_RETURN_BOOL(result);
4831 : }
4832 :
4833 : /*
4834 : * convert_largeobject_priv_string
4835 : * Convert text string to AclMode value.
4836 : */
4837 : static AclMode
4838 140 : convert_largeobject_priv_string(text *priv_type_text)
4839 : {
4840 : static const priv_map largeobject_priv_map[] = {
4841 : {"SELECT", ACL_SELECT},
4842 : {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
4843 : {"UPDATE", ACL_UPDATE},
4844 : {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
4845 : {NULL, 0}
4846 : };
4847 :
4848 140 : return convert_any_priv_string(priv_type_text, largeobject_priv_map);
4849 : }
4850 :
4851 : /*
4852 : * pg_has_role variants
4853 : * These are all named "pg_has_role" at the SQL level.
4854 : * They take various combinations of role name, role OID,
4855 : * user name, user OID, or implicit user = current_user.
4856 : *
4857 : * The result is a boolean value: true if user has the indicated
4858 : * privilege, false if not.
4859 : */
4860 :
4861 : /*
4862 : * pg_has_role_name_name
4863 : * Check user privileges on a role given
4864 : * name username, name rolename, and text priv name.
4865 : */
4866 : Datum
4867 24 : pg_has_role_name_name(PG_FUNCTION_ARGS)
4868 : {
4869 24 : Name username = PG_GETARG_NAME(0);
4870 24 : Name rolename = PG_GETARG_NAME(1);
4871 24 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4872 : Oid roleid;
4873 : Oid roleoid;
4874 : AclMode mode;
4875 : AclResult aclresult;
4876 :
4877 24 : roleid = get_role_oid(NameStr(*username), false);
4878 24 : roleoid = get_role_oid(NameStr(*rolename), false);
4879 24 : mode = convert_role_priv_string(priv_type_text);
4880 :
4881 24 : aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4882 :
4883 24 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4884 : }
4885 :
4886 : /*
4887 : * pg_has_role_name
4888 : * Check user privileges on a role given
4889 : * name rolename and text priv name.
4890 : * current_user is assumed
4891 : */
4892 : Datum
4893 12 : pg_has_role_name(PG_FUNCTION_ARGS)
4894 : {
4895 12 : Name rolename = PG_GETARG_NAME(0);
4896 12 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4897 : Oid roleid;
4898 : Oid roleoid;
4899 : AclMode mode;
4900 : AclResult aclresult;
4901 :
4902 12 : roleid = GetUserId();
4903 12 : roleoid = get_role_oid(NameStr(*rolename), false);
4904 12 : mode = convert_role_priv_string(priv_type_text);
4905 :
4906 12 : aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4907 :
4908 12 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4909 : }
4910 :
4911 : /*
4912 : * pg_has_role_name_id
4913 : * Check user privileges on a role given
4914 : * name usename, role oid, and text priv name.
4915 : */
4916 : Datum
4917 0 : pg_has_role_name_id(PG_FUNCTION_ARGS)
4918 : {
4919 0 : Name username = PG_GETARG_NAME(0);
4920 0 : Oid roleoid = PG_GETARG_OID(1);
4921 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4922 : Oid roleid;
4923 : AclMode mode;
4924 : AclResult aclresult;
4925 :
4926 0 : roleid = get_role_oid(NameStr(*username), false);
4927 0 : mode = convert_role_priv_string(priv_type_text);
4928 :
4929 0 : aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4930 :
4931 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4932 : }
4933 :
4934 : /*
4935 : * pg_has_role_id
4936 : * Check user privileges on a role given
4937 : * role oid, and text priv name.
4938 : * current_user is assumed
4939 : */
4940 : Datum
4941 65208 : pg_has_role_id(PG_FUNCTION_ARGS)
4942 : {
4943 65208 : Oid roleoid = PG_GETARG_OID(0);
4944 65208 : text *priv_type_text = PG_GETARG_TEXT_PP(1);
4945 : Oid roleid;
4946 : AclMode mode;
4947 : AclResult aclresult;
4948 :
4949 65208 : roleid = GetUserId();
4950 65208 : mode = convert_role_priv_string(priv_type_text);
4951 :
4952 65208 : aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4953 :
4954 65208 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4955 : }
4956 :
4957 : /*
4958 : * pg_has_role_id_name
4959 : * Check user privileges on a role given
4960 : * roleid, name rolename, and text priv name.
4961 : */
4962 : Datum
4963 0 : pg_has_role_id_name(PG_FUNCTION_ARGS)
4964 : {
4965 0 : Oid roleid = PG_GETARG_OID(0);
4966 0 : Name rolename = PG_GETARG_NAME(1);
4967 0 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4968 : Oid roleoid;
4969 : AclMode mode;
4970 : AclResult aclresult;
4971 :
4972 0 : roleoid = get_role_oid(NameStr(*rolename), false);
4973 0 : mode = convert_role_priv_string(priv_type_text);
4974 :
4975 0 : aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4976 :
4977 0 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4978 : }
4979 :
4980 : /*
4981 : * pg_has_role_id_id
4982 : * Check user privileges on a role given
4983 : * roleid, role oid, and text priv name.
4984 : */
4985 : Datum
4986 120 : pg_has_role_id_id(PG_FUNCTION_ARGS)
4987 : {
4988 120 : Oid roleid = PG_GETARG_OID(0);
4989 120 : Oid roleoid = PG_GETARG_OID(1);
4990 120 : text *priv_type_text = PG_GETARG_TEXT_PP(2);
4991 : AclMode mode;
4992 : AclResult aclresult;
4993 :
4994 120 : mode = convert_role_priv_string(priv_type_text);
4995 :
4996 120 : aclresult = pg_role_aclcheck(roleoid, roleid, mode);
4997 :
4998 120 : PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
4999 : }
5000 :
5001 : /*
5002 : * Support routines for pg_has_role family.
5003 : */
5004 :
5005 : /*
5006 : * convert_role_priv_string
5007 : * Convert text string to AclMode value.
5008 : *
5009 : * We use USAGE to denote whether the privileges of the role are accessible
5010 : * (has_privs_of_role), MEMBER to denote is_member, and MEMBER WITH GRANT
5011 : * (or ADMIN) OPTION to denote is_admin. There is no ACL bit corresponding
5012 : * to MEMBER so we cheat and use ACL_CREATE for that. This convention
5013 : * is shared only with pg_role_aclcheck, below.
5014 : */
5015 : static AclMode
5016 65364 : convert_role_priv_string(text *priv_type_text)
5017 : {
5018 : static const priv_map role_priv_map[] = {
5019 : {"USAGE", ACL_USAGE},
5020 : {"MEMBER", ACL_CREATE},
5021 : {"SET", ACL_SET},
5022 : {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
5023 : {"USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
5024 : {"MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
5025 : {"MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
5026 : {"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
5027 : {"SET WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
5028 : {NULL, 0}
5029 : };
5030 :
5031 65364 : return convert_any_priv_string(priv_type_text, role_priv_map);
5032 : }
5033 :
5034 : /*
5035 : * pg_role_aclcheck
5036 : * Quick-and-dirty support for pg_has_role
5037 : */
5038 : static AclResult
5039 65364 : pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
5040 : {
5041 65364 : if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
5042 : {
5043 8 : if (is_admin_of_role(roleid, role_oid))
5044 0 : return ACLCHECK_OK;
5045 : }
5046 65364 : if (mode & ACL_CREATE)
5047 : {
5048 8 : if (is_member_of_role(roleid, role_oid))
5049 4 : return ACLCHECK_OK;
5050 : }
5051 65360 : if (mode & ACL_USAGE)
5052 : {
5053 65348 : if (has_privs_of_role(roleid, role_oid))
5054 64638 : return ACLCHECK_OK;
5055 : }
5056 722 : if (mode & ACL_SET)
5057 : {
5058 0 : if (member_can_set_role(roleid, role_oid))
5059 0 : return ACLCHECK_OK;
5060 : }
5061 722 : return ACLCHECK_NO_PRIV;
5062 : }
5063 :
5064 :
5065 : /*
5066 : * initialization function (called by InitPostgres)
5067 : */
5068 : void
5069 18172 : initialize_acl(void)
5070 : {
5071 18172 : if (!IsBootstrapProcessingMode())
5072 : {
5073 18115 : cached_db_hash =
5074 18115 : GetSysCacheHashValue1(DATABASEOID,
5075 : ObjectIdGetDatum(MyDatabaseId));
5076 :
5077 : /*
5078 : * In normal mode, set a callback on any syscache invalidation of rows
5079 : * of pg_auth_members (for roles_is_member_of()) pg_database (for
5080 : * roles_is_member_of())
5081 : */
5082 18115 : CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
5083 : RoleMembershipCacheCallback,
5084 : (Datum) 0);
5085 18115 : CacheRegisterSyscacheCallback(AUTHOID,
5086 : RoleMembershipCacheCallback,
5087 : (Datum) 0);
5088 18115 : CacheRegisterSyscacheCallback(DATABASEOID,
5089 : RoleMembershipCacheCallback,
5090 : (Datum) 0);
5091 : }
5092 18172 : }
5093 :
5094 : /*
5095 : * RoleMembershipCacheCallback
5096 : * Syscache inval callback function
5097 : */
5098 : static void
5099 39296 : RoleMembershipCacheCallback(Datum arg, SysCacheIdentifier cacheid,
5100 : uint32 hashvalue)
5101 : {
5102 39296 : if (cacheid == DATABASEOID &&
5103 5683 : hashvalue != cached_db_hash &&
5104 : hashvalue != 0)
5105 : {
5106 1674 : return; /* ignore pg_database changes for other DBs */
5107 : }
5108 :
5109 : /* Force membership caches to be recomputed on next use */
5110 37622 : cached_role[ROLERECURSE_MEMBERS] = InvalidOid;
5111 37622 : cached_role[ROLERECURSE_PRIVS] = InvalidOid;
5112 37622 : cached_role[ROLERECURSE_SETROLE] = InvalidOid;
5113 : }
5114 :
5115 : /*
5116 : * A helper function for roles_is_member_of() that provides an optimized
5117 : * implementation of list_append_unique_oid() via a Bloom filter. The caller
5118 : * (i.e., roles_is_member_of()) is responsible for freeing bf once it is done
5119 : * using this function.
5120 : */
5121 : static inline List *
5122 3118 : roles_list_append(List *roles_list, bloom_filter **bf, Oid role)
5123 : {
5124 3118 : unsigned char *roleptr = (unsigned char *) &role;
5125 :
5126 : /*
5127 : * If there is a previously-created Bloom filter, use it to try to
5128 : * determine whether the role is missing from the list. If it says yes,
5129 : * that's a hard fact and we can go ahead and add the role. If it says
5130 : * no, that's only probabilistic and we'd better search the list. Without
5131 : * a filter, we must always do an ordinary linear search through the
5132 : * existing list.
5133 : */
5134 3118 : if ((*bf && bloom_lacks_element(*bf, roleptr, sizeof(Oid))) ||
5135 3118 : !list_member_oid(roles_list, role))
5136 : {
5137 : /*
5138 : * If the list is large, we take on the overhead of creating and
5139 : * populating a Bloom filter to speed up future calls to this
5140 : * function.
5141 : */
5142 5116 : if (*bf == NULL &&
5143 2558 : list_length(roles_list) > ROLES_LIST_BLOOM_THRESHOLD)
5144 : {
5145 0 : *bf = bloom_create(ROLES_LIST_BLOOM_THRESHOLD * 10, work_mem, 0);
5146 0 : foreach_oid(roleid, roles_list)
5147 0 : bloom_add_element(*bf, (unsigned char *) &roleid, sizeof(Oid));
5148 : }
5149 :
5150 : /*
5151 : * Finally, add the role to the list and the Bloom filter, if it
5152 : * exists.
5153 : */
5154 2558 : roles_list = lappend_oid(roles_list, role);
5155 2558 : if (*bf)
5156 0 : bloom_add_element(*bf, roleptr, sizeof(Oid));
5157 : }
5158 :
5159 3118 : return roles_list;
5160 : }
5161 :
5162 : /*
5163 : * Get a list of roles that the specified roleid is a member of
5164 : *
5165 : * Type ROLERECURSE_MEMBERS recurses through all grants; ROLERECURSE_PRIVS
5166 : * recurses only through inheritable grants; and ROLERECURSE_SETROLE recurses
5167 : * only through grants with set_option.
5168 : *
5169 : * Since indirect membership testing is relatively expensive, we cache
5170 : * a list of memberships. Hence, the result is only guaranteed good until
5171 : * the next call of roles_is_member_of()!
5172 : *
5173 : * For the benefit of select_best_grantor, the result is defined to be
5174 : * in breadth-first order, ie, closer relationships earlier.
5175 : *
5176 : * If admin_of is not InvalidOid, this function sets *admin_role, either
5177 : * to the OID of the first role in the result list that directly possesses
5178 : * ADMIN OPTION on the role corresponding to admin_of, or to InvalidOid if
5179 : * there is no such role.
5180 : */
5181 : static List *
5182 39927 : roles_is_member_of(Oid roleid, enum RoleRecurseType type,
5183 : Oid admin_of, Oid *admin_role)
5184 : {
5185 : Oid dba;
5186 : List *roles_list;
5187 : ListCell *l;
5188 : List *new_cached_roles;
5189 : MemoryContext oldctx;
5190 39927 : bloom_filter *bf = NULL;
5191 :
5192 : Assert(OidIsValid(admin_of) == (admin_role != NULL));
5193 39927 : if (admin_role != NULL)
5194 630 : *admin_role = InvalidOid;
5195 :
5196 : /* If cache is valid and ADMIN OPTION not sought, just return the list */
5197 39927 : if (cached_role[type] == roleid && !OidIsValid(admin_of) &&
5198 36993 : OidIsValid(cached_role[type]))
5199 36993 : return cached_roles[type];
5200 :
5201 : /*
5202 : * Role expansion happens in a non-database backend when guc.c checks
5203 : * ROLE_PG_READ_ALL_SETTINGS for a physical walsender SHOW command. In
5204 : * that case, no role gets pg_database_owner.
5205 : */
5206 2934 : if (!OidIsValid(MyDatabaseId))
5207 18 : dba = InvalidOid;
5208 : else
5209 : {
5210 : HeapTuple dbtup;
5211 :
5212 2916 : dbtup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
5213 2916 : if (!HeapTupleIsValid(dbtup))
5214 0 : elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
5215 2916 : dba = ((Form_pg_database) GETSTRUCT(dbtup))->datdba;
5216 2916 : ReleaseSysCache(dbtup);
5217 : }
5218 :
5219 : /*
5220 : * Find all the roles that roleid is a member of, including multi-level
5221 : * recursion. The role itself will always be the first element of the
5222 : * resulting list.
5223 : *
5224 : * Each element of the list is scanned to see if it adds any indirect
5225 : * memberships. We can use a single list as both the record of
5226 : * already-found memberships and the agenda of roles yet to be scanned.
5227 : * This is a bit tricky but works because the foreach() macro doesn't
5228 : * fetch the next list element until the bottom of the loop.
5229 : */
5230 2934 : roles_list = list_make1_oid(roleid);
5231 :
5232 8426 : foreach(l, roles_list)
5233 : {
5234 5492 : Oid memberid = lfirst_oid(l);
5235 : CatCList *memlist;
5236 : int i;
5237 :
5238 : /* Find roles that memberid is directly a member of */
5239 5492 : memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
5240 : ObjectIdGetDatum(memberid));
5241 10087 : for (i = 0; i < memlist->n_members; i++)
5242 : {
5243 4595 : HeapTuple tup = &memlist->members[i]->tuple;
5244 4595 : Form_pg_auth_members form = (Form_pg_auth_members) GETSTRUCT(tup);
5245 4595 : Oid otherid = form->roleid;
5246 :
5247 : /*
5248 : * While otherid==InvalidOid shouldn't appear in the catalog, the
5249 : * OidIsValid() avoids crashing if that arises.
5250 : */
5251 4595 : if (otherid == admin_of && form->admin_option &&
5252 528 : OidIsValid(admin_of) && !OidIsValid(*admin_role))
5253 512 : *admin_role = memberid;
5254 :
5255 : /* If we're supposed to ignore non-heritable grants, do so. */
5256 4595 : if (type == ROLERECURSE_PRIVS && !form->inherit_option)
5257 1397 : continue;
5258 :
5259 : /* If we're supposed to ignore non-SET grants, do so. */
5260 3198 : if (type == ROLERECURSE_SETROLE && !form->set_option)
5261 92 : continue;
5262 :
5263 : /*
5264 : * Even though there shouldn't be any loops in the membership
5265 : * graph, we must test for having already seen this role. It is
5266 : * legal for instance to have both A->B and A->C->B.
5267 : */
5268 3106 : roles_list = roles_list_append(roles_list, &bf, otherid);
5269 : }
5270 5492 : ReleaseSysCacheList(memlist);
5271 :
5272 : /* implement pg_database_owner implicit membership */
5273 5492 : if (memberid == dba && OidIsValid(dba))
5274 12 : roles_list = roles_list_append(roles_list, &bf,
5275 : ROLE_PG_DATABASE_OWNER);
5276 : }
5277 :
5278 : /*
5279 : * Free the Bloom filter created by roles_list_append(), if there is one.
5280 : */
5281 2934 : if (bf)
5282 0 : bloom_free(bf);
5283 :
5284 : /*
5285 : * Copy the completed list into TopMemoryContext so it will persist.
5286 : */
5287 2934 : oldctx = MemoryContextSwitchTo(TopMemoryContext);
5288 2934 : new_cached_roles = list_copy(roles_list);
5289 2934 : MemoryContextSwitchTo(oldctx);
5290 2934 : list_free(roles_list);
5291 :
5292 : /*
5293 : * Now safe to assign to state variable
5294 : */
5295 2934 : cached_role[type] = InvalidOid; /* just paranoia */
5296 2934 : list_free(cached_roles[type]);
5297 2934 : cached_roles[type] = new_cached_roles;
5298 2934 : cached_role[type] = roleid;
5299 :
5300 : /* And now we can return the answer */
5301 2934 : return cached_roles[type];
5302 : }
5303 :
5304 :
5305 : /*
5306 : * Does member have the privileges of role (directly or indirectly)?
5307 : *
5308 : * This is defined not to recurse through grants that are not inherited,
5309 : * and only inherited grants confer the associated privileges automatically.
5310 : *
5311 : * See also member_can_set_role, below.
5312 : */
5313 : bool
5314 226921 : has_privs_of_role(Oid member, Oid role)
5315 : {
5316 : /* Fast path for simple case */
5317 226921 : if (member == role)
5318 68036 : return true;
5319 :
5320 : /* Superusers have every privilege, so are part of every role */
5321 158885 : if (superuser_arg(member))
5322 120550 : return true;
5323 :
5324 : /*
5325 : * Find all the roles that member has the privileges of, including
5326 : * multi-level recursion, then see if target role is any one of them.
5327 : */
5328 38335 : return list_member_oid(roles_is_member_of(member, ROLERECURSE_PRIVS,
5329 : InvalidOid, NULL),
5330 : role);
5331 : }
5332 :
5333 : /*
5334 : * Can member use SET ROLE to this role?
5335 : *
5336 : * There must be a chain of grants from 'member' to 'role' each of which
5337 : * permits SET ROLE; that is, each of which has set_option = true.
5338 : *
5339 : * It doesn't matter whether the grants are inheritable. That's a separate
5340 : * question; see has_privs_of_role.
5341 : *
5342 : * This function should be used to determine whether the session user can
5343 : * use SET ROLE to become the target user. We also use it to determine whether
5344 : * the session user can change an existing object to be owned by the target
5345 : * user, or create new objects owned by the target user.
5346 : */
5347 : bool
5348 299322 : member_can_set_role(Oid member, Oid role)
5349 : {
5350 : /* Fast path for simple case */
5351 299322 : if (member == role)
5352 298254 : return true;
5353 :
5354 : /* Superusers have every privilege, so can always SET ROLE */
5355 1068 : if (superuser_arg(member))
5356 794 : return true;
5357 :
5358 : /*
5359 : * Find all the roles that member can access via SET ROLE, including
5360 : * multi-level recursion, then see if target role is any one of them.
5361 : */
5362 274 : return list_member_oid(roles_is_member_of(member, ROLERECURSE_SETROLE,
5363 : InvalidOid, NULL),
5364 : role);
5365 : }
5366 :
5367 : /*
5368 : * Permission violation error unless able to SET ROLE to target role.
5369 : */
5370 : void
5371 1390 : check_can_set_role(Oid member, Oid role)
5372 : {
5373 1390 : if (!member_can_set_role(member, role))
5374 104 : ereport(ERROR,
5375 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
5376 : errmsg("must be able to SET ROLE \"%s\"",
5377 : GetUserNameFromId(role, false))));
5378 1286 : }
5379 :
5380 : /*
5381 : * Is member a member of role (directly or indirectly)?
5382 : *
5383 : * This is defined to recurse through grants whether they are inherited or not.
5384 : *
5385 : * Do not use this for privilege checking, instead use has_privs_of_role().
5386 : * Don't use it for determining whether it's possible to SET ROLE to some
5387 : * other role; for that, use member_can_set_role(). And don't use it for
5388 : * determining whether it's OK to create an object owned by some other role:
5389 : * use member_can_set_role() for that, too.
5390 : *
5391 : * In short, calling this function is the wrong thing to do nearly everywhere.
5392 : */
5393 : bool
5394 8 : is_member_of_role(Oid member, Oid role)
5395 : {
5396 : /* Fast path for simple case */
5397 8 : if (member == role)
5398 0 : return true;
5399 :
5400 : /* Superusers have every privilege, so are part of every role */
5401 8 : if (superuser_arg(member))
5402 0 : return true;
5403 :
5404 : /*
5405 : * Find all the roles that member is a member of, including multi-level
5406 : * recursion, then see if target role is any one of them.
5407 : */
5408 8 : return list_member_oid(roles_is_member_of(member, ROLERECURSE_MEMBERS,
5409 : InvalidOid, NULL),
5410 : role);
5411 : }
5412 :
5413 : /*
5414 : * Is member a member of role, not considering superuserness?
5415 : *
5416 : * This is identical to is_member_of_role except we ignore superuser
5417 : * status.
5418 : *
5419 : * Do not use this for privilege checking, instead use has_privs_of_role()
5420 : */
5421 : bool
5422 501 : is_member_of_role_nosuper(Oid member, Oid role)
5423 : {
5424 : /* Fast path for simple case */
5425 501 : if (member == role)
5426 13 : return true;
5427 :
5428 : /*
5429 : * Find all the roles that member is a member of, including multi-level
5430 : * recursion, then see if target role is any one of them.
5431 : */
5432 488 : return list_member_oid(roles_is_member_of(member, ROLERECURSE_MEMBERS,
5433 : InvalidOid, NULL),
5434 : role);
5435 : }
5436 :
5437 :
5438 : /*
5439 : * Is member an admin of role? That is, is member the role itself (subject to
5440 : * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
5441 : * or a superuser?
5442 : */
5443 : bool
5444 1985 : is_admin_of_role(Oid member, Oid role)
5445 : {
5446 : Oid admin_role;
5447 :
5448 1985 : if (superuser_arg(member))
5449 1639 : return true;
5450 :
5451 : /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5452 346 : if (member == role)
5453 12 : return false;
5454 :
5455 334 : (void) roles_is_member_of(member, ROLERECURSE_MEMBERS, role, &admin_role);
5456 334 : return OidIsValid(admin_role);
5457 : }
5458 :
5459 : /*
5460 : * Find a role whose privileges "member" inherits which has ADMIN OPTION
5461 : * on "role", ignoring super-userness.
5462 : *
5463 : * There might be more than one such role; prefer one which involves fewer
5464 : * hops. That is, if member has ADMIN OPTION, prefer that over all other
5465 : * options; if not, prefer a role from which member inherits more directly
5466 : * over more indirect inheritance.
5467 : */
5468 : Oid
5469 300 : select_best_admin(Oid member, Oid role)
5470 : {
5471 : Oid admin_role;
5472 :
5473 : /* By policy, a role cannot have WITH ADMIN OPTION on itself. */
5474 300 : if (member == role)
5475 4 : return InvalidOid;
5476 :
5477 296 : (void) roles_is_member_of(member, ROLERECURSE_PRIVS, role, &admin_role);
5478 296 : return admin_role;
5479 : }
5480 :
5481 : /*
5482 : * Select the effective grantor ID for a GRANT or REVOKE operation.
5483 : *
5484 : * If the GRANT/REVOKE has an explicit GRANTED BY clause, we always use
5485 : * exactly that role (which may result in granting/revoking no privileges).
5486 : * Otherwise, we seek a "best" grantor, starting with the current user.
5487 : *
5488 : * The grantor must always be either the object owner or some role that has
5489 : * been explicitly granted grant options. This ensures that all granted
5490 : * privileges appear to flow from the object owner, and there are never
5491 : * multiple "original sources" of a privilege. Therefore, if the would-be
5492 : * grantor is a member of a role that has the needed grant options, we have
5493 : * to do the grant as that role instead.
5494 : *
5495 : * It is possible that the would-be grantor is a member of several roles
5496 : * that have different subsets of the desired grant options, but no one
5497 : * role has 'em all. In this case we pick a role with the largest number
5498 : * of desired options. Ties are broken in favor of closer ancestors.
5499 : *
5500 : * grantedBy: the GRANTED BY clause of GRANT/REVOKE, or NULL if none
5501 : * privileges: the privileges to be granted/revoked
5502 : * acl: the ACL of the object in question
5503 : * ownerId: the role owning the object in question
5504 : * *grantorId: receives the OID of the role to do the grant as
5505 : * *grantOptions: receives grant options actually held by grantorId (maybe 0)
5506 : */
5507 : void
5508 41106 : select_best_grantor(const RoleSpec *grantedBy, AclMode privileges,
5509 : const Acl *acl, Oid ownerId,
5510 : Oid *grantorId, AclMode *grantOptions)
5511 : {
5512 41106 : Oid roleId = GetUserId();
5513 41106 : AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
5514 : List *roles_list;
5515 : int nrights;
5516 : ListCell *l;
5517 :
5518 : /*
5519 : * If we have GRANTED BY, resolve it and verify current user is allowed to
5520 : * specify that role.
5521 : */
5522 41106 : if (grantedBy)
5523 : {
5524 76 : Oid grantor = get_rolespec_oid(grantedBy, false);
5525 :
5526 76 : if (!has_privs_of_role(roleId, grantor))
5527 4 : ereport(ERROR,
5528 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
5529 : errmsg("must inherit privileges of role \"%s\"",
5530 : GetUserNameFromId(grantor, false))));
5531 : /* Use exactly that grantor, whether it has privileges or not */
5532 72 : *grantorId = grantor;
5533 72 : *grantOptions = aclmask_direct(acl, grantor, ownerId,
5534 : needed_goptions, ACLMASK_ALL);
5535 72 : return;
5536 : }
5537 :
5538 : /*
5539 : * The object owner is always treated as having all grant options, so if
5540 : * roleId is the owner it's easy. Also, if roleId is a superuser it's
5541 : * easy: superusers are implicitly members of every role, so they act as
5542 : * the object owner.
5543 : */
5544 41030 : if (roleId == ownerId || superuser_arg(roleId))
5545 : {
5546 40838 : *grantorId = ownerId;
5547 40838 : *grantOptions = needed_goptions;
5548 40838 : return;
5549 : }
5550 :
5551 : /*
5552 : * Otherwise we have to do a careful search to see if roleId has the
5553 : * privileges of any suitable role. Note: we can hang onto the result of
5554 : * roles_is_member_of() throughout this loop, because aclmask_direct()
5555 : * doesn't query any role memberships.
5556 : */
5557 192 : roles_list = roles_is_member_of(roleId, ROLERECURSE_PRIVS,
5558 : InvalidOid, NULL);
5559 :
5560 : /* initialize candidate result as default */
5561 192 : *grantorId = roleId;
5562 192 : *grantOptions = ACL_NO_RIGHTS;
5563 192 : nrights = 0;
5564 :
5565 360 : foreach(l, roles_list)
5566 : {
5567 308 : Oid otherrole = lfirst_oid(l);
5568 : AclMode otherprivs;
5569 :
5570 308 : otherprivs = aclmask_direct(acl, otherrole, ownerId,
5571 : needed_goptions, ACLMASK_ALL);
5572 308 : if (otherprivs == needed_goptions)
5573 : {
5574 : /* Found a suitable grantor */
5575 140 : *grantorId = otherrole;
5576 140 : *grantOptions = otherprivs;
5577 140 : return;
5578 : }
5579 :
5580 : /*
5581 : * If it has just some of the needed privileges, remember best
5582 : * candidate.
5583 : */
5584 168 : if (otherprivs != ACL_NO_RIGHTS)
5585 : {
5586 68 : int nnewrights = pg_popcount64(otherprivs);
5587 :
5588 68 : if (nnewrights > nrights)
5589 : {
5590 36 : *grantorId = otherrole;
5591 36 : *grantOptions = otherprivs;
5592 36 : nrights = nnewrights;
5593 : }
5594 : }
5595 : }
5596 : }
5597 :
5598 : /*
5599 : * get_role_oid - Given a role name, look up the role's OID.
5600 : *
5601 : * If missing_ok is false, throw an error if role name not found. If
5602 : * true, just return InvalidOid.
5603 : */
5604 : Oid
5605 22801 : get_role_oid(const char *rolname, bool missing_ok)
5606 : {
5607 : Oid oid;
5608 :
5609 22801 : oid = GetSysCacheOid1(AUTHNAME, Anum_pg_authid_oid,
5610 : CStringGetDatum(rolname));
5611 22801 : if (!OidIsValid(oid) && !missing_ok)
5612 40 : ereport(ERROR,
5613 : (errcode(ERRCODE_UNDEFINED_OBJECT),
5614 : errmsg("role \"%s\" does not exist", rolname)));
5615 22761 : return oid;
5616 : }
5617 :
5618 : /*
5619 : * get_role_oid_or_public - As above, but return ACL_ID_PUBLIC if the
5620 : * role name is "public".
5621 : */
5622 : Oid
5623 447 : get_role_oid_or_public(const char *rolname)
5624 : {
5625 447 : if (strcmp(rolname, "public") == 0)
5626 0 : return ACL_ID_PUBLIC;
5627 :
5628 447 : return get_role_oid(rolname, false);
5629 : }
5630 :
5631 : /*
5632 : * Given a RoleSpec node, return the OID it corresponds to. If missing_ok is
5633 : * true, return InvalidOid if the role does not exist.
5634 : *
5635 : * PUBLIC is always disallowed here. Routines wanting to handle the PUBLIC
5636 : * case must check the case separately.
5637 : */
5638 : Oid
5639 5877 : get_rolespec_oid(const RoleSpec *role, bool missing_ok)
5640 : {
5641 : Oid oid;
5642 :
5643 5877 : switch (role->roletype)
5644 : {
5645 5620 : case ROLESPEC_CSTRING:
5646 : Assert(role->rolename);
5647 5620 : oid = get_role_oid(role->rolename, missing_ok);
5648 5589 : break;
5649 :
5650 238 : case ROLESPEC_CURRENT_ROLE:
5651 : case ROLESPEC_CURRENT_USER:
5652 238 : oid = GetUserId();
5653 238 : break;
5654 :
5655 11 : case ROLESPEC_SESSION_USER:
5656 11 : oid = GetSessionUserId();
5657 11 : break;
5658 :
5659 8 : case ROLESPEC_PUBLIC:
5660 8 : ereport(ERROR,
5661 : (errcode(ERRCODE_UNDEFINED_OBJECT),
5662 : errmsg("role \"%s\" does not exist", "public")));
5663 : oid = InvalidOid; /* make compiler happy */
5664 : break;
5665 :
5666 0 : default:
5667 0 : elog(ERROR, "unexpected role type %d", role->roletype);
5668 : }
5669 :
5670 5838 : return oid;
5671 : }
5672 :
5673 : /*
5674 : * Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
5675 : * Caller must ReleaseSysCache when done with the result tuple.
5676 : */
5677 : HeapTuple
5678 442 : get_rolespec_tuple(const RoleSpec *role)
5679 : {
5680 : HeapTuple tuple;
5681 :
5682 442 : switch (role->roletype)
5683 : {
5684 416 : case ROLESPEC_CSTRING:
5685 : Assert(role->rolename);
5686 416 : tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolename));
5687 416 : if (!HeapTupleIsValid(tuple))
5688 6 : ereport(ERROR,
5689 : (errcode(ERRCODE_UNDEFINED_OBJECT),
5690 : errmsg("role \"%s\" does not exist", role->rolename)));
5691 410 : break;
5692 :
5693 14 : case ROLESPEC_CURRENT_ROLE:
5694 : case ROLESPEC_CURRENT_USER:
5695 14 : tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
5696 14 : if (!HeapTupleIsValid(tuple))
5697 0 : elog(ERROR, "cache lookup failed for role %u", GetUserId());
5698 14 : break;
5699 :
5700 6 : case ROLESPEC_SESSION_USER:
5701 6 : tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetSessionUserId()));
5702 6 : if (!HeapTupleIsValid(tuple))
5703 0 : elog(ERROR, "cache lookup failed for role %u", GetSessionUserId());
5704 6 : break;
5705 :
5706 6 : case ROLESPEC_PUBLIC:
5707 6 : ereport(ERROR,
5708 : (errcode(ERRCODE_UNDEFINED_OBJECT),
5709 : errmsg("role \"%s\" does not exist", "public")));
5710 : tuple = NULL; /* make compiler happy */
5711 : break;
5712 :
5713 0 : default:
5714 0 : elog(ERROR, "unexpected role type %d", role->roletype);
5715 : }
5716 :
5717 430 : return tuple;
5718 : }
5719 :
5720 : /*
5721 : * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
5722 : */
5723 : char *
5724 28 : get_rolespec_name(const RoleSpec *role)
5725 : {
5726 : HeapTuple tp;
5727 : Form_pg_authid authForm;
5728 : char *rolename;
5729 :
5730 28 : tp = get_rolespec_tuple(role);
5731 28 : authForm = (Form_pg_authid) GETSTRUCT(tp);
5732 28 : rolename = pstrdup(NameStr(authForm->rolname));
5733 28 : ReleaseSysCache(tp);
5734 :
5735 28 : return rolename;
5736 : }
5737 :
5738 : /*
5739 : * Given a RoleSpec, throw an error if the name is reserved, using detail_msg,
5740 : * if provided (which must be already translated).
5741 : *
5742 : * If node is NULL, no error is thrown. If detail_msg is NULL then no detail
5743 : * message is provided.
5744 : */
5745 : void
5746 349 : check_rolespec_name(const RoleSpec *role, const char *detail_msg)
5747 : {
5748 349 : if (!role)
5749 0 : return;
5750 :
5751 349 : if (role->roletype != ROLESPEC_CSTRING)
5752 26 : return;
5753 :
5754 323 : if (IsReservedName(role->rolename))
5755 : {
5756 0 : if (detail_msg)
5757 0 : ereport(ERROR,
5758 : (errcode(ERRCODE_RESERVED_NAME),
5759 : errmsg("role name \"%s\" is reserved",
5760 : role->rolename),
5761 : errdetail_internal("%s", detail_msg)));
5762 : else
5763 0 : ereport(ERROR,
5764 : (errcode(ERRCODE_RESERVED_NAME),
5765 : errmsg("role name \"%s\" is reserved",
5766 : role->rolename)));
5767 : }
5768 : }
|