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