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