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