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