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