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