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