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