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