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