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