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