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