1 /*-------------------------------------------------------------------------
2  *
3  * aclchk.c
4  *	  Routines to check access control permissions.
5  *
6  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/catalog/aclchk.c
12  *
13  * NOTES
14  *	  See acl.h.
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19 
20 #include "access/genam.h"
21 #include "access/heapam.h"
22 #include "access/htup_details.h"
23 #include "access/sysattr.h"
24 #include "access/xact.h"
25 #include "catalog/binary_upgrade.h"
26 #include "catalog/catalog.h"
27 #include "catalog/dependency.h"
28 #include "catalog/indexing.h"
29 #include "catalog/objectaccess.h"
30 #include "catalog/pg_aggregate.h"
31 #include "catalog/pg_am.h"
32 #include "catalog/pg_authid.h"
33 #include "catalog/pg_cast.h"
34 #include "catalog/pg_collation.h"
35 #include "catalog/pg_conversion.h"
36 #include "catalog/pg_database.h"
37 #include "catalog/pg_default_acl.h"
38 #include "catalog/pg_event_trigger.h"
39 #include "catalog/pg_extension.h"
40 #include "catalog/pg_foreign_data_wrapper.h"
41 #include "catalog/pg_foreign_server.h"
42 #include "catalog/pg_init_privs.h"
43 #include "catalog/pg_language.h"
44 #include "catalog/pg_largeobject.h"
45 #include "catalog/pg_largeobject_metadata.h"
46 #include "catalog/pg_namespace.h"
47 #include "catalog/pg_opclass.h"
48 #include "catalog/pg_operator.h"
49 #include "catalog/pg_opfamily.h"
50 #include "catalog/pg_proc.h"
51 #include "catalog/pg_statistic_ext.h"
52 #include "catalog/pg_subscription.h"
53 #include "catalog/pg_tablespace.h"
54 #include "catalog/pg_type.h"
55 #include "catalog/pg_ts_config.h"
56 #include "catalog/pg_ts_dict.h"
57 #include "catalog/pg_ts_parser.h"
58 #include "catalog/pg_ts_template.h"
59 #include "catalog/pg_transform.h"
60 #include "commands/dbcommands.h"
61 #include "commands/event_trigger.h"
62 #include "commands/extension.h"
63 #include "commands/proclang.h"
64 #include "commands/tablespace.h"
65 #include "foreign/foreign.h"
66 #include "miscadmin.h"
67 #include "nodes/makefuncs.h"
68 #include "parser/parse_func.h"
69 #include "parser/parse_type.h"
70 #include "utils/acl.h"
71 #include "utils/aclchk_internal.h"
72 #include "utils/builtins.h"
73 #include "utils/fmgroids.h"
74 #include "utils/lsyscache.h"
75 #include "utils/rel.h"
76 #include "utils/syscache.h"
77 #include "utils/tqual.h"
78 
79 
80 /*
81  * Internal format used by ALTER DEFAULT PRIVILEGES.
82  */
83 typedef struct
84 {
85 	Oid			roleid;			/* owning role */
86 	Oid			nspid;			/* namespace, or InvalidOid if none */
87 	/* remaining fields are same as in InternalGrant: */
88 	bool		is_grant;
89 	ObjectType	objtype;
90 	bool		all_privs;
91 	AclMode		privileges;
92 	List	   *grantees;
93 	bool		grant_option;
94 	DropBehavior behavior;
95 } InternalDefaultACL;
96 
97 /*
98  * When performing a binary-upgrade, pg_dump will call a function to set
99  * this variable to let us know that we need to populate the pg_init_privs
100  * table for the GRANT/REVOKE commands while this variable is set to true.
101  */
102 bool		binary_upgrade_record_init_privs = false;
103 
104 static void ExecGrantStmt_oids(InternalGrant *istmt);
105 static void ExecGrant_Relation(InternalGrant *grantStmt);
106 static void ExecGrant_Database(InternalGrant *grantStmt);
107 static void ExecGrant_Fdw(InternalGrant *grantStmt);
108 static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
109 static void ExecGrant_Function(InternalGrant *grantStmt);
110 static void ExecGrant_Language(InternalGrant *grantStmt);
111 static void ExecGrant_Largeobject(InternalGrant *grantStmt);
112 static void ExecGrant_Namespace(InternalGrant *grantStmt);
113 static void ExecGrant_Tablespace(InternalGrant *grantStmt);
114 static void ExecGrant_Type(InternalGrant *grantStmt);
115 
116 static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
117 static void SetDefaultACL(InternalDefaultACL *iacls);
118 
119 static List *objectNamesToOids(ObjectType objtype, List *objnames);
120 static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
121 static List *getRelationsInNamespace(Oid namespaceId, char relkind);
122 static void expand_col_privileges(List *colnames, Oid table_oid,
123 					  AclMode this_privileges,
124 					  AclMode *col_privileges,
125 					  int num_col_privileges);
126 static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
127 						  AclMode this_privileges,
128 						  AclMode *col_privileges,
129 						  int num_col_privileges);
130 static AclMode string_to_privilege(const char *privname);
131 static const char *privilege_to_string(AclMode privilege);
132 static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
133 						 bool all_privs, AclMode privileges,
134 						 Oid objectId, Oid grantorId,
135 						 ObjectType objtype, const char *objname,
136 						 AttrNumber att_number, const char *colname);
137 static AclMode pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum,
138 		   Oid roleid, AclMode mask, AclMaskHow how);
139 static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
140 						Acl *new_acl);
141 static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
142 							  Acl *new_acl);
143 
144 
145 #ifdef ACLDEBUG
146 static void
dumpacl(Acl * acl)147 dumpacl(Acl *acl)
148 {
149 	int			i;
150 	AclItem    *aip;
151 
152 	elog(DEBUG2, "acl size = %d, # acls = %d",
153 		 ACL_SIZE(acl), ACL_NUM(acl));
154 	aip = ACL_DAT(acl);
155 	for (i = 0; i < ACL_NUM(acl); ++i)
156 		elog(DEBUG2, "	acl[%d]: %s", i,
157 			 DatumGetCString(DirectFunctionCall1(aclitemout,
158 												 PointerGetDatum(aip + i))));
159 }
160 #endif							/* ACLDEBUG */
161 
162 
163 /*
164  * If is_grant is true, adds the given privileges for the list of
165  * grantees to the existing old_acl.  If is_grant is false, the
166  * privileges for the given grantees are removed from old_acl.
167  *
168  * NB: the original old_acl is pfree'd.
169  */
170 static Acl *
merge_acl_with_grant(Acl * old_acl,bool is_grant,bool grant_option,DropBehavior behavior,List * grantees,AclMode privileges,Oid grantorId,Oid ownerId)171 merge_acl_with_grant(Acl *old_acl, bool is_grant,
172 					 bool grant_option, DropBehavior behavior,
173 					 List *grantees, AclMode privileges,
174 					 Oid grantorId, Oid ownerId)
175 {
176 	unsigned	modechg;
177 	ListCell   *j;
178 	Acl		   *new_acl;
179 
180 	modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
181 
182 #ifdef ACLDEBUG
183 	dumpacl(old_acl);
184 #endif
185 	new_acl = old_acl;
186 
187 	foreach(j, grantees)
188 	{
189 		AclItem		aclitem;
190 		Acl		   *newer_acl;
191 
192 		aclitem.ai_grantee = lfirst_oid(j);
193 
194 		/*
195 		 * Grant options can only be granted to individual roles, not PUBLIC.
196 		 * The reason is that if a user would re-grant a privilege that he
197 		 * held through PUBLIC, and later the user is removed, the situation
198 		 * is impossible to clean up.
199 		 */
200 		if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
201 			ereport(ERROR,
202 					(errcode(ERRCODE_INVALID_GRANT_OPERATION),
203 					 errmsg("grant options can only be granted to roles")));
204 
205 		aclitem.ai_grantor = grantorId;
206 
207 		/*
208 		 * The asymmetry in the conditions here comes from the spec.  In
209 		 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
210 		 * to grant both the basic privilege and its grant option. But in
211 		 * REVOKE, plain revoke revokes both the basic privilege and its grant
212 		 * option, while REVOKE GRANT OPTION revokes only the option.
213 		 */
214 		ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
215 								   (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
216 								   (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
217 
218 		newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
219 
220 		/* avoid memory leak when there are many grantees */
221 		pfree(new_acl);
222 		new_acl = newer_acl;
223 
224 #ifdef ACLDEBUG
225 		dumpacl(new_acl);
226 #endif
227 	}
228 
229 	return new_acl;
230 }
231 
232 /*
233  * Restrict the privileges to what we can actually grant, and emit
234  * the standards-mandated warning and error messages.
235  */
236 static AclMode
restrict_and_check_grant(bool is_grant,AclMode avail_goptions,bool all_privs,AclMode privileges,Oid objectId,Oid grantorId,ObjectType objtype,const char * objname,AttrNumber att_number,const char * colname)237 restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
238 						 AclMode privileges, Oid objectId, Oid grantorId,
239 						 ObjectType objtype, const char *objname,
240 						 AttrNumber att_number, const char *colname)
241 {
242 	AclMode		this_privileges;
243 	AclMode		whole_mask;
244 
245 	switch (objtype)
246 	{
247 		case OBJECT_COLUMN:
248 			whole_mask = ACL_ALL_RIGHTS_COLUMN;
249 			break;
250 		case OBJECT_TABLE:
251 			whole_mask = ACL_ALL_RIGHTS_RELATION;
252 			break;
253 		case OBJECT_SEQUENCE:
254 			whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
255 			break;
256 		case OBJECT_DATABASE:
257 			whole_mask = ACL_ALL_RIGHTS_DATABASE;
258 			break;
259 		case OBJECT_FUNCTION:
260 			whole_mask = ACL_ALL_RIGHTS_FUNCTION;
261 			break;
262 		case OBJECT_LANGUAGE:
263 			whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
264 			break;
265 		case OBJECT_LARGEOBJECT:
266 			whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
267 			break;
268 		case OBJECT_SCHEMA:
269 			whole_mask = ACL_ALL_RIGHTS_SCHEMA;
270 			break;
271 		case OBJECT_TABLESPACE:
272 			whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
273 			break;
274 		case OBJECT_FDW:
275 			whole_mask = ACL_ALL_RIGHTS_FDW;
276 			break;
277 		case OBJECT_FOREIGN_SERVER:
278 			whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
279 			break;
280 		case OBJECT_EVENT_TRIGGER:
281 			elog(ERROR, "grantable rights not supported for event triggers");
282 			/* not reached, but keep compiler quiet */
283 			return ACL_NO_RIGHTS;
284 		case OBJECT_TYPE:
285 			whole_mask = ACL_ALL_RIGHTS_TYPE;
286 			break;
287 		default:
288 			elog(ERROR, "unrecognized object type: %d", objtype);
289 			/* not reached, but keep compiler quiet */
290 			return ACL_NO_RIGHTS;
291 	}
292 
293 	/*
294 	 * If we found no grant options, consider whether to issue a hard error.
295 	 * Per spec, having any privilege at all on the object will get you by
296 	 * here.
297 	 */
298 	if (avail_goptions == ACL_NO_RIGHTS)
299 	{
300 		if (pg_aclmask(objtype, objectId, att_number, grantorId,
301 					   whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
302 					   ACLMASK_ANY) == ACL_NO_RIGHTS)
303 		{
304 			if (objtype == OBJECT_COLUMN && colname)
305 				aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
306 			else
307 				aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
308 		}
309 	}
310 
311 	/*
312 	 * Restrict the operation to what we can actually grant or revoke, and
313 	 * issue a warning if appropriate.  (For REVOKE this isn't quite what the
314 	 * spec says to do: the spec seems to want a warning only if no privilege
315 	 * bits actually change in the ACL. In practice that behavior seems much
316 	 * too noisy, as well as inconsistent with the GRANT case.)
317 	 */
318 	this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
319 	if (is_grant)
320 	{
321 		if (this_privileges == 0)
322 		{
323 			if (objtype == OBJECT_COLUMN && colname)
324 				ereport(WARNING,
325 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
326 						 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
327 								colname, objname)));
328 			else
329 				ereport(WARNING,
330 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
331 						 errmsg("no privileges were granted for \"%s\"",
332 								objname)));
333 		}
334 		else if (!all_privs && this_privileges != privileges)
335 		{
336 			if (objtype == OBJECT_COLUMN && colname)
337 				ereport(WARNING,
338 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
339 						 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
340 								colname, objname)));
341 			else
342 				ereport(WARNING,
343 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
344 						 errmsg("not all privileges were granted for \"%s\"",
345 								objname)));
346 		}
347 	}
348 	else
349 	{
350 		if (this_privileges == 0)
351 		{
352 			if (objtype == OBJECT_COLUMN && colname)
353 				ereport(WARNING,
354 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
355 						 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
356 								colname, objname)));
357 			else
358 				ereport(WARNING,
359 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
360 						 errmsg("no privileges could be revoked for \"%s\"",
361 								objname)));
362 		}
363 		else if (!all_privs && this_privileges != privileges)
364 		{
365 			if (objtype == OBJECT_COLUMN && colname)
366 				ereport(WARNING,
367 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
368 						 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
369 								colname, objname)));
370 			else
371 				ereport(WARNING,
372 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
373 						 errmsg("not all privileges could be revoked for \"%s\"",
374 								objname)));
375 		}
376 	}
377 
378 	return this_privileges;
379 }
380 
381 /*
382  * Called to execute the utility commands GRANT and REVOKE
383  */
384 void
ExecuteGrantStmt(GrantStmt * stmt)385 ExecuteGrantStmt(GrantStmt *stmt)
386 {
387 	InternalGrant istmt;
388 	ListCell   *cell;
389 	const char *errormsg;
390 	AclMode		all_privileges;
391 
392 	/*
393 	 * Turn the regular GrantStmt into the InternalGrant form.
394 	 */
395 	istmt.is_grant = stmt->is_grant;
396 	istmt.objtype = stmt->objtype;
397 
398 	/* Collect the OIDs of the target objects */
399 	switch (stmt->targtype)
400 	{
401 		case ACL_TARGET_OBJECT:
402 			istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
403 			break;
404 		case ACL_TARGET_ALL_IN_SCHEMA:
405 			istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
406 			break;
407 			/* ACL_TARGET_DEFAULTS should not be seen here */
408 		default:
409 			elog(ERROR, "unrecognized GrantStmt.targtype: %d",
410 				 (int) stmt->targtype);
411 	}
412 
413 	/* all_privs to be filled below */
414 	/* privileges to be filled below */
415 	istmt.col_privs = NIL;		/* may get filled below */
416 	istmt.grantees = NIL;		/* filled below */
417 	istmt.grant_option = stmt->grant_option;
418 	istmt.behavior = stmt->behavior;
419 
420 	/*
421 	 * Convert the RoleSpec list into an Oid list.  Note that at this point we
422 	 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
423 	 * there shouldn't be any additional work needed to support this case.
424 	 */
425 	foreach(cell, stmt->grantees)
426 	{
427 		RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
428 		Oid			grantee_uid;
429 
430 		switch (grantee->roletype)
431 		{
432 			case ROLESPEC_PUBLIC:
433 				grantee_uid = ACL_ID_PUBLIC;
434 				break;
435 			default:
436 				grantee_uid = get_rolespec_oid(grantee, false);
437 				break;
438 		}
439 		istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
440 	}
441 
442 	/*
443 	 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
444 	 * bitmask.  Note: objtype can't be OBJECT_COLUMN.
445 	 */
446 	switch (stmt->objtype)
447 	{
448 		case OBJECT_TABLE:
449 
450 			/*
451 			 * Because this might be a sequence, we test both relation and
452 			 * sequence bits, and later do a more limited test when we know
453 			 * the object type.
454 			 */
455 			all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
456 			errormsg = gettext_noop("invalid privilege type %s for relation");
457 			break;
458 		case OBJECT_SEQUENCE:
459 			all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
460 			errormsg = gettext_noop("invalid privilege type %s for sequence");
461 			break;
462 		case OBJECT_DATABASE:
463 			all_privileges = ACL_ALL_RIGHTS_DATABASE;
464 			errormsg = gettext_noop("invalid privilege type %s for database");
465 			break;
466 		case OBJECT_DOMAIN:
467 			all_privileges = ACL_ALL_RIGHTS_TYPE;
468 			errormsg = gettext_noop("invalid privilege type %s for domain");
469 			break;
470 		case OBJECT_FUNCTION:
471 			all_privileges = ACL_ALL_RIGHTS_FUNCTION;
472 			errormsg = gettext_noop("invalid privilege type %s for function");
473 			break;
474 		case OBJECT_LANGUAGE:
475 			all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
476 			errormsg = gettext_noop("invalid privilege type %s for language");
477 			break;
478 		case OBJECT_LARGEOBJECT:
479 			all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
480 			errormsg = gettext_noop("invalid privilege type %s for large object");
481 			break;
482 		case OBJECT_SCHEMA:
483 			all_privileges = ACL_ALL_RIGHTS_SCHEMA;
484 			errormsg = gettext_noop("invalid privilege type %s for schema");
485 			break;
486 		case OBJECT_PROCEDURE:
487 			all_privileges = ACL_ALL_RIGHTS_FUNCTION;
488 			errormsg = gettext_noop("invalid privilege type %s for procedure");
489 			break;
490 		case OBJECT_ROUTINE:
491 			all_privileges = ACL_ALL_RIGHTS_FUNCTION;
492 			errormsg = gettext_noop("invalid privilege type %s for routine");
493 			break;
494 		case OBJECT_TABLESPACE:
495 			all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
496 			errormsg = gettext_noop("invalid privilege type %s for tablespace");
497 			break;
498 		case OBJECT_TYPE:
499 			all_privileges = ACL_ALL_RIGHTS_TYPE;
500 			errormsg = gettext_noop("invalid privilege type %s for type");
501 			break;
502 		case OBJECT_FDW:
503 			all_privileges = ACL_ALL_RIGHTS_FDW;
504 			errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
505 			break;
506 		case OBJECT_FOREIGN_SERVER:
507 			all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
508 			errormsg = gettext_noop("invalid privilege type %s for foreign server");
509 			break;
510 		default:
511 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
512 				 (int) stmt->objtype);
513 			/* keep compiler quiet */
514 			all_privileges = ACL_NO_RIGHTS;
515 			errormsg = NULL;
516 	}
517 
518 	if (stmt->privileges == NIL)
519 	{
520 		istmt.all_privs = true;
521 
522 		/*
523 		 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
524 		 * depending on the object type
525 		 */
526 		istmt.privileges = ACL_NO_RIGHTS;
527 	}
528 	else
529 	{
530 		istmt.all_privs = false;
531 		istmt.privileges = ACL_NO_RIGHTS;
532 
533 		foreach(cell, stmt->privileges)
534 		{
535 			AccessPriv *privnode = (AccessPriv *) lfirst(cell);
536 			AclMode		priv;
537 
538 			/*
539 			 * If it's a column-level specification, we just set it aside in
540 			 * col_privs for the moment; but insist it's for a relation.
541 			 */
542 			if (privnode->cols)
543 			{
544 				if (stmt->objtype != OBJECT_TABLE)
545 					ereport(ERROR,
546 							(errcode(ERRCODE_INVALID_GRANT_OPERATION),
547 							 errmsg("column privileges are only valid for relations")));
548 				istmt.col_privs = lappend(istmt.col_privs, privnode);
549 				continue;
550 			}
551 
552 			if (privnode->priv_name == NULL)	/* parser mistake? */
553 				elog(ERROR, "AccessPriv node must specify privilege or columns");
554 			priv = string_to_privilege(privnode->priv_name);
555 
556 			if (priv & ~((AclMode) all_privileges))
557 				ereport(ERROR,
558 						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
559 						 errmsg(errormsg, privilege_to_string(priv))));
560 
561 			istmt.privileges |= priv;
562 		}
563 	}
564 
565 	ExecGrantStmt_oids(&istmt);
566 }
567 
568 /*
569  * ExecGrantStmt_oids
570  *
571  * Internal entry point for granting and revoking privileges.
572  */
573 static void
ExecGrantStmt_oids(InternalGrant * istmt)574 ExecGrantStmt_oids(InternalGrant *istmt)
575 {
576 	switch (istmt->objtype)
577 	{
578 		case OBJECT_TABLE:
579 		case OBJECT_SEQUENCE:
580 			ExecGrant_Relation(istmt);
581 			break;
582 		case OBJECT_DATABASE:
583 			ExecGrant_Database(istmt);
584 			break;
585 		case OBJECT_DOMAIN:
586 		case OBJECT_TYPE:
587 			ExecGrant_Type(istmt);
588 			break;
589 		case OBJECT_FDW:
590 			ExecGrant_Fdw(istmt);
591 			break;
592 		case OBJECT_FOREIGN_SERVER:
593 			ExecGrant_ForeignServer(istmt);
594 			break;
595 		case OBJECT_FUNCTION:
596 		case OBJECT_PROCEDURE:
597 		case OBJECT_ROUTINE:
598 			ExecGrant_Function(istmt);
599 			break;
600 		case OBJECT_LANGUAGE:
601 			ExecGrant_Language(istmt);
602 			break;
603 		case OBJECT_LARGEOBJECT:
604 			ExecGrant_Largeobject(istmt);
605 			break;
606 		case OBJECT_SCHEMA:
607 			ExecGrant_Namespace(istmt);
608 			break;
609 		case OBJECT_TABLESPACE:
610 			ExecGrant_Tablespace(istmt);
611 			break;
612 		default:
613 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
614 				 (int) istmt->objtype);
615 	}
616 
617 	/*
618 	 * Pass the info to event triggers about the just-executed GRANT.  Note
619 	 * that we prefer to do it after actually executing it, because that gives
620 	 * the functions a chance to adjust the istmt with privileges actually
621 	 * granted.
622 	 */
623 	if (EventTriggerSupportsObjectType(istmt->objtype))
624 		EventTriggerCollectGrant(istmt);
625 }
626 
627 /*
628  * objectNamesToOids
629  *
630  * Turn a list of object names of a given type into an Oid list.
631  *
632  * XXX: This function doesn't take any sort of locks on the objects whose
633  * names it looks up.  In the face of concurrent DDL, we might easily latch
634  * onto an old version of an object, causing the GRANT or REVOKE statement
635  * to fail.
636  */
637 static List *
objectNamesToOids(ObjectType objtype,List * objnames)638 objectNamesToOids(ObjectType objtype, List *objnames)
639 {
640 	List	   *objects = NIL;
641 	ListCell   *cell;
642 
643 	Assert(objnames != NIL);
644 
645 	switch (objtype)
646 	{
647 		case OBJECT_TABLE:
648 		case OBJECT_SEQUENCE:
649 			foreach(cell, objnames)
650 			{
651 				RangeVar   *relvar = (RangeVar *) lfirst(cell);
652 				Oid			relOid;
653 
654 				relOid = RangeVarGetRelid(relvar, NoLock, false);
655 				objects = lappend_oid(objects, relOid);
656 			}
657 			break;
658 		case OBJECT_DATABASE:
659 			foreach(cell, objnames)
660 			{
661 				char	   *dbname = strVal(lfirst(cell));
662 				Oid			dbid;
663 
664 				dbid = get_database_oid(dbname, false);
665 				objects = lappend_oid(objects, dbid);
666 			}
667 			break;
668 		case OBJECT_DOMAIN:
669 		case OBJECT_TYPE:
670 			foreach(cell, objnames)
671 			{
672 				List	   *typname = (List *) lfirst(cell);
673 				Oid			oid;
674 
675 				oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
676 				objects = lappend_oid(objects, oid);
677 			}
678 			break;
679 		case OBJECT_FUNCTION:
680 			foreach(cell, objnames)
681 			{
682 				ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
683 				Oid			funcid;
684 
685 				funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
686 				objects = lappend_oid(objects, funcid);
687 			}
688 			break;
689 		case OBJECT_LANGUAGE:
690 			foreach(cell, objnames)
691 			{
692 				char	   *langname = strVal(lfirst(cell));
693 				Oid			oid;
694 
695 				oid = get_language_oid(langname, false);
696 				objects = lappend_oid(objects, oid);
697 			}
698 			break;
699 		case OBJECT_LARGEOBJECT:
700 			foreach(cell, objnames)
701 			{
702 				Oid			lobjOid = oidparse(lfirst(cell));
703 
704 				if (!LargeObjectExists(lobjOid))
705 					ereport(ERROR,
706 							(errcode(ERRCODE_UNDEFINED_OBJECT),
707 							 errmsg("large object %u does not exist",
708 									lobjOid)));
709 
710 				objects = lappend_oid(objects, lobjOid);
711 			}
712 			break;
713 		case OBJECT_SCHEMA:
714 			foreach(cell, objnames)
715 			{
716 				char	   *nspname = strVal(lfirst(cell));
717 				Oid			oid;
718 
719 				oid = get_namespace_oid(nspname, false);
720 				objects = lappend_oid(objects, oid);
721 			}
722 			break;
723 		case OBJECT_PROCEDURE:
724 			foreach(cell, objnames)
725 			{
726 				ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
727 				Oid			procid;
728 
729 				procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
730 				objects = lappend_oid(objects, procid);
731 			}
732 			break;
733 		case OBJECT_ROUTINE:
734 			foreach(cell, objnames)
735 			{
736 				ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
737 				Oid			routid;
738 
739 				routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
740 				objects = lappend_oid(objects, routid);
741 			}
742 			break;
743 		case OBJECT_TABLESPACE:
744 			foreach(cell, objnames)
745 			{
746 				char	   *spcname = strVal(lfirst(cell));
747 				Oid			spcoid;
748 
749 				spcoid = get_tablespace_oid(spcname, false);
750 				objects = lappend_oid(objects, spcoid);
751 			}
752 			break;
753 		case OBJECT_FDW:
754 			foreach(cell, objnames)
755 			{
756 				char	   *fdwname = strVal(lfirst(cell));
757 				Oid			fdwid = get_foreign_data_wrapper_oid(fdwname, false);
758 
759 				objects = lappend_oid(objects, fdwid);
760 			}
761 			break;
762 		case OBJECT_FOREIGN_SERVER:
763 			foreach(cell, objnames)
764 			{
765 				char	   *srvname = strVal(lfirst(cell));
766 				Oid			srvid = get_foreign_server_oid(srvname, false);
767 
768 				objects = lappend_oid(objects, srvid);
769 			}
770 			break;
771 		default:
772 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
773 				 (int) objtype);
774 	}
775 
776 	return objects;
777 }
778 
779 /*
780  * objectsInSchemaToOids
781  *
782  * Find all objects of a given type in specified schemas, and make a list
783  * of their Oids.  We check USAGE privilege on the schemas, but there is
784  * no privilege checking on the individual objects here.
785  */
786 static List *
objectsInSchemaToOids(ObjectType objtype,List * nspnames)787 objectsInSchemaToOids(ObjectType objtype, List *nspnames)
788 {
789 	List	   *objects = NIL;
790 	ListCell   *cell;
791 
792 	foreach(cell, nspnames)
793 	{
794 		char	   *nspname = strVal(lfirst(cell));
795 		Oid			namespaceId;
796 		List	   *objs;
797 
798 		namespaceId = LookupExplicitNamespace(nspname, false);
799 
800 		switch (objtype)
801 		{
802 			case OBJECT_TABLE:
803 				objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
804 				objects = list_concat(objects, objs);
805 				objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
806 				objects = list_concat(objects, objs);
807 				objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
808 				objects = list_concat(objects, objs);
809 				objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
810 				objects = list_concat(objects, objs);
811 				objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
812 				objects = list_concat(objects, objs);
813 				break;
814 			case OBJECT_SEQUENCE:
815 				objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
816 				objects = list_concat(objects, objs);
817 				break;
818 			case OBJECT_FUNCTION:
819 			case OBJECT_PROCEDURE:
820 			case OBJECT_ROUTINE:
821 				{
822 					ScanKeyData key[2];
823 					int			keycount;
824 					Relation	rel;
825 					HeapScanDesc scan;
826 					HeapTuple	tuple;
827 
828 					keycount = 0;
829 					ScanKeyInit(&key[keycount++],
830 								Anum_pg_proc_pronamespace,
831 								BTEqualStrategyNumber, F_OIDEQ,
832 								ObjectIdGetDatum(namespaceId));
833 
834 					if (objtype == OBJECT_FUNCTION)
835 						/* includes aggregates and window functions */
836 						ScanKeyInit(&key[keycount++],
837 									Anum_pg_proc_prokind,
838 									BTEqualStrategyNumber, F_CHARNE,
839 									CharGetDatum(PROKIND_PROCEDURE));
840 					else if (objtype == OBJECT_PROCEDURE)
841 						ScanKeyInit(&key[keycount++],
842 									Anum_pg_proc_prokind,
843 									BTEqualStrategyNumber, F_CHAREQ,
844 									CharGetDatum(PROKIND_PROCEDURE));
845 
846 					rel = heap_open(ProcedureRelationId, AccessShareLock);
847 					scan = heap_beginscan_catalog(rel, keycount, key);
848 
849 					while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
850 					{
851 						objects = lappend_oid(objects, HeapTupleGetOid(tuple));
852 					}
853 
854 					heap_endscan(scan);
855 					heap_close(rel, AccessShareLock);
856 				}
857 				break;
858 			default:
859 				/* should not happen */
860 				elog(ERROR, "unrecognized GrantStmt.objtype: %d",
861 					 (int) objtype);
862 		}
863 	}
864 
865 	return objects;
866 }
867 
868 /*
869  * getRelationsInNamespace
870  *
871  * Return Oid list of relations in given namespace filtered by relation kind
872  */
873 static List *
getRelationsInNamespace(Oid namespaceId,char relkind)874 getRelationsInNamespace(Oid namespaceId, char relkind)
875 {
876 	List	   *relations = NIL;
877 	ScanKeyData key[2];
878 	Relation	rel;
879 	HeapScanDesc scan;
880 	HeapTuple	tuple;
881 
882 	ScanKeyInit(&key[0],
883 				Anum_pg_class_relnamespace,
884 				BTEqualStrategyNumber, F_OIDEQ,
885 				ObjectIdGetDatum(namespaceId));
886 	ScanKeyInit(&key[1],
887 				Anum_pg_class_relkind,
888 				BTEqualStrategyNumber, F_CHAREQ,
889 				CharGetDatum(relkind));
890 
891 	rel = heap_open(RelationRelationId, AccessShareLock);
892 	scan = heap_beginscan_catalog(rel, 2, key);
893 
894 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
895 	{
896 		relations = lappend_oid(relations, HeapTupleGetOid(tuple));
897 	}
898 
899 	heap_endscan(scan);
900 	heap_close(rel, AccessShareLock);
901 
902 	return relations;
903 }
904 
905 
906 /*
907  * ALTER DEFAULT PRIVILEGES statement
908  */
909 void
ExecAlterDefaultPrivilegesStmt(ParseState * pstate,AlterDefaultPrivilegesStmt * stmt)910 ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
911 {
912 	GrantStmt  *action = stmt->action;
913 	InternalDefaultACL iacls;
914 	ListCell   *cell;
915 	List	   *rolespecs = NIL;
916 	List	   *nspnames = NIL;
917 	DefElem    *drolespecs = NULL;
918 	DefElem    *dnspnames = NULL;
919 	AclMode		all_privileges;
920 	const char *errormsg;
921 
922 	/* Deconstruct the "options" part of the statement */
923 	foreach(cell, stmt->options)
924 	{
925 		DefElem    *defel = (DefElem *) lfirst(cell);
926 
927 		if (strcmp(defel->defname, "schemas") == 0)
928 		{
929 			if (dnspnames)
930 				ereport(ERROR,
931 						(errcode(ERRCODE_SYNTAX_ERROR),
932 						 errmsg("conflicting or redundant options"),
933 						 parser_errposition(pstate, defel->location)));
934 			dnspnames = defel;
935 		}
936 		else if (strcmp(defel->defname, "roles") == 0)
937 		{
938 			if (drolespecs)
939 				ereport(ERROR,
940 						(errcode(ERRCODE_SYNTAX_ERROR),
941 						 errmsg("conflicting or redundant options"),
942 						 parser_errposition(pstate, defel->location)));
943 			drolespecs = defel;
944 		}
945 		else
946 			elog(ERROR, "option \"%s\" not recognized", defel->defname);
947 	}
948 
949 	if (dnspnames)
950 		nspnames = (List *) dnspnames->arg;
951 	if (drolespecs)
952 		rolespecs = (List *) drolespecs->arg;
953 
954 	/* Prepare the InternalDefaultACL representation of the statement */
955 	/* roleid to be filled below */
956 	/* nspid to be filled in SetDefaultACLsInSchemas */
957 	iacls.is_grant = action->is_grant;
958 	iacls.objtype = action->objtype;
959 	/* all_privs to be filled below */
960 	/* privileges to be filled below */
961 	iacls.grantees = NIL;		/* filled below */
962 	iacls.grant_option = action->grant_option;
963 	iacls.behavior = action->behavior;
964 
965 	/*
966 	 * Convert the RoleSpec list into an Oid list.  Note that at this point we
967 	 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
968 	 * there shouldn't be any additional work needed to support this case.
969 	 */
970 	foreach(cell, action->grantees)
971 	{
972 		RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
973 		Oid			grantee_uid;
974 
975 		switch (grantee->roletype)
976 		{
977 			case ROLESPEC_PUBLIC:
978 				grantee_uid = ACL_ID_PUBLIC;
979 				break;
980 			default:
981 				grantee_uid = get_rolespec_oid(grantee, false);
982 				break;
983 		}
984 		iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
985 	}
986 
987 	/*
988 	 * Convert action->privileges, a list of privilege strings, into an
989 	 * AclMode bitmask.
990 	 */
991 	switch (action->objtype)
992 	{
993 		case OBJECT_TABLE:
994 			all_privileges = ACL_ALL_RIGHTS_RELATION;
995 			errormsg = gettext_noop("invalid privilege type %s for relation");
996 			break;
997 		case OBJECT_SEQUENCE:
998 			all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
999 			errormsg = gettext_noop("invalid privilege type %s for sequence");
1000 			break;
1001 		case OBJECT_FUNCTION:
1002 			all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1003 			errormsg = gettext_noop("invalid privilege type %s for function");
1004 			break;
1005 		case OBJECT_PROCEDURE:
1006 			all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1007 			errormsg = gettext_noop("invalid privilege type %s for procedure");
1008 			break;
1009 		case OBJECT_ROUTINE:
1010 			all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1011 			errormsg = gettext_noop("invalid privilege type %s for routine");
1012 			break;
1013 		case OBJECT_TYPE:
1014 			all_privileges = ACL_ALL_RIGHTS_TYPE;
1015 			errormsg = gettext_noop("invalid privilege type %s for type");
1016 			break;
1017 		case OBJECT_SCHEMA:
1018 			all_privileges = ACL_ALL_RIGHTS_SCHEMA;
1019 			errormsg = gettext_noop("invalid privilege type %s for schema");
1020 			break;
1021 		default:
1022 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1023 				 (int) action->objtype);
1024 			/* keep compiler quiet */
1025 			all_privileges = ACL_NO_RIGHTS;
1026 			errormsg = NULL;
1027 	}
1028 
1029 	if (action->privileges == NIL)
1030 	{
1031 		iacls.all_privs = true;
1032 
1033 		/*
1034 		 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1035 		 * depending on the object type
1036 		 */
1037 		iacls.privileges = ACL_NO_RIGHTS;
1038 	}
1039 	else
1040 	{
1041 		iacls.all_privs = false;
1042 		iacls.privileges = ACL_NO_RIGHTS;
1043 
1044 		foreach(cell, action->privileges)
1045 		{
1046 			AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1047 			AclMode		priv;
1048 
1049 			if (privnode->cols)
1050 				ereport(ERROR,
1051 						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
1052 						 errmsg("default privileges cannot be set for columns")));
1053 
1054 			if (privnode->priv_name == NULL)	/* parser mistake? */
1055 				elog(ERROR, "AccessPriv node must specify privilege");
1056 			priv = string_to_privilege(privnode->priv_name);
1057 
1058 			if (priv & ~((AclMode) all_privileges))
1059 				ereport(ERROR,
1060 						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
1061 						 errmsg(errormsg, privilege_to_string(priv))));
1062 
1063 			iacls.privileges |= priv;
1064 		}
1065 	}
1066 
1067 	if (rolespecs == NIL)
1068 	{
1069 		/* Set permissions for myself */
1070 		iacls.roleid = GetUserId();
1071 
1072 		SetDefaultACLsInSchemas(&iacls, nspnames);
1073 	}
1074 	else
1075 	{
1076 		/* Look up the role OIDs and do permissions checks */
1077 		ListCell   *rolecell;
1078 
1079 		foreach(rolecell, rolespecs)
1080 		{
1081 			RoleSpec   *rolespec = lfirst(rolecell);
1082 
1083 			iacls.roleid = get_rolespec_oid(rolespec, false);
1084 
1085 			/*
1086 			 * We insist that calling user be a member of each target role. If
1087 			 * he has that, he could become that role anyway via SET ROLE, so
1088 			 * FOR ROLE is just a syntactic convenience and doesn't give any
1089 			 * special privileges.
1090 			 */
1091 			check_is_member_of_role(GetUserId(), iacls.roleid);
1092 
1093 			SetDefaultACLsInSchemas(&iacls, nspnames);
1094 		}
1095 	}
1096 }
1097 
1098 /*
1099  * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1100  *
1101  * All fields of *iacls except nspid were filled already
1102  */
1103 static void
SetDefaultACLsInSchemas(InternalDefaultACL * iacls,List * nspnames)1104 SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
1105 {
1106 	if (nspnames == NIL)
1107 	{
1108 		/* Set database-wide permissions if no schema was specified */
1109 		iacls->nspid = InvalidOid;
1110 
1111 		SetDefaultACL(iacls);
1112 	}
1113 	else
1114 	{
1115 		/* Look up the schema OIDs and set permissions for each one */
1116 		ListCell   *nspcell;
1117 
1118 		foreach(nspcell, nspnames)
1119 		{
1120 			char	   *nspname = strVal(lfirst(nspcell));
1121 
1122 			iacls->nspid = get_namespace_oid(nspname, false);
1123 
1124 			/*
1125 			 * We used to insist that the target role have CREATE privileges
1126 			 * on the schema, since without that it wouldn't be able to create
1127 			 * an object for which these default privileges would apply.
1128 			 * However, this check proved to be more confusing than helpful,
1129 			 * and it also caused certain database states to not be
1130 			 * dumpable/restorable, since revoking CREATE doesn't cause
1131 			 * default privileges for the schema to go away.  So now, we just
1132 			 * allow the ALTER; if the user lacks CREATE he'll find out when
1133 			 * he tries to create an object.
1134 			 */
1135 
1136 			SetDefaultACL(iacls);
1137 		}
1138 	}
1139 }
1140 
1141 
1142 /*
1143  * Create or update a pg_default_acl entry
1144  */
1145 static void
SetDefaultACL(InternalDefaultACL * iacls)1146 SetDefaultACL(InternalDefaultACL *iacls)
1147 {
1148 	AclMode		this_privileges = iacls->privileges;
1149 	char		objtype;
1150 	Relation	rel;
1151 	HeapTuple	tuple;
1152 	bool		isNew;
1153 	Acl		   *def_acl;
1154 	Acl		   *old_acl;
1155 	Acl		   *new_acl;
1156 	HeapTuple	newtuple;
1157 	Datum		values[Natts_pg_default_acl];
1158 	bool		nulls[Natts_pg_default_acl];
1159 	bool		replaces[Natts_pg_default_acl];
1160 	int			noldmembers;
1161 	int			nnewmembers;
1162 	Oid		   *oldmembers;
1163 	Oid		   *newmembers;
1164 
1165 	rel = heap_open(DefaultAclRelationId, RowExclusiveLock);
1166 
1167 	/*
1168 	 * The default for a global entry is the hard-wired default ACL for the
1169 	 * particular object type.  The default for non-global entries is an empty
1170 	 * ACL.  This must be so because global entries replace the hard-wired
1171 	 * defaults, while others are added on.
1172 	 */
1173 	if (!OidIsValid(iacls->nspid))
1174 		def_acl = acldefault(iacls->objtype, iacls->roleid);
1175 	else
1176 		def_acl = make_empty_acl();
1177 
1178 	/*
1179 	 * Convert ACL object type to pg_default_acl object type and handle
1180 	 * all_privs option
1181 	 */
1182 	switch (iacls->objtype)
1183 	{
1184 		case OBJECT_TABLE:
1185 			objtype = DEFACLOBJ_RELATION;
1186 			if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1187 				this_privileges = ACL_ALL_RIGHTS_RELATION;
1188 			break;
1189 
1190 		case OBJECT_SEQUENCE:
1191 			objtype = DEFACLOBJ_SEQUENCE;
1192 			if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1193 				this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1194 			break;
1195 
1196 		case OBJECT_FUNCTION:
1197 			objtype = DEFACLOBJ_FUNCTION;
1198 			if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1199 				this_privileges = ACL_ALL_RIGHTS_FUNCTION;
1200 			break;
1201 
1202 		case OBJECT_TYPE:
1203 			objtype = DEFACLOBJ_TYPE;
1204 			if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1205 				this_privileges = ACL_ALL_RIGHTS_TYPE;
1206 			break;
1207 
1208 		case OBJECT_SCHEMA:
1209 			if (OidIsValid(iacls->nspid))
1210 				ereport(ERROR,
1211 						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
1212 						 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1213 			objtype = DEFACLOBJ_NAMESPACE;
1214 			if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1215 				this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1216 			break;
1217 
1218 		default:
1219 			elog(ERROR, "unrecognized objtype: %d",
1220 				 (int) iacls->objtype);
1221 			objtype = 0;		/* keep compiler quiet */
1222 			break;
1223 	}
1224 
1225 	/* Search for existing row for this object type in catalog */
1226 	tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1227 							ObjectIdGetDatum(iacls->roleid),
1228 							ObjectIdGetDatum(iacls->nspid),
1229 							CharGetDatum(objtype));
1230 
1231 	if (HeapTupleIsValid(tuple))
1232 	{
1233 		Datum		aclDatum;
1234 		bool		isNull;
1235 
1236 		aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1237 								   Anum_pg_default_acl_defaclacl,
1238 								   &isNull);
1239 		if (!isNull)
1240 			old_acl = DatumGetAclPCopy(aclDatum);
1241 		else
1242 			old_acl = NULL;		/* this case shouldn't happen, probably */
1243 		isNew = false;
1244 	}
1245 	else
1246 	{
1247 		old_acl = NULL;
1248 		isNew = true;
1249 	}
1250 
1251 	if (old_acl != NULL)
1252 	{
1253 		/*
1254 		 * We need the members of both old and new ACLs so we can correct the
1255 		 * shared dependency information.  Collect data before
1256 		 * merge_acl_with_grant throws away old_acl.
1257 		 */
1258 		noldmembers = aclmembers(old_acl, &oldmembers);
1259 	}
1260 	else
1261 	{
1262 		/* If no or null entry, start with the default ACL value */
1263 		old_acl = aclcopy(def_acl);
1264 		/* There are no old member roles according to the catalogs */
1265 		noldmembers = 0;
1266 		oldmembers = NULL;
1267 	}
1268 
1269 	/*
1270 	 * Generate new ACL.  Grantor of rights is always the same as the target
1271 	 * role.
1272 	 */
1273 	new_acl = merge_acl_with_grant(old_acl,
1274 								   iacls->is_grant,
1275 								   iacls->grant_option,
1276 								   iacls->behavior,
1277 								   iacls->grantees,
1278 								   this_privileges,
1279 								   iacls->roleid,
1280 								   iacls->roleid);
1281 
1282 	/*
1283 	 * If the result is the same as the default value, we do not need an
1284 	 * explicit pg_default_acl entry, and should in fact remove the entry if
1285 	 * it exists.  Must sort both arrays to compare properly.
1286 	 */
1287 	aclitemsort(new_acl);
1288 	aclitemsort(def_acl);
1289 	if (aclequal(new_acl, def_acl))
1290 	{
1291 		/* delete old entry, if indeed there is one */
1292 		if (!isNew)
1293 		{
1294 			ObjectAddress myself;
1295 
1296 			/*
1297 			 * The dependency machinery will take care of removing all
1298 			 * associated dependency entries.  We use DROP_RESTRICT since
1299 			 * there shouldn't be anything depending on this entry.
1300 			 */
1301 			myself.classId = DefaultAclRelationId;
1302 			myself.objectId = HeapTupleGetOid(tuple);
1303 			myself.objectSubId = 0;
1304 
1305 			performDeletion(&myself, DROP_RESTRICT, 0);
1306 		}
1307 	}
1308 	else
1309 	{
1310 		/* Prepare to insert or update pg_default_acl entry */
1311 		MemSet(values, 0, sizeof(values));
1312 		MemSet(nulls, false, sizeof(nulls));
1313 		MemSet(replaces, false, sizeof(replaces));
1314 
1315 		if (isNew)
1316 		{
1317 			/* insert new entry */
1318 			values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1319 			values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1320 			values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1321 			values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1322 
1323 			newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1324 			CatalogTupleInsert(rel, newtuple);
1325 		}
1326 		else
1327 		{
1328 			/* update existing entry */
1329 			values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1330 			replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1331 
1332 			newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1333 										 values, nulls, replaces);
1334 			CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1335 		}
1336 
1337 		/* these dependencies don't change in an update */
1338 		if (isNew)
1339 		{
1340 			/* dependency on role */
1341 			recordDependencyOnOwner(DefaultAclRelationId,
1342 									HeapTupleGetOid(newtuple),
1343 									iacls->roleid);
1344 
1345 			/* dependency on namespace */
1346 			if (OidIsValid(iacls->nspid))
1347 			{
1348 				ObjectAddress myself,
1349 							referenced;
1350 
1351 				myself.classId = DefaultAclRelationId;
1352 				myself.objectId = HeapTupleGetOid(newtuple);
1353 				myself.objectSubId = 0;
1354 
1355 				referenced.classId = NamespaceRelationId;
1356 				referenced.objectId = iacls->nspid;
1357 				referenced.objectSubId = 0;
1358 
1359 				recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1360 			}
1361 		}
1362 
1363 		/*
1364 		 * Update the shared dependency ACL info
1365 		 */
1366 		nnewmembers = aclmembers(new_acl, &newmembers);
1367 
1368 		updateAclDependencies(DefaultAclRelationId,
1369 							  HeapTupleGetOid(newtuple), 0,
1370 							  iacls->roleid,
1371 							  noldmembers, oldmembers,
1372 							  nnewmembers, newmembers);
1373 
1374 		if (isNew)
1375 			InvokeObjectPostCreateHook(DefaultAclRelationId,
1376 									   HeapTupleGetOid(newtuple), 0);
1377 		else
1378 			InvokeObjectPostAlterHook(DefaultAclRelationId,
1379 									  HeapTupleGetOid(newtuple), 0);
1380 	}
1381 
1382 	if (HeapTupleIsValid(tuple))
1383 		ReleaseSysCache(tuple);
1384 
1385 	heap_close(rel, RowExclusiveLock);
1386 
1387 	/* prevent error when processing duplicate objects */
1388 	CommandCounterIncrement();
1389 }
1390 
1391 
1392 /*
1393  * RemoveRoleFromObjectACL
1394  *
1395  * Used by shdepDropOwned to remove mentions of a role in ACLs
1396  */
1397 void
RemoveRoleFromObjectACL(Oid roleid,Oid classid,Oid objid)1398 RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1399 {
1400 	if (classid == DefaultAclRelationId)
1401 	{
1402 		InternalDefaultACL iacls;
1403 		Form_pg_default_acl pg_default_acl_tuple;
1404 		Relation	rel;
1405 		ScanKeyData skey[1];
1406 		SysScanDesc scan;
1407 		HeapTuple	tuple;
1408 
1409 		/* first fetch info needed by SetDefaultACL */
1410 		rel = heap_open(DefaultAclRelationId, AccessShareLock);
1411 
1412 		ScanKeyInit(&skey[0],
1413 					ObjectIdAttributeNumber,
1414 					BTEqualStrategyNumber, F_OIDEQ,
1415 					ObjectIdGetDatum(objid));
1416 
1417 		scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1418 								  NULL, 1, skey);
1419 
1420 		tuple = systable_getnext(scan);
1421 
1422 		if (!HeapTupleIsValid(tuple))
1423 			elog(ERROR, "could not find tuple for default ACL %u", objid);
1424 
1425 		pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1426 
1427 		iacls.roleid = pg_default_acl_tuple->defaclrole;
1428 		iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1429 
1430 		switch (pg_default_acl_tuple->defaclobjtype)
1431 		{
1432 			case DEFACLOBJ_RELATION:
1433 				iacls.objtype = OBJECT_TABLE;
1434 				break;
1435 			case DEFACLOBJ_SEQUENCE:
1436 				iacls.objtype = OBJECT_SEQUENCE;
1437 				break;
1438 			case DEFACLOBJ_FUNCTION:
1439 				iacls.objtype = OBJECT_FUNCTION;
1440 				break;
1441 			case DEFACLOBJ_TYPE:
1442 				iacls.objtype = OBJECT_TYPE;
1443 				break;
1444 			case DEFACLOBJ_NAMESPACE:
1445 				iacls.objtype = OBJECT_SCHEMA;
1446 				break;
1447 			default:
1448 				/* Shouldn't get here */
1449 				elog(ERROR, "unexpected default ACL type: %d",
1450 					 (int) pg_default_acl_tuple->defaclobjtype);
1451 				break;
1452 		}
1453 
1454 		systable_endscan(scan);
1455 		heap_close(rel, AccessShareLock);
1456 
1457 		iacls.is_grant = false;
1458 		iacls.all_privs = true;
1459 		iacls.privileges = ACL_NO_RIGHTS;
1460 		iacls.grantees = list_make1_oid(roleid);
1461 		iacls.grant_option = false;
1462 		iacls.behavior = DROP_CASCADE;
1463 
1464 		/* Do it */
1465 		SetDefaultACL(&iacls);
1466 	}
1467 	else
1468 	{
1469 		InternalGrant istmt;
1470 
1471 		switch (classid)
1472 		{
1473 			case RelationRelationId:
1474 				/* it's OK to use TABLE for a sequence */
1475 				istmt.objtype = OBJECT_TABLE;
1476 				break;
1477 			case DatabaseRelationId:
1478 				istmt.objtype = OBJECT_DATABASE;
1479 				break;
1480 			case TypeRelationId:
1481 				istmt.objtype = OBJECT_TYPE;
1482 				break;
1483 			case ProcedureRelationId:
1484 				istmt.objtype = OBJECT_ROUTINE;
1485 				break;
1486 			case LanguageRelationId:
1487 				istmt.objtype = OBJECT_LANGUAGE;
1488 				break;
1489 			case LargeObjectRelationId:
1490 				istmt.objtype = OBJECT_LARGEOBJECT;
1491 				break;
1492 			case NamespaceRelationId:
1493 				istmt.objtype = OBJECT_SCHEMA;
1494 				break;
1495 			case TableSpaceRelationId:
1496 				istmt.objtype = OBJECT_TABLESPACE;
1497 				break;
1498 			case ForeignServerRelationId:
1499 				istmt.objtype = OBJECT_FOREIGN_SERVER;
1500 				break;
1501 			case ForeignDataWrapperRelationId:
1502 				istmt.objtype = OBJECT_FDW;
1503 				break;
1504 			default:
1505 				elog(ERROR, "unexpected object class %u", classid);
1506 				break;
1507 		}
1508 		istmt.is_grant = false;
1509 		istmt.objects = list_make1_oid(objid);
1510 		istmt.all_privs = true;
1511 		istmt.privileges = ACL_NO_RIGHTS;
1512 		istmt.col_privs = NIL;
1513 		istmt.grantees = list_make1_oid(roleid);
1514 		istmt.grant_option = false;
1515 		istmt.behavior = DROP_CASCADE;
1516 
1517 		ExecGrantStmt_oids(&istmt);
1518 	}
1519 }
1520 
1521 
1522 /*
1523  * Remove a pg_default_acl entry
1524  */
1525 void
RemoveDefaultACLById(Oid defaclOid)1526 RemoveDefaultACLById(Oid defaclOid)
1527 {
1528 	Relation	rel;
1529 	ScanKeyData skey[1];
1530 	SysScanDesc scan;
1531 	HeapTuple	tuple;
1532 
1533 	rel = heap_open(DefaultAclRelationId, RowExclusiveLock);
1534 
1535 	ScanKeyInit(&skey[0],
1536 				ObjectIdAttributeNumber,
1537 				BTEqualStrategyNumber, F_OIDEQ,
1538 				ObjectIdGetDatum(defaclOid));
1539 
1540 	scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1541 							  NULL, 1, skey);
1542 
1543 	tuple = systable_getnext(scan);
1544 
1545 	if (!HeapTupleIsValid(tuple))
1546 		elog(ERROR, "could not find tuple for default ACL %u", defaclOid);
1547 
1548 	CatalogTupleDelete(rel, &tuple->t_self);
1549 
1550 	systable_endscan(scan);
1551 	heap_close(rel, RowExclusiveLock);
1552 }
1553 
1554 
1555 /*
1556  * expand_col_privileges
1557  *
1558  * OR the specified privilege(s) into per-column array entries for each
1559  * specified attribute.  The per-column array is indexed starting at
1560  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1561  */
1562 static void
expand_col_privileges(List * colnames,Oid table_oid,AclMode this_privileges,AclMode * col_privileges,int num_col_privileges)1563 expand_col_privileges(List *colnames, Oid table_oid,
1564 					  AclMode this_privileges,
1565 					  AclMode *col_privileges,
1566 					  int num_col_privileges)
1567 {
1568 	ListCell   *cell;
1569 
1570 	foreach(cell, colnames)
1571 	{
1572 		char	   *colname = strVal(lfirst(cell));
1573 		AttrNumber	attnum;
1574 
1575 		attnum = get_attnum(table_oid, colname);
1576 		if (attnum == InvalidAttrNumber)
1577 			ereport(ERROR,
1578 					(errcode(ERRCODE_UNDEFINED_COLUMN),
1579 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
1580 							colname, get_rel_name(table_oid))));
1581 		attnum -= FirstLowInvalidHeapAttributeNumber;
1582 		if (attnum <= 0 || attnum >= num_col_privileges)
1583 			elog(ERROR, "column number out of range");	/* safety check */
1584 		col_privileges[attnum] |= this_privileges;
1585 	}
1586 }
1587 
1588 /*
1589  * expand_all_col_privileges
1590  *
1591  * OR the specified privilege(s) into per-column array entries for each valid
1592  * attribute of a relation.  The per-column array is indexed starting at
1593  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1594  */
1595 static void
expand_all_col_privileges(Oid table_oid,Form_pg_class classForm,AclMode this_privileges,AclMode * col_privileges,int num_col_privileges)1596 expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
1597 						  AclMode this_privileges,
1598 						  AclMode *col_privileges,
1599 						  int num_col_privileges)
1600 {
1601 	AttrNumber	curr_att;
1602 
1603 	Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1604 	for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1605 		 curr_att <= classForm->relnatts;
1606 		 curr_att++)
1607 	{
1608 		HeapTuple	attTuple;
1609 		bool		isdropped;
1610 
1611 		if (curr_att == InvalidAttrNumber)
1612 			continue;
1613 
1614 		/* Skip OID column if it doesn't exist */
1615 		if (curr_att == ObjectIdAttributeNumber && !classForm->relhasoids)
1616 			continue;
1617 
1618 		/* Views don't have any system columns at all */
1619 		if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1620 			continue;
1621 
1622 		attTuple = SearchSysCache2(ATTNUM,
1623 								   ObjectIdGetDatum(table_oid),
1624 								   Int16GetDatum(curr_att));
1625 		if (!HeapTupleIsValid(attTuple))
1626 			elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1627 				 curr_att, table_oid);
1628 
1629 		isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1630 
1631 		ReleaseSysCache(attTuple);
1632 
1633 		/* ignore dropped columns */
1634 		if (isdropped)
1635 			continue;
1636 
1637 		col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1638 	}
1639 }
1640 
1641 /*
1642  *	This processes attributes, but expects to be called from
1643  *	ExecGrant_Relation, not directly from ExecGrantStmt.
1644  */
1645 static void
ExecGrant_Attribute(InternalGrant * istmt,Oid relOid,const char * relname,AttrNumber attnum,Oid ownerId,AclMode col_privileges,Relation attRelation,const Acl * old_rel_acl)1646 ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1647 					AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1648 					Relation attRelation, const Acl *old_rel_acl)
1649 {
1650 	HeapTuple	attr_tuple;
1651 	Form_pg_attribute pg_attribute_tuple;
1652 	Acl		   *old_acl;
1653 	Acl		   *new_acl;
1654 	Acl		   *merged_acl;
1655 	Datum		aclDatum;
1656 	bool		isNull;
1657 	Oid			grantorId;
1658 	AclMode		avail_goptions;
1659 	bool		need_update;
1660 	HeapTuple	newtuple;
1661 	Datum		values[Natts_pg_attribute];
1662 	bool		nulls[Natts_pg_attribute];
1663 	bool		replaces[Natts_pg_attribute];
1664 	int			noldmembers;
1665 	int			nnewmembers;
1666 	Oid		   *oldmembers;
1667 	Oid		   *newmembers;
1668 
1669 	attr_tuple = SearchSysCache2(ATTNUM,
1670 								 ObjectIdGetDatum(relOid),
1671 								 Int16GetDatum(attnum));
1672 	if (!HeapTupleIsValid(attr_tuple))
1673 		elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1674 			 attnum, relOid);
1675 	pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1676 
1677 	/*
1678 	 * Get working copy of existing ACL. If there's no ACL, substitute the
1679 	 * proper default.
1680 	 */
1681 	aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1682 							   &isNull);
1683 	if (isNull)
1684 	{
1685 		old_acl = acldefault(OBJECT_COLUMN, ownerId);
1686 		/* There are no old member roles according to the catalogs */
1687 		noldmembers = 0;
1688 		oldmembers = NULL;
1689 	}
1690 	else
1691 	{
1692 		old_acl = DatumGetAclPCopy(aclDatum);
1693 		/* Get the roles mentioned in the existing ACL */
1694 		noldmembers = aclmembers(old_acl, &oldmembers);
1695 	}
1696 
1697 	/*
1698 	 * In select_best_grantor we should consider existing table-level ACL bits
1699 	 * as well as the per-column ACL.  Build a new ACL that is their
1700 	 * concatenation.  (This is a bit cheap and dirty compared to merging them
1701 	 * properly with no duplications, but it's all we need here.)
1702 	 */
1703 	merged_acl = aclconcat(old_rel_acl, old_acl);
1704 
1705 	/* Determine ID to do the grant as, and available grant options */
1706 	select_best_grantor(GetUserId(), col_privileges,
1707 						merged_acl, ownerId,
1708 						&grantorId, &avail_goptions);
1709 
1710 	pfree(merged_acl);
1711 
1712 	/*
1713 	 * Restrict the privileges to what we can actually grant, and emit the
1714 	 * standards-mandated warning and error messages.  Note: we don't track
1715 	 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1716 	 * each column; we just approximate it by whether all the possible
1717 	 * privileges are specified now.  Since the all_privs flag only determines
1718 	 * whether a warning is issued, this seems close enough.
1719 	 */
1720 	col_privileges =
1721 		restrict_and_check_grant(istmt->is_grant, avail_goptions,
1722 								 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1723 								 col_privileges,
1724 								 relOid, grantorId, OBJECT_COLUMN,
1725 								 relname, attnum,
1726 								 NameStr(pg_attribute_tuple->attname));
1727 
1728 	/*
1729 	 * Generate new ACL.
1730 	 */
1731 	new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1732 								   istmt->grant_option,
1733 								   istmt->behavior, istmt->grantees,
1734 								   col_privileges, grantorId,
1735 								   ownerId);
1736 
1737 	/*
1738 	 * We need the members of both old and new ACLs so we can correct the
1739 	 * shared dependency information.
1740 	 */
1741 	nnewmembers = aclmembers(new_acl, &newmembers);
1742 
1743 	/* finished building new ACL value, now insert it */
1744 	MemSet(values, 0, sizeof(values));
1745 	MemSet(nulls, false, sizeof(nulls));
1746 	MemSet(replaces, false, sizeof(replaces));
1747 
1748 	/*
1749 	 * If the updated ACL is empty, we can set attacl to null, and maybe even
1750 	 * avoid an update of the pg_attribute row.  This is worth testing because
1751 	 * we'll come through here multiple times for any relation-level REVOKE,
1752 	 * even if there were never any column GRANTs.  Note we are assuming that
1753 	 * the "default" ACL state for columns is empty.
1754 	 */
1755 	if (ACL_NUM(new_acl) > 0)
1756 	{
1757 		values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1758 		need_update = true;
1759 	}
1760 	else
1761 	{
1762 		nulls[Anum_pg_attribute_attacl - 1] = true;
1763 		need_update = !isNull;
1764 	}
1765 	replaces[Anum_pg_attribute_attacl - 1] = true;
1766 
1767 	if (need_update)
1768 	{
1769 		newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1770 									 values, nulls, replaces);
1771 
1772 		CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1773 
1774 		/* Update initial privileges for extensions */
1775 		recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1776 								ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1777 
1778 		/* Update the shared dependency ACL info */
1779 		updateAclDependencies(RelationRelationId, relOid, attnum,
1780 							  ownerId,
1781 							  noldmembers, oldmembers,
1782 							  nnewmembers, newmembers);
1783 	}
1784 
1785 	pfree(new_acl);
1786 
1787 	ReleaseSysCache(attr_tuple);
1788 }
1789 
1790 /*
1791  *	This processes both sequences and non-sequences.
1792  */
1793 static void
ExecGrant_Relation(InternalGrant * istmt)1794 ExecGrant_Relation(InternalGrant *istmt)
1795 {
1796 	Relation	relation;
1797 	Relation	attRelation;
1798 	ListCell   *cell;
1799 
1800 	relation = heap_open(RelationRelationId, RowExclusiveLock);
1801 	attRelation = heap_open(AttributeRelationId, RowExclusiveLock);
1802 
1803 	foreach(cell, istmt->objects)
1804 	{
1805 		Oid			relOid = lfirst_oid(cell);
1806 		Datum		aclDatum;
1807 		Form_pg_class pg_class_tuple;
1808 		bool		isNull;
1809 		AclMode		this_privileges;
1810 		AclMode    *col_privileges;
1811 		int			num_col_privileges;
1812 		bool		have_col_privileges;
1813 		Acl		   *old_acl;
1814 		Acl		   *old_rel_acl;
1815 		int			noldmembers;
1816 		Oid		   *oldmembers;
1817 		Oid			ownerId;
1818 		HeapTuple	tuple;
1819 		ListCell   *cell_colprivs;
1820 
1821 		tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
1822 		if (!HeapTupleIsValid(tuple))
1823 			elog(ERROR, "cache lookup failed for relation %u", relOid);
1824 		pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1825 
1826 		/* Not sensible to grant on an index */
1827 		if (pg_class_tuple->relkind == RELKIND_INDEX ||
1828 			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1829 			ereport(ERROR,
1830 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1831 					 errmsg("\"%s\" is an index",
1832 							NameStr(pg_class_tuple->relname))));
1833 
1834 		/* Composite types aren't tables either */
1835 		if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1836 			ereport(ERROR,
1837 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1838 					 errmsg("\"%s\" is a composite type",
1839 							NameStr(pg_class_tuple->relname))));
1840 
1841 		/* Used GRANT SEQUENCE on a non-sequence? */
1842 		if (istmt->objtype == OBJECT_SEQUENCE &&
1843 			pg_class_tuple->relkind != RELKIND_SEQUENCE)
1844 			ereport(ERROR,
1845 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1846 					 errmsg("\"%s\" is not a sequence",
1847 							NameStr(pg_class_tuple->relname))));
1848 
1849 		/* Adjust the default permissions based on object type */
1850 		if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1851 		{
1852 			if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1853 				this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1854 			else
1855 				this_privileges = ACL_ALL_RIGHTS_RELATION;
1856 		}
1857 		else
1858 			this_privileges = istmt->privileges;
1859 
1860 		/*
1861 		 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1862 		 * so we have to look at the relkind to determine the supported
1863 		 * permissions.  The OR of table and sequence permissions were already
1864 		 * checked.
1865 		 */
1866 		if (istmt->objtype == OBJECT_TABLE)
1867 		{
1868 			if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1869 			{
1870 				/*
1871 				 * For backward compatibility, just throw a warning for
1872 				 * invalid sequence permissions when using the non-sequence
1873 				 * GRANT syntax.
1874 				 */
1875 				if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1876 				{
1877 					/*
1878 					 * Mention the object name because the user needs to know
1879 					 * which operations succeeded.  This is required because
1880 					 * WARNING allows the command to continue.
1881 					 */
1882 					ereport(WARNING,
1883 							(errcode(ERRCODE_INVALID_GRANT_OPERATION),
1884 							 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1885 									NameStr(pg_class_tuple->relname))));
1886 					this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1887 				}
1888 			}
1889 			else
1890 			{
1891 				if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1892 				{
1893 					/*
1894 					 * USAGE is the only permission supported by sequences but
1895 					 * not by non-sequences.  Don't mention the object name
1896 					 * because we didn't in the combined TABLE | SEQUENCE
1897 					 * check.
1898 					 */
1899 					ereport(ERROR,
1900 							(errcode(ERRCODE_INVALID_GRANT_OPERATION),
1901 							 errmsg("invalid privilege type %s for table",
1902 									"USAGE")));
1903 				}
1904 			}
1905 		}
1906 
1907 		/*
1908 		 * Set up array in which we'll accumulate any column privilege bits
1909 		 * that need modification.  The array is indexed such that entry [0]
1910 		 * corresponds to FirstLowInvalidHeapAttributeNumber.
1911 		 */
1912 		num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1913 		col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1914 		have_col_privileges = false;
1915 
1916 		/*
1917 		 * If we are revoking relation privileges that are also column
1918 		 * privileges, we must implicitly revoke them from each column too,
1919 		 * per SQL spec.  (We don't need to implicitly add column privileges
1920 		 * during GRANT because the permissions-checking code always checks
1921 		 * both relation and per-column privileges.)
1922 		 */
1923 		if (!istmt->is_grant &&
1924 			(this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1925 		{
1926 			expand_all_col_privileges(relOid, pg_class_tuple,
1927 									  this_privileges & ACL_ALL_RIGHTS_COLUMN,
1928 									  col_privileges,
1929 									  num_col_privileges);
1930 			have_col_privileges = true;
1931 		}
1932 
1933 		/*
1934 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
1935 		 * substitute the proper default.
1936 		 */
1937 		ownerId = pg_class_tuple->relowner;
1938 		aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1939 								   &isNull);
1940 		if (isNull)
1941 		{
1942 			switch (pg_class_tuple->relkind)
1943 			{
1944 				case RELKIND_SEQUENCE:
1945 					old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1946 					break;
1947 				default:
1948 					old_acl = acldefault(OBJECT_TABLE, ownerId);
1949 					break;
1950 			}
1951 			/* There are no old member roles according to the catalogs */
1952 			noldmembers = 0;
1953 			oldmembers = NULL;
1954 		}
1955 		else
1956 		{
1957 			old_acl = DatumGetAclPCopy(aclDatum);
1958 			/* Get the roles mentioned in the existing ACL */
1959 			noldmembers = aclmembers(old_acl, &oldmembers);
1960 		}
1961 
1962 		/* Need an extra copy of original rel ACL for column handling */
1963 		old_rel_acl = aclcopy(old_acl);
1964 
1965 		/*
1966 		 * Handle relation-level privileges, if any were specified
1967 		 */
1968 		if (this_privileges != ACL_NO_RIGHTS)
1969 		{
1970 			AclMode		avail_goptions;
1971 			Acl		   *new_acl;
1972 			Oid			grantorId;
1973 			HeapTuple	newtuple;
1974 			Datum		values[Natts_pg_class];
1975 			bool		nulls[Natts_pg_class];
1976 			bool		replaces[Natts_pg_class];
1977 			int			nnewmembers;
1978 			Oid		   *newmembers;
1979 			ObjectType	objtype;
1980 
1981 			/* Determine ID to do the grant as, and available grant options */
1982 			select_best_grantor(GetUserId(), this_privileges,
1983 								old_acl, ownerId,
1984 								&grantorId, &avail_goptions);
1985 
1986 			switch (pg_class_tuple->relkind)
1987 			{
1988 				case RELKIND_SEQUENCE:
1989 					objtype = OBJECT_SEQUENCE;
1990 					break;
1991 				default:
1992 					objtype = OBJECT_TABLE;
1993 					break;
1994 			}
1995 
1996 			/*
1997 			 * Restrict the privileges to what we can actually grant, and emit
1998 			 * the standards-mandated warning and error messages.
1999 			 */
2000 			this_privileges =
2001 				restrict_and_check_grant(istmt->is_grant, avail_goptions,
2002 										 istmt->all_privs, this_privileges,
2003 										 relOid, grantorId, objtype,
2004 										 NameStr(pg_class_tuple->relname),
2005 										 0, NULL);
2006 
2007 			/*
2008 			 * Generate new ACL.
2009 			 */
2010 			new_acl = merge_acl_with_grant(old_acl,
2011 										   istmt->is_grant,
2012 										   istmt->grant_option,
2013 										   istmt->behavior,
2014 										   istmt->grantees,
2015 										   this_privileges,
2016 										   grantorId,
2017 										   ownerId);
2018 
2019 			/*
2020 			 * We need the members of both old and new ACLs so we can correct
2021 			 * the shared dependency information.
2022 			 */
2023 			nnewmembers = aclmembers(new_acl, &newmembers);
2024 
2025 			/* finished building new ACL value, now insert it */
2026 			MemSet(values, 0, sizeof(values));
2027 			MemSet(nulls, false, sizeof(nulls));
2028 			MemSet(replaces, false, sizeof(replaces));
2029 
2030 			replaces[Anum_pg_class_relacl - 1] = true;
2031 			values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
2032 
2033 			newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2034 										 values, nulls, replaces);
2035 
2036 			CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2037 
2038 			/* Update initial privileges for extensions */
2039 			recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2040 
2041 			/* Update the shared dependency ACL info */
2042 			updateAclDependencies(RelationRelationId, relOid, 0,
2043 								  ownerId,
2044 								  noldmembers, oldmembers,
2045 								  nnewmembers, newmembers);
2046 
2047 			pfree(new_acl);
2048 		}
2049 
2050 		/*
2051 		 * Handle column-level privileges, if any were specified or implied.
2052 		 * We first expand the user-specified column privileges into the
2053 		 * array, and then iterate over all nonempty array entries.
2054 		 */
2055 		foreach(cell_colprivs, istmt->col_privs)
2056 		{
2057 			AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2058 
2059 			if (col_privs->priv_name == NULL)
2060 				this_privileges = ACL_ALL_RIGHTS_COLUMN;
2061 			else
2062 				this_privileges = string_to_privilege(col_privs->priv_name);
2063 
2064 			if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2065 				ereport(ERROR,
2066 						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
2067 						 errmsg("invalid privilege type %s for column",
2068 								privilege_to_string(this_privileges))));
2069 
2070 			if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2071 				this_privileges & ~((AclMode) ACL_SELECT))
2072 			{
2073 				/*
2074 				 * The only column privilege allowed on sequences is SELECT.
2075 				 * This is a warning not error because we do it that way for
2076 				 * relation-level privileges.
2077 				 */
2078 				ereport(WARNING,
2079 						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
2080 						 errmsg("sequence \"%s\" only supports SELECT column privileges",
2081 								NameStr(pg_class_tuple->relname))));
2082 
2083 				this_privileges &= (AclMode) ACL_SELECT;
2084 			}
2085 
2086 			expand_col_privileges(col_privs->cols, relOid,
2087 								  this_privileges,
2088 								  col_privileges,
2089 								  num_col_privileges);
2090 			have_col_privileges = true;
2091 		}
2092 
2093 		if (have_col_privileges)
2094 		{
2095 			AttrNumber	i;
2096 
2097 			for (i = 0; i < num_col_privileges; i++)
2098 			{
2099 				if (col_privileges[i] == ACL_NO_RIGHTS)
2100 					continue;
2101 				ExecGrant_Attribute(istmt,
2102 									relOid,
2103 									NameStr(pg_class_tuple->relname),
2104 									i + FirstLowInvalidHeapAttributeNumber,
2105 									ownerId,
2106 									col_privileges[i],
2107 									attRelation,
2108 									old_rel_acl);
2109 			}
2110 		}
2111 
2112 		pfree(old_rel_acl);
2113 		pfree(col_privileges);
2114 
2115 		ReleaseSysCache(tuple);
2116 
2117 		/* prevent error when processing duplicate objects */
2118 		CommandCounterIncrement();
2119 	}
2120 
2121 	heap_close(attRelation, RowExclusiveLock);
2122 	heap_close(relation, RowExclusiveLock);
2123 }
2124 
2125 static void
ExecGrant_Database(InternalGrant * istmt)2126 ExecGrant_Database(InternalGrant *istmt)
2127 {
2128 	Relation	relation;
2129 	ListCell   *cell;
2130 
2131 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2132 		istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
2133 
2134 	relation = heap_open(DatabaseRelationId, RowExclusiveLock);
2135 
2136 	foreach(cell, istmt->objects)
2137 	{
2138 		Oid			datId = lfirst_oid(cell);
2139 		Form_pg_database pg_database_tuple;
2140 		Datum		aclDatum;
2141 		bool		isNull;
2142 		AclMode		avail_goptions;
2143 		AclMode		this_privileges;
2144 		Acl		   *old_acl;
2145 		Acl		   *new_acl;
2146 		Oid			grantorId;
2147 		Oid			ownerId;
2148 		HeapTuple	newtuple;
2149 		Datum		values[Natts_pg_database];
2150 		bool		nulls[Natts_pg_database];
2151 		bool		replaces[Natts_pg_database];
2152 		int			noldmembers;
2153 		int			nnewmembers;
2154 		Oid		   *oldmembers;
2155 		Oid		   *newmembers;
2156 		HeapTuple	tuple;
2157 
2158 		tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId));
2159 		if (!HeapTupleIsValid(tuple))
2160 			elog(ERROR, "cache lookup failed for database %u", datId);
2161 
2162 		pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
2163 
2164 		/*
2165 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
2166 		 * substitute the proper default.
2167 		 */
2168 		ownerId = pg_database_tuple->datdba;
2169 		aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
2170 								RelationGetDescr(relation), &isNull);
2171 		if (isNull)
2172 		{
2173 			old_acl = acldefault(OBJECT_DATABASE, ownerId);
2174 			/* There are no old member roles according to the catalogs */
2175 			noldmembers = 0;
2176 			oldmembers = NULL;
2177 		}
2178 		else
2179 		{
2180 			old_acl = DatumGetAclPCopy(aclDatum);
2181 			/* Get the roles mentioned in the existing ACL */
2182 			noldmembers = aclmembers(old_acl, &oldmembers);
2183 		}
2184 
2185 		/* Determine ID to do the grant as, and available grant options */
2186 		select_best_grantor(GetUserId(), istmt->privileges,
2187 							old_acl, ownerId,
2188 							&grantorId, &avail_goptions);
2189 
2190 		/*
2191 		 * Restrict the privileges to what we can actually grant, and emit the
2192 		 * standards-mandated warning and error messages.
2193 		 */
2194 		this_privileges =
2195 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
2196 									 istmt->all_privs, istmt->privileges,
2197 									 datId, grantorId, OBJECT_DATABASE,
2198 									 NameStr(pg_database_tuple->datname),
2199 									 0, NULL);
2200 
2201 		/*
2202 		 * Generate new ACL.
2203 		 */
2204 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2205 									   istmt->grant_option, istmt->behavior,
2206 									   istmt->grantees, this_privileges,
2207 									   grantorId, ownerId);
2208 
2209 		/*
2210 		 * We need the members of both old and new ACLs so we can correct the
2211 		 * shared dependency information.
2212 		 */
2213 		nnewmembers = aclmembers(new_acl, &newmembers);
2214 
2215 		/* finished building new ACL value, now insert it */
2216 		MemSet(values, 0, sizeof(values));
2217 		MemSet(nulls, false, sizeof(nulls));
2218 		MemSet(replaces, false, sizeof(replaces));
2219 
2220 		replaces[Anum_pg_database_datacl - 1] = true;
2221 		values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
2222 
2223 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2224 									 nulls, replaces);
2225 
2226 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2227 
2228 		/* Update the shared dependency ACL info */
2229 		updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), 0,
2230 							  ownerId,
2231 							  noldmembers, oldmembers,
2232 							  nnewmembers, newmembers);
2233 
2234 		ReleaseSysCache(tuple);
2235 
2236 		pfree(new_acl);
2237 
2238 		/* prevent error when processing duplicate objects */
2239 		CommandCounterIncrement();
2240 	}
2241 
2242 	heap_close(relation, RowExclusiveLock);
2243 }
2244 
2245 static void
ExecGrant_Fdw(InternalGrant * istmt)2246 ExecGrant_Fdw(InternalGrant *istmt)
2247 {
2248 	Relation	relation;
2249 	ListCell   *cell;
2250 
2251 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2252 		istmt->privileges = ACL_ALL_RIGHTS_FDW;
2253 
2254 	relation = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
2255 
2256 	foreach(cell, istmt->objects)
2257 	{
2258 		Oid			fdwid = lfirst_oid(cell);
2259 		Form_pg_foreign_data_wrapper pg_fdw_tuple;
2260 		Datum		aclDatum;
2261 		bool		isNull;
2262 		AclMode		avail_goptions;
2263 		AclMode		this_privileges;
2264 		Acl		   *old_acl;
2265 		Acl		   *new_acl;
2266 		Oid			grantorId;
2267 		Oid			ownerId;
2268 		HeapTuple	tuple;
2269 		HeapTuple	newtuple;
2270 		Datum		values[Natts_pg_foreign_data_wrapper];
2271 		bool		nulls[Natts_pg_foreign_data_wrapper];
2272 		bool		replaces[Natts_pg_foreign_data_wrapper];
2273 		int			noldmembers;
2274 		int			nnewmembers;
2275 		Oid		   *oldmembers;
2276 		Oid		   *newmembers;
2277 
2278 		tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
2279 								ObjectIdGetDatum(fdwid));
2280 		if (!HeapTupleIsValid(tuple))
2281 			elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
2282 
2283 		pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
2284 
2285 		/*
2286 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
2287 		 * substitute the proper default.
2288 		 */
2289 		ownerId = pg_fdw_tuple->fdwowner;
2290 		aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
2291 								   Anum_pg_foreign_data_wrapper_fdwacl,
2292 								   &isNull);
2293 		if (isNull)
2294 		{
2295 			old_acl = acldefault(OBJECT_FDW, ownerId);
2296 			/* There are no old member roles according to the catalogs */
2297 			noldmembers = 0;
2298 			oldmembers = NULL;
2299 		}
2300 		else
2301 		{
2302 			old_acl = DatumGetAclPCopy(aclDatum);
2303 			/* Get the roles mentioned in the existing ACL */
2304 			noldmembers = aclmembers(old_acl, &oldmembers);
2305 		}
2306 
2307 		/* Determine ID to do the grant as, and available grant options */
2308 		select_best_grantor(GetUserId(), istmt->privileges,
2309 							old_acl, ownerId,
2310 							&grantorId, &avail_goptions);
2311 
2312 		/*
2313 		 * Restrict the privileges to what we can actually grant, and emit the
2314 		 * standards-mandated warning and error messages.
2315 		 */
2316 		this_privileges =
2317 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
2318 									 istmt->all_privs, istmt->privileges,
2319 									 fdwid, grantorId, OBJECT_FDW,
2320 									 NameStr(pg_fdw_tuple->fdwname),
2321 									 0, NULL);
2322 
2323 		/*
2324 		 * Generate new ACL.
2325 		 */
2326 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2327 									   istmt->grant_option, istmt->behavior,
2328 									   istmt->grantees, this_privileges,
2329 									   grantorId, ownerId);
2330 
2331 		/*
2332 		 * We need the members of both old and new ACLs so we can correct the
2333 		 * shared dependency information.
2334 		 */
2335 		nnewmembers = aclmembers(new_acl, &newmembers);
2336 
2337 		/* finished building new ACL value, now insert it */
2338 		MemSet(values, 0, sizeof(values));
2339 		MemSet(nulls, false, sizeof(nulls));
2340 		MemSet(replaces, false, sizeof(replaces));
2341 
2342 		replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
2343 		values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl);
2344 
2345 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2346 									 nulls, replaces);
2347 
2348 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2349 
2350 		/* Update initial privileges for extensions */
2351 		recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
2352 								new_acl);
2353 
2354 		/* Update the shared dependency ACL info */
2355 		updateAclDependencies(ForeignDataWrapperRelationId,
2356 							  HeapTupleGetOid(tuple), 0,
2357 							  ownerId,
2358 							  noldmembers, oldmembers,
2359 							  nnewmembers, newmembers);
2360 
2361 		ReleaseSysCache(tuple);
2362 
2363 		pfree(new_acl);
2364 
2365 		/* prevent error when processing duplicate objects */
2366 		CommandCounterIncrement();
2367 	}
2368 
2369 	heap_close(relation, RowExclusiveLock);
2370 }
2371 
2372 static void
ExecGrant_ForeignServer(InternalGrant * istmt)2373 ExecGrant_ForeignServer(InternalGrant *istmt)
2374 {
2375 	Relation	relation;
2376 	ListCell   *cell;
2377 
2378 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2379 		istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
2380 
2381 	relation = heap_open(ForeignServerRelationId, RowExclusiveLock);
2382 
2383 	foreach(cell, istmt->objects)
2384 	{
2385 		Oid			srvid = lfirst_oid(cell);
2386 		Form_pg_foreign_server pg_server_tuple;
2387 		Datum		aclDatum;
2388 		bool		isNull;
2389 		AclMode		avail_goptions;
2390 		AclMode		this_privileges;
2391 		Acl		   *old_acl;
2392 		Acl		   *new_acl;
2393 		Oid			grantorId;
2394 		Oid			ownerId;
2395 		HeapTuple	tuple;
2396 		HeapTuple	newtuple;
2397 		Datum		values[Natts_pg_foreign_server];
2398 		bool		nulls[Natts_pg_foreign_server];
2399 		bool		replaces[Natts_pg_foreign_server];
2400 		int			noldmembers;
2401 		int			nnewmembers;
2402 		Oid		   *oldmembers;
2403 		Oid		   *newmembers;
2404 
2405 		tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid));
2406 		if (!HeapTupleIsValid(tuple))
2407 			elog(ERROR, "cache lookup failed for foreign server %u", srvid);
2408 
2409 		pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple);
2410 
2411 		/*
2412 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
2413 		 * substitute the proper default.
2414 		 */
2415 		ownerId = pg_server_tuple->srvowner;
2416 		aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
2417 								   Anum_pg_foreign_server_srvacl,
2418 								   &isNull);
2419 		if (isNull)
2420 		{
2421 			old_acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
2422 			/* There are no old member roles according to the catalogs */
2423 			noldmembers = 0;
2424 			oldmembers = NULL;
2425 		}
2426 		else
2427 		{
2428 			old_acl = DatumGetAclPCopy(aclDatum);
2429 			/* Get the roles mentioned in the existing ACL */
2430 			noldmembers = aclmembers(old_acl, &oldmembers);
2431 		}
2432 
2433 		/* Determine ID to do the grant as, and available grant options */
2434 		select_best_grantor(GetUserId(), istmt->privileges,
2435 							old_acl, ownerId,
2436 							&grantorId, &avail_goptions);
2437 
2438 		/*
2439 		 * Restrict the privileges to what we can actually grant, and emit the
2440 		 * standards-mandated warning and error messages.
2441 		 */
2442 		this_privileges =
2443 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
2444 									 istmt->all_privs, istmt->privileges,
2445 									 srvid, grantorId, OBJECT_FOREIGN_SERVER,
2446 									 NameStr(pg_server_tuple->srvname),
2447 									 0, NULL);
2448 
2449 		/*
2450 		 * Generate new ACL.
2451 		 */
2452 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2453 									   istmt->grant_option, istmt->behavior,
2454 									   istmt->grantees, this_privileges,
2455 									   grantorId, ownerId);
2456 
2457 		/*
2458 		 * We need the members of both old and new ACLs so we can correct the
2459 		 * shared dependency information.
2460 		 */
2461 		nnewmembers = aclmembers(new_acl, &newmembers);
2462 
2463 		/* finished building new ACL value, now insert it */
2464 		MemSet(values, 0, sizeof(values));
2465 		MemSet(nulls, false, sizeof(nulls));
2466 		MemSet(replaces, false, sizeof(replaces));
2467 
2468 		replaces[Anum_pg_foreign_server_srvacl - 1] = true;
2469 		values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl);
2470 
2471 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2472 									 nulls, replaces);
2473 
2474 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2475 
2476 		/* Update initial privileges for extensions */
2477 		recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
2478 
2479 		/* Update the shared dependency ACL info */
2480 		updateAclDependencies(ForeignServerRelationId,
2481 							  HeapTupleGetOid(tuple), 0,
2482 							  ownerId,
2483 							  noldmembers, oldmembers,
2484 							  nnewmembers, newmembers);
2485 
2486 		ReleaseSysCache(tuple);
2487 
2488 		pfree(new_acl);
2489 
2490 		/* prevent error when processing duplicate objects */
2491 		CommandCounterIncrement();
2492 	}
2493 
2494 	heap_close(relation, RowExclusiveLock);
2495 }
2496 
2497 static void
ExecGrant_Function(InternalGrant * istmt)2498 ExecGrant_Function(InternalGrant *istmt)
2499 {
2500 	Relation	relation;
2501 	ListCell   *cell;
2502 
2503 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2504 		istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
2505 
2506 	relation = heap_open(ProcedureRelationId, RowExclusiveLock);
2507 
2508 	foreach(cell, istmt->objects)
2509 	{
2510 		Oid			funcId = lfirst_oid(cell);
2511 		Form_pg_proc pg_proc_tuple;
2512 		Datum		aclDatum;
2513 		bool		isNull;
2514 		AclMode		avail_goptions;
2515 		AclMode		this_privileges;
2516 		Acl		   *old_acl;
2517 		Acl		   *new_acl;
2518 		Oid			grantorId;
2519 		Oid			ownerId;
2520 		HeapTuple	tuple;
2521 		HeapTuple	newtuple;
2522 		Datum		values[Natts_pg_proc];
2523 		bool		nulls[Natts_pg_proc];
2524 		bool		replaces[Natts_pg_proc];
2525 		int			noldmembers;
2526 		int			nnewmembers;
2527 		Oid		   *oldmembers;
2528 		Oid		   *newmembers;
2529 
2530 		tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId));
2531 		if (!HeapTupleIsValid(tuple))
2532 			elog(ERROR, "cache lookup failed for function %u", funcId);
2533 
2534 		pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
2535 
2536 		/*
2537 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
2538 		 * substitute the proper default.
2539 		 */
2540 		ownerId = pg_proc_tuple->proowner;
2541 		aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
2542 								   &isNull);
2543 		if (isNull)
2544 		{
2545 			old_acl = acldefault(OBJECT_FUNCTION, ownerId);
2546 			/* There are no old member roles according to the catalogs */
2547 			noldmembers = 0;
2548 			oldmembers = NULL;
2549 		}
2550 		else
2551 		{
2552 			old_acl = DatumGetAclPCopy(aclDatum);
2553 			/* Get the roles mentioned in the existing ACL */
2554 			noldmembers = aclmembers(old_acl, &oldmembers);
2555 		}
2556 
2557 		/* Determine ID to do the grant as, and available grant options */
2558 		select_best_grantor(GetUserId(), istmt->privileges,
2559 							old_acl, ownerId,
2560 							&grantorId, &avail_goptions);
2561 
2562 		/*
2563 		 * Restrict the privileges to what we can actually grant, and emit the
2564 		 * standards-mandated warning and error messages.
2565 		 */
2566 		this_privileges =
2567 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
2568 									 istmt->all_privs, istmt->privileges,
2569 									 funcId, grantorId, OBJECT_FUNCTION,
2570 									 NameStr(pg_proc_tuple->proname),
2571 									 0, NULL);
2572 
2573 		/*
2574 		 * Generate new ACL.
2575 		 */
2576 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2577 									   istmt->grant_option, istmt->behavior,
2578 									   istmt->grantees, this_privileges,
2579 									   grantorId, ownerId);
2580 
2581 		/*
2582 		 * We need the members of both old and new ACLs so we can correct the
2583 		 * shared dependency information.
2584 		 */
2585 		nnewmembers = aclmembers(new_acl, &newmembers);
2586 
2587 		/* finished building new ACL value, now insert it */
2588 		MemSet(values, 0, sizeof(values));
2589 		MemSet(nulls, false, sizeof(nulls));
2590 		MemSet(replaces, false, sizeof(replaces));
2591 
2592 		replaces[Anum_pg_proc_proacl - 1] = true;
2593 		values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
2594 
2595 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2596 									 nulls, replaces);
2597 
2598 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2599 
2600 		/* Update initial privileges for extensions */
2601 		recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
2602 
2603 		/* Update the shared dependency ACL info */
2604 		updateAclDependencies(ProcedureRelationId, funcId, 0,
2605 							  ownerId,
2606 							  noldmembers, oldmembers,
2607 							  nnewmembers, newmembers);
2608 
2609 		ReleaseSysCache(tuple);
2610 
2611 		pfree(new_acl);
2612 
2613 		/* prevent error when processing duplicate objects */
2614 		CommandCounterIncrement();
2615 	}
2616 
2617 	heap_close(relation, RowExclusiveLock);
2618 }
2619 
2620 static void
ExecGrant_Language(InternalGrant * istmt)2621 ExecGrant_Language(InternalGrant *istmt)
2622 {
2623 	Relation	relation;
2624 	ListCell   *cell;
2625 
2626 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2627 		istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
2628 
2629 	relation = heap_open(LanguageRelationId, RowExclusiveLock);
2630 
2631 	foreach(cell, istmt->objects)
2632 	{
2633 		Oid			langId = lfirst_oid(cell);
2634 		Form_pg_language pg_language_tuple;
2635 		Datum		aclDatum;
2636 		bool		isNull;
2637 		AclMode		avail_goptions;
2638 		AclMode		this_privileges;
2639 		Acl		   *old_acl;
2640 		Acl		   *new_acl;
2641 		Oid			grantorId;
2642 		Oid			ownerId;
2643 		HeapTuple	tuple;
2644 		HeapTuple	newtuple;
2645 		Datum		values[Natts_pg_language];
2646 		bool		nulls[Natts_pg_language];
2647 		bool		replaces[Natts_pg_language];
2648 		int			noldmembers;
2649 		int			nnewmembers;
2650 		Oid		   *oldmembers;
2651 		Oid		   *newmembers;
2652 
2653 		tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(langId));
2654 		if (!HeapTupleIsValid(tuple))
2655 			elog(ERROR, "cache lookup failed for language %u", langId);
2656 
2657 		pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2658 
2659 		if (!pg_language_tuple->lanpltrusted)
2660 			ereport(ERROR,
2661 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2662 					 errmsg("language \"%s\" is not trusted",
2663 							NameStr(pg_language_tuple->lanname)),
2664 					 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2665 							   "because only superusers can use untrusted languages.")));
2666 
2667 		/*
2668 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
2669 		 * substitute the proper default.
2670 		 */
2671 		ownerId = pg_language_tuple->lanowner;
2672 		aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
2673 								   &isNull);
2674 		if (isNull)
2675 		{
2676 			old_acl = acldefault(OBJECT_LANGUAGE, ownerId);
2677 			/* There are no old member roles according to the catalogs */
2678 			noldmembers = 0;
2679 			oldmembers = NULL;
2680 		}
2681 		else
2682 		{
2683 			old_acl = DatumGetAclPCopy(aclDatum);
2684 			/* Get the roles mentioned in the existing ACL */
2685 			noldmembers = aclmembers(old_acl, &oldmembers);
2686 		}
2687 
2688 		/* Determine ID to do the grant as, and available grant options */
2689 		select_best_grantor(GetUserId(), istmt->privileges,
2690 							old_acl, ownerId,
2691 							&grantorId, &avail_goptions);
2692 
2693 		/*
2694 		 * Restrict the privileges to what we can actually grant, and emit the
2695 		 * standards-mandated warning and error messages.
2696 		 */
2697 		this_privileges =
2698 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
2699 									 istmt->all_privs, istmt->privileges,
2700 									 langId, grantorId, OBJECT_LANGUAGE,
2701 									 NameStr(pg_language_tuple->lanname),
2702 									 0, NULL);
2703 
2704 		/*
2705 		 * Generate new ACL.
2706 		 */
2707 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2708 									   istmt->grant_option, istmt->behavior,
2709 									   istmt->grantees, this_privileges,
2710 									   grantorId, ownerId);
2711 
2712 		/*
2713 		 * We need the members of both old and new ACLs so we can correct the
2714 		 * shared dependency information.
2715 		 */
2716 		nnewmembers = aclmembers(new_acl, &newmembers);
2717 
2718 		/* finished building new ACL value, now insert it */
2719 		MemSet(values, 0, sizeof(values));
2720 		MemSet(nulls, false, sizeof(nulls));
2721 		MemSet(replaces, false, sizeof(replaces));
2722 
2723 		replaces[Anum_pg_language_lanacl - 1] = true;
2724 		values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
2725 
2726 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2727 									 nulls, replaces);
2728 
2729 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2730 
2731 		/* Update initial privileges for extensions */
2732 		recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
2733 
2734 		/* Update the shared dependency ACL info */
2735 		updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
2736 							  ownerId,
2737 							  noldmembers, oldmembers,
2738 							  nnewmembers, newmembers);
2739 
2740 		ReleaseSysCache(tuple);
2741 
2742 		pfree(new_acl);
2743 
2744 		/* prevent error when processing duplicate objects */
2745 		CommandCounterIncrement();
2746 	}
2747 
2748 	heap_close(relation, RowExclusiveLock);
2749 }
2750 
2751 static void
ExecGrant_Largeobject(InternalGrant * istmt)2752 ExecGrant_Largeobject(InternalGrant *istmt)
2753 {
2754 	Relation	relation;
2755 	ListCell   *cell;
2756 
2757 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2758 		istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
2759 
2760 	relation = heap_open(LargeObjectMetadataRelationId,
2761 						 RowExclusiveLock);
2762 
2763 	foreach(cell, istmt->objects)
2764 	{
2765 		Oid			loid = lfirst_oid(cell);
2766 		Form_pg_largeobject_metadata form_lo_meta;
2767 		char		loname[NAMEDATALEN];
2768 		Datum		aclDatum;
2769 		bool		isNull;
2770 		AclMode		avail_goptions;
2771 		AclMode		this_privileges;
2772 		Acl		   *old_acl;
2773 		Acl		   *new_acl;
2774 		Oid			grantorId;
2775 		Oid			ownerId;
2776 		HeapTuple	newtuple;
2777 		Datum		values[Natts_pg_largeobject_metadata];
2778 		bool		nulls[Natts_pg_largeobject_metadata];
2779 		bool		replaces[Natts_pg_largeobject_metadata];
2780 		int			noldmembers;
2781 		int			nnewmembers;
2782 		Oid		   *oldmembers;
2783 		Oid		   *newmembers;
2784 		ScanKeyData entry[1];
2785 		SysScanDesc scan;
2786 		HeapTuple	tuple;
2787 
2788 		/* There's no syscache for pg_largeobject_metadata */
2789 		ScanKeyInit(&entry[0],
2790 					ObjectIdAttributeNumber,
2791 					BTEqualStrategyNumber, F_OIDEQ,
2792 					ObjectIdGetDatum(loid));
2793 
2794 		scan = systable_beginscan(relation,
2795 								  LargeObjectMetadataOidIndexId, true,
2796 								  NULL, 1, entry);
2797 
2798 		tuple = systable_getnext(scan);
2799 		if (!HeapTupleIsValid(tuple))
2800 			elog(ERROR, "could not find tuple for large object %u", loid);
2801 
2802 		form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2803 
2804 		/*
2805 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
2806 		 * substitute the proper default.
2807 		 */
2808 		ownerId = form_lo_meta->lomowner;
2809 		aclDatum = heap_getattr(tuple,
2810 								Anum_pg_largeobject_metadata_lomacl,
2811 								RelationGetDescr(relation), &isNull);
2812 		if (isNull)
2813 		{
2814 			old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2815 			/* There are no old member roles according to the catalogs */
2816 			noldmembers = 0;
2817 			oldmembers = NULL;
2818 		}
2819 		else
2820 		{
2821 			old_acl = DatumGetAclPCopy(aclDatum);
2822 			/* Get the roles mentioned in the existing ACL */
2823 			noldmembers = aclmembers(old_acl, &oldmembers);
2824 		}
2825 
2826 		/* Determine ID to do the grant as, and available grant options */
2827 		select_best_grantor(GetUserId(), istmt->privileges,
2828 							old_acl, ownerId,
2829 							&grantorId, &avail_goptions);
2830 
2831 		/*
2832 		 * Restrict the privileges to what we can actually grant, and emit the
2833 		 * standards-mandated warning and error messages.
2834 		 */
2835 		snprintf(loname, sizeof(loname), "large object %u", loid);
2836 		this_privileges =
2837 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
2838 									 istmt->all_privs, istmt->privileges,
2839 									 loid, grantorId, OBJECT_LARGEOBJECT,
2840 									 loname, 0, NULL);
2841 
2842 		/*
2843 		 * Generate new ACL.
2844 		 */
2845 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2846 									   istmt->grant_option, istmt->behavior,
2847 									   istmt->grantees, this_privileges,
2848 									   grantorId, ownerId);
2849 
2850 		/*
2851 		 * We need the members of both old and new ACLs so we can correct the
2852 		 * shared dependency information.
2853 		 */
2854 		nnewmembers = aclmembers(new_acl, &newmembers);
2855 
2856 		/* finished building new ACL value, now insert it */
2857 		MemSet(values, 0, sizeof(values));
2858 		MemSet(nulls, false, sizeof(nulls));
2859 		MemSet(replaces, false, sizeof(replaces));
2860 
2861 		replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2862 		values[Anum_pg_largeobject_metadata_lomacl - 1]
2863 			= PointerGetDatum(new_acl);
2864 
2865 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2866 									 values, nulls, replaces);
2867 
2868 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2869 
2870 		/* Update initial privileges for extensions */
2871 		recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2872 
2873 		/* Update the shared dependency ACL info */
2874 		updateAclDependencies(LargeObjectRelationId,
2875 							  HeapTupleGetOid(tuple), 0,
2876 							  ownerId,
2877 							  noldmembers, oldmembers,
2878 							  nnewmembers, newmembers);
2879 
2880 		systable_endscan(scan);
2881 
2882 		pfree(new_acl);
2883 
2884 		/* prevent error when processing duplicate objects */
2885 		CommandCounterIncrement();
2886 	}
2887 
2888 	heap_close(relation, RowExclusiveLock);
2889 }
2890 
2891 static void
ExecGrant_Namespace(InternalGrant * istmt)2892 ExecGrant_Namespace(InternalGrant *istmt)
2893 {
2894 	Relation	relation;
2895 	ListCell   *cell;
2896 
2897 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2898 		istmt->privileges = ACL_ALL_RIGHTS_SCHEMA;
2899 
2900 	relation = heap_open(NamespaceRelationId, RowExclusiveLock);
2901 
2902 	foreach(cell, istmt->objects)
2903 	{
2904 		Oid			nspid = lfirst_oid(cell);
2905 		Form_pg_namespace pg_namespace_tuple;
2906 		Datum		aclDatum;
2907 		bool		isNull;
2908 		AclMode		avail_goptions;
2909 		AclMode		this_privileges;
2910 		Acl		   *old_acl;
2911 		Acl		   *new_acl;
2912 		Oid			grantorId;
2913 		Oid			ownerId;
2914 		HeapTuple	tuple;
2915 		HeapTuple	newtuple;
2916 		Datum		values[Natts_pg_namespace];
2917 		bool		nulls[Natts_pg_namespace];
2918 		bool		replaces[Natts_pg_namespace];
2919 		int			noldmembers;
2920 		int			nnewmembers;
2921 		Oid		   *oldmembers;
2922 		Oid		   *newmembers;
2923 
2924 		tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
2925 		if (!HeapTupleIsValid(tuple))
2926 			elog(ERROR, "cache lookup failed for namespace %u", nspid);
2927 
2928 		pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
2929 
2930 		/*
2931 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
2932 		 * substitute the proper default.
2933 		 */
2934 		ownerId = pg_namespace_tuple->nspowner;
2935 		aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
2936 								   Anum_pg_namespace_nspacl,
2937 								   &isNull);
2938 		if (isNull)
2939 		{
2940 			old_acl = acldefault(OBJECT_SCHEMA, ownerId);
2941 			/* There are no old member roles according to the catalogs */
2942 			noldmembers = 0;
2943 			oldmembers = NULL;
2944 		}
2945 		else
2946 		{
2947 			old_acl = DatumGetAclPCopy(aclDatum);
2948 			/* Get the roles mentioned in the existing ACL */
2949 			noldmembers = aclmembers(old_acl, &oldmembers);
2950 		}
2951 
2952 		/* Determine ID to do the grant as, and available grant options */
2953 		select_best_grantor(GetUserId(), istmt->privileges,
2954 							old_acl, ownerId,
2955 							&grantorId, &avail_goptions);
2956 
2957 		/*
2958 		 * Restrict the privileges to what we can actually grant, and emit the
2959 		 * standards-mandated warning and error messages.
2960 		 */
2961 		this_privileges =
2962 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
2963 									 istmt->all_privs, istmt->privileges,
2964 									 nspid, grantorId, OBJECT_SCHEMA,
2965 									 NameStr(pg_namespace_tuple->nspname),
2966 									 0, NULL);
2967 
2968 		/*
2969 		 * Generate new ACL.
2970 		 */
2971 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2972 									   istmt->grant_option, istmt->behavior,
2973 									   istmt->grantees, this_privileges,
2974 									   grantorId, ownerId);
2975 
2976 		/*
2977 		 * We need the members of both old and new ACLs so we can correct the
2978 		 * shared dependency information.
2979 		 */
2980 		nnewmembers = aclmembers(new_acl, &newmembers);
2981 
2982 		/* finished building new ACL value, now insert it */
2983 		MemSet(values, 0, sizeof(values));
2984 		MemSet(nulls, false, sizeof(nulls));
2985 		MemSet(replaces, false, sizeof(replaces));
2986 
2987 		replaces[Anum_pg_namespace_nspacl - 1] = true;
2988 		values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
2989 
2990 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2991 									 nulls, replaces);
2992 
2993 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2994 
2995 		/* Update initial privileges for extensions */
2996 		recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
2997 
2998 		/* Update the shared dependency ACL info */
2999 		updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
3000 							  ownerId,
3001 							  noldmembers, oldmembers,
3002 							  nnewmembers, newmembers);
3003 
3004 		ReleaseSysCache(tuple);
3005 
3006 		pfree(new_acl);
3007 
3008 		/* prevent error when processing duplicate objects */
3009 		CommandCounterIncrement();
3010 	}
3011 
3012 	heap_close(relation, RowExclusiveLock);
3013 }
3014 
3015 static void
ExecGrant_Tablespace(InternalGrant * istmt)3016 ExecGrant_Tablespace(InternalGrant *istmt)
3017 {
3018 	Relation	relation;
3019 	ListCell   *cell;
3020 
3021 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
3022 		istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
3023 
3024 	relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
3025 
3026 	foreach(cell, istmt->objects)
3027 	{
3028 		Oid			tblId = lfirst_oid(cell);
3029 		Form_pg_tablespace pg_tablespace_tuple;
3030 		Datum		aclDatum;
3031 		bool		isNull;
3032 		AclMode		avail_goptions;
3033 		AclMode		this_privileges;
3034 		Acl		   *old_acl;
3035 		Acl		   *new_acl;
3036 		Oid			grantorId;
3037 		Oid			ownerId;
3038 		HeapTuple	newtuple;
3039 		Datum		values[Natts_pg_tablespace];
3040 		bool		nulls[Natts_pg_tablespace];
3041 		bool		replaces[Natts_pg_tablespace];
3042 		int			noldmembers;
3043 		int			nnewmembers;
3044 		Oid		   *oldmembers;
3045 		Oid		   *newmembers;
3046 		HeapTuple	tuple;
3047 
3048 		/* Search syscache for pg_tablespace */
3049 		tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId));
3050 		if (!HeapTupleIsValid(tuple))
3051 			elog(ERROR, "cache lookup failed for tablespace %u", tblId);
3052 
3053 		pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
3054 
3055 		/*
3056 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
3057 		 * substitute the proper default.
3058 		 */
3059 		ownerId = pg_tablespace_tuple->spcowner;
3060 		aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
3061 								RelationGetDescr(relation), &isNull);
3062 		if (isNull)
3063 		{
3064 			old_acl = acldefault(OBJECT_TABLESPACE, ownerId);
3065 			/* There are no old member roles according to the catalogs */
3066 			noldmembers = 0;
3067 			oldmembers = NULL;
3068 		}
3069 		else
3070 		{
3071 			old_acl = DatumGetAclPCopy(aclDatum);
3072 			/* Get the roles mentioned in the existing ACL */
3073 			noldmembers = aclmembers(old_acl, &oldmembers);
3074 		}
3075 
3076 		/* Determine ID to do the grant as, and available grant options */
3077 		select_best_grantor(GetUserId(), istmt->privileges,
3078 							old_acl, ownerId,
3079 							&grantorId, &avail_goptions);
3080 
3081 		/*
3082 		 * Restrict the privileges to what we can actually grant, and emit the
3083 		 * standards-mandated warning and error messages.
3084 		 */
3085 		this_privileges =
3086 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
3087 									 istmt->all_privs, istmt->privileges,
3088 									 tblId, grantorId, OBJECT_TABLESPACE,
3089 									 NameStr(pg_tablespace_tuple->spcname),
3090 									 0, NULL);
3091 
3092 		/*
3093 		 * Generate new ACL.
3094 		 */
3095 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
3096 									   istmt->grant_option, istmt->behavior,
3097 									   istmt->grantees, this_privileges,
3098 									   grantorId, ownerId);
3099 
3100 		/*
3101 		 * We need the members of both old and new ACLs so we can correct the
3102 		 * shared dependency information.
3103 		 */
3104 		nnewmembers = aclmembers(new_acl, &newmembers);
3105 
3106 		/* finished building new ACL value, now insert it */
3107 		MemSet(values, 0, sizeof(values));
3108 		MemSet(nulls, false, sizeof(nulls));
3109 		MemSet(replaces, false, sizeof(replaces));
3110 
3111 		replaces[Anum_pg_tablespace_spcacl - 1] = true;
3112 		values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
3113 
3114 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
3115 									 nulls, replaces);
3116 
3117 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
3118 
3119 		/* Update the shared dependency ACL info */
3120 		updateAclDependencies(TableSpaceRelationId, tblId, 0,
3121 							  ownerId,
3122 							  noldmembers, oldmembers,
3123 							  nnewmembers, newmembers);
3124 
3125 		ReleaseSysCache(tuple);
3126 		pfree(new_acl);
3127 
3128 		/* prevent error when processing duplicate objects */
3129 		CommandCounterIncrement();
3130 	}
3131 
3132 	heap_close(relation, RowExclusiveLock);
3133 }
3134 
3135 static void
ExecGrant_Type(InternalGrant * istmt)3136 ExecGrant_Type(InternalGrant *istmt)
3137 {
3138 	Relation	relation;
3139 	ListCell   *cell;
3140 
3141 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
3142 		istmt->privileges = ACL_ALL_RIGHTS_TYPE;
3143 
3144 	relation = heap_open(TypeRelationId, RowExclusiveLock);
3145 
3146 	foreach(cell, istmt->objects)
3147 	{
3148 		Oid			typId = lfirst_oid(cell);
3149 		Form_pg_type pg_type_tuple;
3150 		Datum		aclDatum;
3151 		bool		isNull;
3152 		AclMode		avail_goptions;
3153 		AclMode		this_privileges;
3154 		Acl		   *old_acl;
3155 		Acl		   *new_acl;
3156 		Oid			grantorId;
3157 		Oid			ownerId;
3158 		HeapTuple	newtuple;
3159 		Datum		values[Natts_pg_type];
3160 		bool		nulls[Natts_pg_type];
3161 		bool		replaces[Natts_pg_type];
3162 		int			noldmembers;
3163 		int			nnewmembers;
3164 		Oid		   *oldmembers;
3165 		Oid		   *newmembers;
3166 		HeapTuple	tuple;
3167 
3168 		/* Search syscache for pg_type */
3169 		tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typId));
3170 		if (!HeapTupleIsValid(tuple))
3171 			elog(ERROR, "cache lookup failed for type %u", typId);
3172 
3173 		pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
3174 
3175 		if (pg_type_tuple->typelem != 0 && pg_type_tuple->typlen == -1)
3176 			ereport(ERROR,
3177 					(errcode(ERRCODE_INVALID_GRANT_OPERATION),
3178 					 errmsg("cannot set privileges of array types"),
3179 					 errhint("Set the privileges of the element type instead.")));
3180 
3181 		/* Used GRANT DOMAIN on a non-domain? */
3182 		if (istmt->objtype == OBJECT_DOMAIN &&
3183 			pg_type_tuple->typtype != TYPTYPE_DOMAIN)
3184 			ereport(ERROR,
3185 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3186 					 errmsg("\"%s\" is not a domain",
3187 							NameStr(pg_type_tuple->typname))));
3188 
3189 		/*
3190 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
3191 		 * substitute the proper default.
3192 		 */
3193 		ownerId = pg_type_tuple->typowner;
3194 		aclDatum = heap_getattr(tuple, Anum_pg_type_typacl,
3195 								RelationGetDescr(relation), &isNull);
3196 		if (isNull)
3197 		{
3198 			old_acl = acldefault(istmt->objtype, ownerId);
3199 			/* There are no old member roles according to the catalogs */
3200 			noldmembers = 0;
3201 			oldmembers = NULL;
3202 		}
3203 		else
3204 		{
3205 			old_acl = DatumGetAclPCopy(aclDatum);
3206 			/* Get the roles mentioned in the existing ACL */
3207 			noldmembers = aclmembers(old_acl, &oldmembers);
3208 		}
3209 
3210 		/* Determine ID to do the grant as, and available grant options */
3211 		select_best_grantor(GetUserId(), istmt->privileges,
3212 							old_acl, ownerId,
3213 							&grantorId, &avail_goptions);
3214 
3215 		/*
3216 		 * Restrict the privileges to what we can actually grant, and emit the
3217 		 * standards-mandated warning and error messages.
3218 		 */
3219 		this_privileges =
3220 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
3221 									 istmt->all_privs, istmt->privileges,
3222 									 typId, grantorId, OBJECT_TYPE,
3223 									 NameStr(pg_type_tuple->typname),
3224 									 0, NULL);
3225 
3226 		/*
3227 		 * Generate new ACL.
3228 		 */
3229 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
3230 									   istmt->grant_option, istmt->behavior,
3231 									   istmt->grantees, this_privileges,
3232 									   grantorId, ownerId);
3233 
3234 		/*
3235 		 * We need the members of both old and new ACLs so we can correct the
3236 		 * shared dependency information.
3237 		 */
3238 		nnewmembers = aclmembers(new_acl, &newmembers);
3239 
3240 		/* finished building new ACL value, now insert it */
3241 		MemSet(values, 0, sizeof(values));
3242 		MemSet(nulls, false, sizeof(nulls));
3243 		MemSet(replaces, false, sizeof(replaces));
3244 
3245 		replaces[Anum_pg_type_typacl - 1] = true;
3246 		values[Anum_pg_type_typacl - 1] = PointerGetDatum(new_acl);
3247 
3248 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
3249 									 nulls, replaces);
3250 
3251 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
3252 
3253 		/* Update initial privileges for extensions */
3254 		recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
3255 
3256 		/* Update the shared dependency ACL info */
3257 		updateAclDependencies(TypeRelationId, typId, 0,
3258 							  ownerId,
3259 							  noldmembers, oldmembers,
3260 							  nnewmembers, newmembers);
3261 
3262 		ReleaseSysCache(tuple);
3263 		pfree(new_acl);
3264 
3265 		/* prevent error when processing duplicate objects */
3266 		CommandCounterIncrement();
3267 	}
3268 
3269 	heap_close(relation, RowExclusiveLock);
3270 }
3271 
3272 
3273 static AclMode
string_to_privilege(const char * privname)3274 string_to_privilege(const char *privname)
3275 {
3276 	if (strcmp(privname, "insert") == 0)
3277 		return ACL_INSERT;
3278 	if (strcmp(privname, "select") == 0)
3279 		return ACL_SELECT;
3280 	if (strcmp(privname, "update") == 0)
3281 		return ACL_UPDATE;
3282 	if (strcmp(privname, "delete") == 0)
3283 		return ACL_DELETE;
3284 	if (strcmp(privname, "truncate") == 0)
3285 		return ACL_TRUNCATE;
3286 	if (strcmp(privname, "references") == 0)
3287 		return ACL_REFERENCES;
3288 	if (strcmp(privname, "trigger") == 0)
3289 		return ACL_TRIGGER;
3290 	if (strcmp(privname, "execute") == 0)
3291 		return ACL_EXECUTE;
3292 	if (strcmp(privname, "usage") == 0)
3293 		return ACL_USAGE;
3294 	if (strcmp(privname, "create") == 0)
3295 		return ACL_CREATE;
3296 	if (strcmp(privname, "temporary") == 0)
3297 		return ACL_CREATE_TEMP;
3298 	if (strcmp(privname, "temp") == 0)
3299 		return ACL_CREATE_TEMP;
3300 	if (strcmp(privname, "connect") == 0)
3301 		return ACL_CONNECT;
3302 	if (strcmp(privname, "rule") == 0)
3303 		return 0;				/* ignore old RULE privileges */
3304 	ereport(ERROR,
3305 			(errcode(ERRCODE_SYNTAX_ERROR),
3306 			 errmsg("unrecognized privilege type \"%s\"", privname)));
3307 	return 0;					/* appease compiler */
3308 }
3309 
3310 static const char *
privilege_to_string(AclMode privilege)3311 privilege_to_string(AclMode privilege)
3312 {
3313 	switch (privilege)
3314 	{
3315 		case ACL_INSERT:
3316 			return "INSERT";
3317 		case ACL_SELECT:
3318 			return "SELECT";
3319 		case ACL_UPDATE:
3320 			return "UPDATE";
3321 		case ACL_DELETE:
3322 			return "DELETE";
3323 		case ACL_TRUNCATE:
3324 			return "TRUNCATE";
3325 		case ACL_REFERENCES:
3326 			return "REFERENCES";
3327 		case ACL_TRIGGER:
3328 			return "TRIGGER";
3329 		case ACL_EXECUTE:
3330 			return "EXECUTE";
3331 		case ACL_USAGE:
3332 			return "USAGE";
3333 		case ACL_CREATE:
3334 			return "CREATE";
3335 		case ACL_CREATE_TEMP:
3336 			return "TEMP";
3337 		case ACL_CONNECT:
3338 			return "CONNECT";
3339 		default:
3340 			elog(ERROR, "unrecognized privilege: %d", (int) privilege);
3341 	}
3342 	return NULL;				/* appease compiler */
3343 }
3344 
3345 /*
3346  * Standardized reporting of aclcheck permissions failures.
3347  *
3348  * Note: we do not double-quote the %s's below, because many callers
3349  * supply strings that might be already quoted.
3350  */
3351 void
aclcheck_error(AclResult aclerr,ObjectType objtype,const char * objectname)3352 aclcheck_error(AclResult aclerr, ObjectType objtype,
3353 			   const char *objectname)
3354 {
3355 	switch (aclerr)
3356 	{
3357 		case ACLCHECK_OK:
3358 			/* no error, so return to caller */
3359 			break;
3360 		case ACLCHECK_NO_PRIV:
3361 			{
3362 				const char *msg = "???";
3363 
3364 				switch (objtype)
3365 				{
3366 					case OBJECT_AGGREGATE:
3367 						msg = gettext_noop("permission denied for aggregate %s");
3368 						break;
3369 					case OBJECT_COLLATION:
3370 						msg = gettext_noop("permission denied for collation %s");
3371 						break;
3372 					case OBJECT_COLUMN:
3373 						msg = gettext_noop("permission denied for column %s");
3374 						break;
3375 					case OBJECT_CONVERSION:
3376 						msg = gettext_noop("permission denied for conversion %s");
3377 						break;
3378 					case OBJECT_DATABASE:
3379 						msg = gettext_noop("permission denied for database %s");
3380 						break;
3381 					case OBJECT_DOMAIN:
3382 						msg = gettext_noop("permission denied for domain %s");
3383 						break;
3384 					case OBJECT_EVENT_TRIGGER:
3385 						msg = gettext_noop("permission denied for event trigger %s");
3386 						break;
3387 					case OBJECT_EXTENSION:
3388 						msg = gettext_noop("permission denied for extension %s");
3389 						break;
3390 					case OBJECT_FDW:
3391 						msg = gettext_noop("permission denied for foreign-data wrapper %s");
3392 						break;
3393 					case OBJECT_FOREIGN_SERVER:
3394 						msg = gettext_noop("permission denied for foreign server %s");
3395 						break;
3396 					case OBJECT_FOREIGN_TABLE:
3397 						msg = gettext_noop("permission denied for foreign table %s");
3398 						break;
3399 					case OBJECT_FUNCTION:
3400 						msg = gettext_noop("permission denied for function %s");
3401 						break;
3402 					case OBJECT_INDEX:
3403 						msg = gettext_noop("permission denied for index %s");
3404 						break;
3405 					case OBJECT_LANGUAGE:
3406 						msg = gettext_noop("permission denied for language %s");
3407 						break;
3408 					case OBJECT_LARGEOBJECT:
3409 						msg = gettext_noop("permission denied for large object %s");
3410 						break;
3411 					case OBJECT_MATVIEW:
3412 						msg = gettext_noop("permission denied for materialized view %s");
3413 						break;
3414 					case OBJECT_OPCLASS:
3415 						msg = gettext_noop("permission denied for operator class %s");
3416 						break;
3417 					case OBJECT_OPERATOR:
3418 						msg = gettext_noop("permission denied for operator %s");
3419 						break;
3420 					case OBJECT_OPFAMILY:
3421 						msg = gettext_noop("permission denied for operator family %s");
3422 						break;
3423 					case OBJECT_POLICY:
3424 						msg = gettext_noop("permission denied for policy %s");
3425 						break;
3426 					case OBJECT_PROCEDURE:
3427 						msg = gettext_noop("permission denied for procedure %s");
3428 						break;
3429 					case OBJECT_PUBLICATION:
3430 						msg = gettext_noop("permission denied for publication %s");
3431 						break;
3432 					case OBJECT_ROUTINE:
3433 						msg = gettext_noop("permission denied for routine %s");
3434 						break;
3435 					case OBJECT_SCHEMA:
3436 						msg = gettext_noop("permission denied for schema %s");
3437 						break;
3438 					case OBJECT_SEQUENCE:
3439 						msg = gettext_noop("permission denied for sequence %s");
3440 						break;
3441 					case OBJECT_STATISTIC_EXT:
3442 						msg = gettext_noop("permission denied for statistics object %s");
3443 						break;
3444 					case OBJECT_SUBSCRIPTION:
3445 						msg = gettext_noop("permission denied for subscription %s");
3446 						break;
3447 					case OBJECT_TABLE:
3448 						msg = gettext_noop("permission denied for table %s");
3449 						break;
3450 					case OBJECT_TABLESPACE:
3451 						msg = gettext_noop("permission denied for tablespace %s");
3452 						break;
3453 					case OBJECT_TSCONFIGURATION:
3454 						msg = gettext_noop("permission denied for text search configuration %s");
3455 						break;
3456 					case OBJECT_TSDICTIONARY:
3457 						msg = gettext_noop("permission denied for text search dictionary %s");
3458 						break;
3459 					case OBJECT_TYPE:
3460 						msg = gettext_noop("permission denied for type %s");
3461 						break;
3462 					case OBJECT_VIEW:
3463 						msg = gettext_noop("permission denied for view %s");
3464 						break;
3465 						/* these currently aren't used */
3466 					case OBJECT_ACCESS_METHOD:
3467 					case OBJECT_AMOP:
3468 					case OBJECT_AMPROC:
3469 					case OBJECT_ATTRIBUTE:
3470 					case OBJECT_CAST:
3471 					case OBJECT_DEFAULT:
3472 					case OBJECT_DEFACL:
3473 					case OBJECT_DOMCONSTRAINT:
3474 					case OBJECT_PUBLICATION_REL:
3475 					case OBJECT_ROLE:
3476 					case OBJECT_RULE:
3477 					case OBJECT_TABCONSTRAINT:
3478 					case OBJECT_TRANSFORM:
3479 					case OBJECT_TRIGGER:
3480 					case OBJECT_TSPARSER:
3481 					case OBJECT_TSTEMPLATE:
3482 					case OBJECT_USER_MAPPING:
3483 						elog(ERROR, "unsupported object type %d", objtype);
3484 				}
3485 
3486 				ereport(ERROR,
3487 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3488 						 errmsg(msg, objectname)));
3489 				break;
3490 			}
3491 		case ACLCHECK_NOT_OWNER:
3492 			{
3493 				const char *msg = "???";
3494 
3495 				switch (objtype)
3496 				{
3497 					case OBJECT_AGGREGATE:
3498 						msg = gettext_noop("must be owner of aggregate %s");
3499 						break;
3500 					case OBJECT_COLLATION:
3501 						msg = gettext_noop("must be owner of collation %s");
3502 						break;
3503 					case OBJECT_CONVERSION:
3504 						msg = gettext_noop("must be owner of conversion %s");
3505 						break;
3506 					case OBJECT_DATABASE:
3507 						msg = gettext_noop("must be owner of database %s");
3508 						break;
3509 					case OBJECT_DOMAIN:
3510 						msg = gettext_noop("must be owner of domain %s");
3511 						break;
3512 					case OBJECT_EVENT_TRIGGER:
3513 						msg = gettext_noop("must be owner of event trigger %s");
3514 						break;
3515 					case OBJECT_EXTENSION:
3516 						msg = gettext_noop("must be owner of extension %s");
3517 						break;
3518 					case OBJECT_FDW:
3519 						msg = gettext_noop("must be owner of foreign-data wrapper %s");
3520 						break;
3521 					case OBJECT_FOREIGN_SERVER:
3522 						msg = gettext_noop("must be owner of foreign server %s");
3523 						break;
3524 					case OBJECT_FOREIGN_TABLE:
3525 						msg = gettext_noop("must be owner of foreign table %s");
3526 						break;
3527 					case OBJECT_FUNCTION:
3528 						msg = gettext_noop("must be owner of function %s");
3529 						break;
3530 					case OBJECT_INDEX:
3531 						msg = gettext_noop("must be owner of index %s");
3532 						break;
3533 					case OBJECT_LANGUAGE:
3534 						msg = gettext_noop("must be owner of language %s");
3535 						break;
3536 					case OBJECT_LARGEOBJECT:
3537 						msg = gettext_noop("must be owner of large object %s");
3538 						break;
3539 					case OBJECT_MATVIEW:
3540 						msg = gettext_noop("must be owner of materialized view %s");
3541 						break;
3542 					case OBJECT_OPCLASS:
3543 						msg = gettext_noop("must be owner of operator class %s");
3544 						break;
3545 					case OBJECT_OPERATOR:
3546 						msg = gettext_noop("must be owner of operator %s");
3547 						break;
3548 					case OBJECT_OPFAMILY:
3549 						msg = gettext_noop("must be owner of operator family %s");
3550 						break;
3551 					case OBJECT_PROCEDURE:
3552 						msg = gettext_noop("must be owner of procedure %s");
3553 						break;
3554 					case OBJECT_PUBLICATION:
3555 						msg = gettext_noop("must be owner of publication %s");
3556 						break;
3557 					case OBJECT_ROUTINE:
3558 						msg = gettext_noop("must be owner of routine %s");
3559 						break;
3560 					case OBJECT_SEQUENCE:
3561 						msg = gettext_noop("must be owner of sequence %s");
3562 						break;
3563 					case OBJECT_SUBSCRIPTION:
3564 						msg = gettext_noop("must be owner of subscription %s");
3565 						break;
3566 					case OBJECT_TABLE:
3567 						msg = gettext_noop("must be owner of table %s");
3568 						break;
3569 					case OBJECT_TYPE:
3570 						msg = gettext_noop("must be owner of type %s");
3571 						break;
3572 					case OBJECT_VIEW:
3573 						msg = gettext_noop("must be owner of view %s");
3574 						break;
3575 					case OBJECT_SCHEMA:
3576 						msg = gettext_noop("must be owner of schema %s");
3577 						break;
3578 					case OBJECT_STATISTIC_EXT:
3579 						msg = gettext_noop("must be owner of statistics object %s");
3580 						break;
3581 					case OBJECT_TABLESPACE:
3582 						msg = gettext_noop("must be owner of tablespace %s");
3583 						break;
3584 					case OBJECT_TSCONFIGURATION:
3585 						msg = gettext_noop("must be owner of text search configuration %s");
3586 						break;
3587 					case OBJECT_TSDICTIONARY:
3588 						msg = gettext_noop("must be owner of text search dictionary %s");
3589 						break;
3590 
3591 						/*
3592 						 * Special cases: For these, the error message talks
3593 						 * about "relation", because that's where the
3594 						 * ownership is attached.  See also
3595 						 * check_object_ownership().
3596 						 */
3597 					case OBJECT_COLUMN:
3598 					case OBJECT_POLICY:
3599 					case OBJECT_RULE:
3600 					case OBJECT_TABCONSTRAINT:
3601 					case OBJECT_TRIGGER:
3602 						msg = gettext_noop("must be owner of relation %s");
3603 						break;
3604 						/* these currently aren't used */
3605 					case OBJECT_ACCESS_METHOD:
3606 					case OBJECT_AMOP:
3607 					case OBJECT_AMPROC:
3608 					case OBJECT_ATTRIBUTE:
3609 					case OBJECT_CAST:
3610 					case OBJECT_DEFAULT:
3611 					case OBJECT_DEFACL:
3612 					case OBJECT_DOMCONSTRAINT:
3613 					case OBJECT_PUBLICATION_REL:
3614 					case OBJECT_ROLE:
3615 					case OBJECT_TRANSFORM:
3616 					case OBJECT_TSPARSER:
3617 					case OBJECT_TSTEMPLATE:
3618 					case OBJECT_USER_MAPPING:
3619 						elog(ERROR, "unsupported object type %d", objtype);
3620 				}
3621 
3622 				ereport(ERROR,
3623 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3624 						 errmsg(msg, objectname)));
3625 				break;
3626 			}
3627 		default:
3628 			elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3629 			break;
3630 	}
3631 }
3632 
3633 
3634 void
aclcheck_error_col(AclResult aclerr,ObjectType objtype,const char * objectname,const char * colname)3635 aclcheck_error_col(AclResult aclerr, ObjectType objtype,
3636 				   const char *objectname, const char *colname)
3637 {
3638 	switch (aclerr)
3639 	{
3640 		case ACLCHECK_OK:
3641 			/* no error, so return to caller */
3642 			break;
3643 		case ACLCHECK_NO_PRIV:
3644 			ereport(ERROR,
3645 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3646 					 errmsg("permission denied for column \"%s\" of relation \"%s\"",
3647 							colname, objectname)));
3648 			break;
3649 		case ACLCHECK_NOT_OWNER:
3650 			/* relation msg is OK since columns don't have separate owners */
3651 			aclcheck_error(aclerr, objtype, objectname);
3652 			break;
3653 		default:
3654 			elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
3655 			break;
3656 	}
3657 }
3658 
3659 
3660 /*
3661  * Special common handling for types: use element type instead of array type,
3662  * and format nicely
3663  */
3664 void
aclcheck_error_type(AclResult aclerr,Oid typeOid)3665 aclcheck_error_type(AclResult aclerr, Oid typeOid)
3666 {
3667 	Oid			element_type = get_element_type(typeOid);
3668 
3669 	aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
3670 }
3671 
3672 
3673 /*
3674  * Relay for the various pg_*_mask routines depending on object kind
3675  */
3676 static AclMode
pg_aclmask(ObjectType objtype,Oid table_oid,AttrNumber attnum,Oid roleid,AclMode mask,AclMaskHow how)3677 pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid,
3678 		   AclMode mask, AclMaskHow how)
3679 {
3680 	switch (objtype)
3681 	{
3682 		case OBJECT_COLUMN:
3683 			return
3684 				pg_class_aclmask(table_oid, roleid, mask, how) |
3685 				pg_attribute_aclmask(table_oid, attnum, roleid, mask, how);
3686 		case OBJECT_TABLE:
3687 		case OBJECT_SEQUENCE:
3688 			return pg_class_aclmask(table_oid, roleid, mask, how);
3689 		case OBJECT_DATABASE:
3690 			return pg_database_aclmask(table_oid, roleid, mask, how);
3691 		case OBJECT_FUNCTION:
3692 			return pg_proc_aclmask(table_oid, roleid, mask, how);
3693 		case OBJECT_LANGUAGE:
3694 			return pg_language_aclmask(table_oid, roleid, mask, how);
3695 		case OBJECT_LARGEOBJECT:
3696 			return pg_largeobject_aclmask_snapshot(table_oid, roleid,
3697 												   mask, how, NULL);
3698 		case OBJECT_SCHEMA:
3699 			return pg_namespace_aclmask(table_oid, roleid, mask, how);
3700 		case OBJECT_STATISTIC_EXT:
3701 			elog(ERROR, "grantable rights not supported for statistics objects");
3702 			/* not reached, but keep compiler quiet */
3703 			return ACL_NO_RIGHTS;
3704 		case OBJECT_TABLESPACE:
3705 			return pg_tablespace_aclmask(table_oid, roleid, mask, how);
3706 		case OBJECT_FDW:
3707 			return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
3708 		case OBJECT_FOREIGN_SERVER:
3709 			return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
3710 		case OBJECT_EVENT_TRIGGER:
3711 			elog(ERROR, "grantable rights not supported for event triggers");
3712 			/* not reached, but keep compiler quiet */
3713 			return ACL_NO_RIGHTS;
3714 		case OBJECT_TYPE:
3715 			return pg_type_aclmask(table_oid, roleid, mask, how);
3716 		default:
3717 			elog(ERROR, "unrecognized objtype: %d",
3718 				 (int) objtype);
3719 			/* not reached, but keep compiler quiet */
3720 			return ACL_NO_RIGHTS;
3721 	}
3722 }
3723 
3724 
3725 /* ****************************************************************
3726  * Exported routines for examining a user's privileges for various objects
3727  *
3728  * See aclmask() for a description of the common API for these functions.
3729  *
3730  * Note: we give lookup failure the full ereport treatment because the
3731  * has_xxx_privilege() family of functions allow users to pass any random
3732  * OID to these functions.
3733  * ****************************************************************
3734  */
3735 
3736 /*
3737  * Exported routine for examining a user's privileges for a column
3738  *
3739  * Note: this considers only privileges granted specifically on the column.
3740  * It is caller's responsibility to take relation-level privileges into account
3741  * as appropriate.  (For the same reason, we have no special case for
3742  * superuser-ness here.)
3743  */
3744 AclMode
pg_attribute_aclmask(Oid table_oid,AttrNumber attnum,Oid roleid,AclMode mask,AclMaskHow how)3745 pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
3746 					 AclMode mask, AclMaskHow how)
3747 {
3748 	AclMode		result;
3749 	HeapTuple	classTuple;
3750 	HeapTuple	attTuple;
3751 	Form_pg_class classForm;
3752 	Form_pg_attribute attributeForm;
3753 	Datum		aclDatum;
3754 	bool		isNull;
3755 	Acl		   *acl;
3756 	Oid			ownerId;
3757 
3758 	/*
3759 	 * First, get the column's ACL from its pg_attribute entry
3760 	 */
3761 	attTuple = SearchSysCache2(ATTNUM,
3762 							   ObjectIdGetDatum(table_oid),
3763 							   Int16GetDatum(attnum));
3764 	if (!HeapTupleIsValid(attTuple))
3765 		ereport(ERROR,
3766 				(errcode(ERRCODE_UNDEFINED_COLUMN),
3767 				 errmsg("attribute %d of relation with OID %u does not exist",
3768 						attnum, table_oid)));
3769 	attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3770 
3771 	/* Throw error on dropped columns, too */
3772 	if (attributeForm->attisdropped)
3773 		ereport(ERROR,
3774 				(errcode(ERRCODE_UNDEFINED_COLUMN),
3775 				 errmsg("attribute %d of relation with OID %u does not exist",
3776 						attnum, table_oid)));
3777 
3778 	aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3779 							   &isNull);
3780 
3781 	/*
3782 	 * Here we hard-wire knowledge that the default ACL for a column grants no
3783 	 * privileges, so that we can fall out quickly in the very common case
3784 	 * where attacl is null.
3785 	 */
3786 	if (isNull)
3787 	{
3788 		ReleaseSysCache(attTuple);
3789 		return 0;
3790 	}
3791 
3792 	/*
3793 	 * Must get the relation's ownerId from pg_class.  Since we already found
3794 	 * a pg_attribute entry, the only likely reason for this to fail is that a
3795 	 * concurrent DROP of the relation committed since then (which could only
3796 	 * happen if we don't have lock on the relation).  We prefer to report "no
3797 	 * privileges" rather than failing in such a case, so as to avoid unwanted
3798 	 * failures in has_column_privilege() tests.
3799 	 */
3800 	classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3801 	if (!HeapTupleIsValid(classTuple))
3802 	{
3803 		ReleaseSysCache(attTuple);
3804 		return 0;
3805 	}
3806 	classForm = (Form_pg_class) GETSTRUCT(classTuple);
3807 
3808 	ownerId = classForm->relowner;
3809 
3810 	ReleaseSysCache(classTuple);
3811 
3812 	/* detoast column's ACL if necessary */
3813 	acl = DatumGetAclP(aclDatum);
3814 
3815 	result = aclmask(acl, roleid, ownerId, mask, how);
3816 
3817 	/* if we have a detoasted copy, free it */
3818 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3819 		pfree(acl);
3820 
3821 	ReleaseSysCache(attTuple);
3822 
3823 	return result;
3824 }
3825 
3826 /*
3827  * Exported routine for examining a user's privileges for a table
3828  */
3829 AclMode
pg_class_aclmask(Oid table_oid,Oid roleid,AclMode mask,AclMaskHow how)3830 pg_class_aclmask(Oid table_oid, Oid roleid,
3831 				 AclMode mask, AclMaskHow how)
3832 {
3833 	AclMode		result;
3834 	HeapTuple	tuple;
3835 	Form_pg_class classForm;
3836 	Datum		aclDatum;
3837 	bool		isNull;
3838 	Acl		   *acl;
3839 	Oid			ownerId;
3840 
3841 	/*
3842 	 * Must get the relation's tuple from pg_class
3843 	 */
3844 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3845 	if (!HeapTupleIsValid(tuple))
3846 		ereport(ERROR,
3847 				(errcode(ERRCODE_UNDEFINED_TABLE),
3848 				 errmsg("relation with OID %u does not exist",
3849 						table_oid)));
3850 	classForm = (Form_pg_class) GETSTRUCT(tuple);
3851 
3852 	/*
3853 	 * Deny anyone permission to update a system catalog unless
3854 	 * pg_authid.rolsuper is set.  Also allow it if allowSystemTableMods.
3855 	 *
3856 	 * As of 7.4 we have some updatable system views; those shouldn't be
3857 	 * protected in this way.  Assume the view rules can take care of
3858 	 * themselves.  ACL_USAGE is if we ever have system sequences.
3859 	 */
3860 	if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3861 		IsSystemClass(table_oid, classForm) &&
3862 		classForm->relkind != RELKIND_VIEW &&
3863 		!superuser_arg(roleid) &&
3864 		!allowSystemTableMods)
3865 	{
3866 #ifdef ACLDEBUG
3867 		elog(DEBUG2, "permission denied for system catalog update");
3868 #endif
3869 		mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
3870 	}
3871 
3872 	/*
3873 	 * Otherwise, superusers bypass all permission-checking.
3874 	 */
3875 	if (superuser_arg(roleid))
3876 	{
3877 #ifdef ACLDEBUG
3878 		elog(DEBUG2, "OID %u is superuser, home free", roleid);
3879 #endif
3880 		ReleaseSysCache(tuple);
3881 		return mask;
3882 	}
3883 
3884 	/*
3885 	 * Normal case: get the relation's ACL from pg_class
3886 	 */
3887 	ownerId = classForm->relowner;
3888 
3889 	aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3890 							   &isNull);
3891 	if (isNull)
3892 	{
3893 		/* No ACL, so build default ACL */
3894 		switch (classForm->relkind)
3895 		{
3896 			case RELKIND_SEQUENCE:
3897 				acl = acldefault(OBJECT_SEQUENCE, ownerId);
3898 				break;
3899 			default:
3900 				acl = acldefault(OBJECT_TABLE, ownerId);
3901 				break;
3902 		}
3903 		aclDatum = (Datum) 0;
3904 	}
3905 	else
3906 	{
3907 		/* detoast rel's ACL if necessary */
3908 		acl = DatumGetAclP(aclDatum);
3909 	}
3910 
3911 	result = aclmask(acl, roleid, ownerId, mask, how);
3912 
3913 	/* if we have a detoasted copy, free it */
3914 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3915 		pfree(acl);
3916 
3917 	ReleaseSysCache(tuple);
3918 
3919 	return result;
3920 }
3921 
3922 /*
3923  * Exported routine for examining a user's privileges for a database
3924  */
3925 AclMode
pg_database_aclmask(Oid db_oid,Oid roleid,AclMode mask,AclMaskHow how)3926 pg_database_aclmask(Oid db_oid, Oid roleid,
3927 					AclMode mask, AclMaskHow how)
3928 {
3929 	AclMode		result;
3930 	HeapTuple	tuple;
3931 	Datum		aclDatum;
3932 	bool		isNull;
3933 	Acl		   *acl;
3934 	Oid			ownerId;
3935 
3936 	/* Superusers bypass all permission checking. */
3937 	if (superuser_arg(roleid))
3938 		return mask;
3939 
3940 	/*
3941 	 * Get the database's ACL from pg_database
3942 	 */
3943 	tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
3944 	if (!HeapTupleIsValid(tuple))
3945 		ereport(ERROR,
3946 				(errcode(ERRCODE_UNDEFINED_DATABASE),
3947 				 errmsg("database with OID %u does not exist", db_oid)));
3948 
3949 	ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
3950 
3951 	aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
3952 							   &isNull);
3953 	if (isNull)
3954 	{
3955 		/* No ACL, so build default ACL */
3956 		acl = acldefault(OBJECT_DATABASE, ownerId);
3957 		aclDatum = (Datum) 0;
3958 	}
3959 	else
3960 	{
3961 		/* detoast ACL if necessary */
3962 		acl = DatumGetAclP(aclDatum);
3963 	}
3964 
3965 	result = aclmask(acl, roleid, ownerId, mask, how);
3966 
3967 	/* if we have a detoasted copy, free it */
3968 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3969 		pfree(acl);
3970 
3971 	ReleaseSysCache(tuple);
3972 
3973 	return result;
3974 }
3975 
3976 /*
3977  * Exported routine for examining a user's privileges for a function
3978  */
3979 AclMode
pg_proc_aclmask(Oid proc_oid,Oid roleid,AclMode mask,AclMaskHow how)3980 pg_proc_aclmask(Oid proc_oid, Oid roleid,
3981 				AclMode mask, AclMaskHow how)
3982 {
3983 	AclMode		result;
3984 	HeapTuple	tuple;
3985 	Datum		aclDatum;
3986 	bool		isNull;
3987 	Acl		   *acl;
3988 	Oid			ownerId;
3989 
3990 	/* Superusers bypass all permission checking. */
3991 	if (superuser_arg(roleid))
3992 		return mask;
3993 
3994 	/*
3995 	 * Get the function's ACL from pg_proc
3996 	 */
3997 	tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
3998 	if (!HeapTupleIsValid(tuple))
3999 		ereport(ERROR,
4000 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
4001 				 errmsg("function with OID %u does not exist", proc_oid)));
4002 
4003 	ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
4004 
4005 	aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
4006 							   &isNull);
4007 	if (isNull)
4008 	{
4009 		/* No ACL, so build default ACL */
4010 		acl = acldefault(OBJECT_FUNCTION, ownerId);
4011 		aclDatum = (Datum) 0;
4012 	}
4013 	else
4014 	{
4015 		/* detoast ACL if necessary */
4016 		acl = DatumGetAclP(aclDatum);
4017 	}
4018 
4019 	result = aclmask(acl, roleid, ownerId, mask, how);
4020 
4021 	/* if we have a detoasted copy, free it */
4022 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4023 		pfree(acl);
4024 
4025 	ReleaseSysCache(tuple);
4026 
4027 	return result;
4028 }
4029 
4030 /*
4031  * Exported routine for examining a user's privileges for a language
4032  */
4033 AclMode
pg_language_aclmask(Oid lang_oid,Oid roleid,AclMode mask,AclMaskHow how)4034 pg_language_aclmask(Oid lang_oid, Oid roleid,
4035 					AclMode mask, AclMaskHow how)
4036 {
4037 	AclMode		result;
4038 	HeapTuple	tuple;
4039 	Datum		aclDatum;
4040 	bool		isNull;
4041 	Acl		   *acl;
4042 	Oid			ownerId;
4043 
4044 	/* Superusers bypass all permission checking. */
4045 	if (superuser_arg(roleid))
4046 		return mask;
4047 
4048 	/*
4049 	 * Get the language's ACL from pg_language
4050 	 */
4051 	tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid));
4052 	if (!HeapTupleIsValid(tuple))
4053 		ereport(ERROR,
4054 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4055 				 errmsg("language with OID %u does not exist", lang_oid)));
4056 
4057 	ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
4058 
4059 	aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
4060 							   &isNull);
4061 	if (isNull)
4062 	{
4063 		/* No ACL, so build default ACL */
4064 		acl = acldefault(OBJECT_LANGUAGE, ownerId);
4065 		aclDatum = (Datum) 0;
4066 	}
4067 	else
4068 	{
4069 		/* detoast ACL if necessary */
4070 		acl = DatumGetAclP(aclDatum);
4071 	}
4072 
4073 	result = aclmask(acl, roleid, ownerId, mask, how);
4074 
4075 	/* if we have a detoasted copy, free it */
4076 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4077 		pfree(acl);
4078 
4079 	ReleaseSysCache(tuple);
4080 
4081 	return result;
4082 }
4083 
4084 /*
4085  * Exported routine for examining a user's privileges for a largeobject
4086  *
4087  * When a large object is opened for reading, it is opened relative to the
4088  * caller's snapshot, but when it is opened for writing, a current
4089  * MVCC snapshot will be used.  See doc/src/sgml/lobj.sgml.  This function
4090  * takes a snapshot argument so that the permissions check can be made
4091  * relative to the same snapshot that will be used to read the underlying
4092  * data.  The caller will actually pass NULL for an instantaneous MVCC
4093  * snapshot, since all we do with the snapshot argument is pass it through
4094  * to systable_beginscan().
4095  */
4096 AclMode
pg_largeobject_aclmask_snapshot(Oid lobj_oid,Oid roleid,AclMode mask,AclMaskHow how,Snapshot snapshot)4097 pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
4098 								AclMode mask, AclMaskHow how,
4099 								Snapshot snapshot)
4100 {
4101 	AclMode		result;
4102 	Relation	pg_lo_meta;
4103 	ScanKeyData entry[1];
4104 	SysScanDesc scan;
4105 	HeapTuple	tuple;
4106 	Datum		aclDatum;
4107 	bool		isNull;
4108 	Acl		   *acl;
4109 	Oid			ownerId;
4110 
4111 	/* Superusers bypass all permission checking. */
4112 	if (superuser_arg(roleid))
4113 		return mask;
4114 
4115 	/*
4116 	 * Get the largeobject's ACL from pg_language_metadata
4117 	 */
4118 	pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
4119 						   AccessShareLock);
4120 
4121 	ScanKeyInit(&entry[0],
4122 				ObjectIdAttributeNumber,
4123 				BTEqualStrategyNumber, F_OIDEQ,
4124 				ObjectIdGetDatum(lobj_oid));
4125 
4126 	scan = systable_beginscan(pg_lo_meta,
4127 							  LargeObjectMetadataOidIndexId, true,
4128 							  snapshot, 1, entry);
4129 
4130 	tuple = systable_getnext(scan);
4131 	if (!HeapTupleIsValid(tuple))
4132 		ereport(ERROR,
4133 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4134 				 errmsg("large object %u does not exist", lobj_oid)));
4135 
4136 	ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
4137 
4138 	aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
4139 							RelationGetDescr(pg_lo_meta), &isNull);
4140 
4141 	if (isNull)
4142 	{
4143 		/* No ACL, so build default ACL */
4144 		acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
4145 		aclDatum = (Datum) 0;
4146 	}
4147 	else
4148 	{
4149 		/* detoast ACL if necessary */
4150 		acl = DatumGetAclP(aclDatum);
4151 	}
4152 
4153 	result = aclmask(acl, roleid, ownerId, mask, how);
4154 
4155 	/* if we have a detoasted copy, free it */
4156 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4157 		pfree(acl);
4158 
4159 	systable_endscan(scan);
4160 
4161 	heap_close(pg_lo_meta, AccessShareLock);
4162 
4163 	return result;
4164 }
4165 
4166 /*
4167  * Exported routine for examining a user's privileges for a namespace
4168  */
4169 AclMode
pg_namespace_aclmask(Oid nsp_oid,Oid roleid,AclMode mask,AclMaskHow how)4170 pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
4171 					 AclMode mask, AclMaskHow how)
4172 {
4173 	AclMode		result;
4174 	HeapTuple	tuple;
4175 	Datum		aclDatum;
4176 	bool		isNull;
4177 	Acl		   *acl;
4178 	Oid			ownerId;
4179 
4180 	/* Superusers bypass all permission checking. */
4181 	if (superuser_arg(roleid))
4182 		return mask;
4183 
4184 	/*
4185 	 * If we have been assigned this namespace as a temp namespace, check to
4186 	 * make sure we have CREATE TEMP permission on the database, and if so act
4187 	 * as though we have all standard (but not GRANT OPTION) permissions on
4188 	 * the namespace.  If we don't have CREATE TEMP, act as though we have
4189 	 * only USAGE (and not CREATE) rights.
4190 	 *
4191 	 * This may seem redundant given the check in InitTempTableNamespace, but
4192 	 * it really isn't since current user ID may have changed since then. The
4193 	 * upshot of this behavior is that a SECURITY DEFINER function can create
4194 	 * temp tables that can then be accessed (if permission is granted) by
4195 	 * code in the same session that doesn't have permissions to create temp
4196 	 * tables.
4197 	 *
4198 	 * XXX Would it be safe to ereport a special error message as
4199 	 * InitTempTableNamespace does?  Returning zero here means we'll get a
4200 	 * generic "permission denied for schema pg_temp_N" message, which is not
4201 	 * remarkably user-friendly.
4202 	 */
4203 	if (isTempNamespace(nsp_oid))
4204 	{
4205 		if (pg_database_aclcheck(MyDatabaseId, roleid,
4206 								 ACL_CREATE_TEMP) == ACLCHECK_OK)
4207 			return mask & ACL_ALL_RIGHTS_SCHEMA;
4208 		else
4209 			return mask & ACL_USAGE;
4210 	}
4211 
4212 	/*
4213 	 * Get the schema's ACL from pg_namespace
4214 	 */
4215 	tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
4216 	if (!HeapTupleIsValid(tuple))
4217 		ereport(ERROR,
4218 				(errcode(ERRCODE_UNDEFINED_SCHEMA),
4219 				 errmsg("schema with OID %u does not exist", nsp_oid)));
4220 
4221 	ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
4222 
4223 	aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
4224 							   &isNull);
4225 	if (isNull)
4226 	{
4227 		/* No ACL, so build default ACL */
4228 		acl = acldefault(OBJECT_SCHEMA, ownerId);
4229 		aclDatum = (Datum) 0;
4230 	}
4231 	else
4232 	{
4233 		/* detoast ACL if necessary */
4234 		acl = DatumGetAclP(aclDatum);
4235 	}
4236 
4237 	result = aclmask(acl, roleid, ownerId, mask, how);
4238 
4239 	/* if we have a detoasted copy, free it */
4240 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4241 		pfree(acl);
4242 
4243 	ReleaseSysCache(tuple);
4244 
4245 	return result;
4246 }
4247 
4248 /*
4249  * Exported routine for examining a user's privileges for a tablespace
4250  */
4251 AclMode
pg_tablespace_aclmask(Oid spc_oid,Oid roleid,AclMode mask,AclMaskHow how)4252 pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
4253 					  AclMode mask, AclMaskHow how)
4254 {
4255 	AclMode		result;
4256 	HeapTuple	tuple;
4257 	Datum		aclDatum;
4258 	bool		isNull;
4259 	Acl		   *acl;
4260 	Oid			ownerId;
4261 
4262 	/* Superusers bypass all permission checking. */
4263 	if (superuser_arg(roleid))
4264 		return mask;
4265 
4266 	/*
4267 	 * Get the tablespace's ACL from pg_tablespace
4268 	 */
4269 	tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
4270 	if (!HeapTupleIsValid(tuple))
4271 		ereport(ERROR,
4272 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4273 				 errmsg("tablespace with OID %u does not exist", spc_oid)));
4274 
4275 	ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
4276 
4277 	aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple,
4278 							   Anum_pg_tablespace_spcacl,
4279 							   &isNull);
4280 
4281 	if (isNull)
4282 	{
4283 		/* No ACL, so build default ACL */
4284 		acl = acldefault(OBJECT_TABLESPACE, ownerId);
4285 		aclDatum = (Datum) 0;
4286 	}
4287 	else
4288 	{
4289 		/* detoast ACL if necessary */
4290 		acl = DatumGetAclP(aclDatum);
4291 	}
4292 
4293 	result = aclmask(acl, roleid, ownerId, mask, how);
4294 
4295 	/* if we have a detoasted copy, free it */
4296 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4297 		pfree(acl);
4298 
4299 	ReleaseSysCache(tuple);
4300 
4301 	return result;
4302 }
4303 
4304 /*
4305  * Exported routine for examining a user's privileges for a foreign
4306  * data wrapper
4307  */
4308 AclMode
pg_foreign_data_wrapper_aclmask(Oid fdw_oid,Oid roleid,AclMode mask,AclMaskHow how)4309 pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
4310 								AclMode mask, AclMaskHow how)
4311 {
4312 	AclMode		result;
4313 	HeapTuple	tuple;
4314 	Datum		aclDatum;
4315 	bool		isNull;
4316 	Acl		   *acl;
4317 	Oid			ownerId;
4318 
4319 	Form_pg_foreign_data_wrapper fdwForm;
4320 
4321 	/* Bypass permission checks for superusers */
4322 	if (superuser_arg(roleid))
4323 		return mask;
4324 
4325 	/*
4326 	 * Must get the FDW's tuple from pg_foreign_data_wrapper
4327 	 */
4328 	tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdw_oid));
4329 	if (!HeapTupleIsValid(tuple))
4330 		ereport(ERROR,
4331 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4332 				 errmsg("foreign-data wrapper with OID %u does not exist",
4333 						fdw_oid)));
4334 	fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
4335 
4336 	/*
4337 	 * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
4338 	 */
4339 	ownerId = fdwForm->fdwowner;
4340 
4341 	aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
4342 							   Anum_pg_foreign_data_wrapper_fdwacl, &isNull);
4343 	if (isNull)
4344 	{
4345 		/* No ACL, so build default ACL */
4346 		acl = acldefault(OBJECT_FDW, ownerId);
4347 		aclDatum = (Datum) 0;
4348 	}
4349 	else
4350 	{
4351 		/* detoast rel's ACL if necessary */
4352 		acl = DatumGetAclP(aclDatum);
4353 	}
4354 
4355 	result = aclmask(acl, roleid, ownerId, mask, how);
4356 
4357 	/* if we have a detoasted copy, free it */
4358 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4359 		pfree(acl);
4360 
4361 	ReleaseSysCache(tuple);
4362 
4363 	return result;
4364 }
4365 
4366 /*
4367  * Exported routine for examining a user's privileges for a foreign
4368  * server.
4369  */
4370 AclMode
pg_foreign_server_aclmask(Oid srv_oid,Oid roleid,AclMode mask,AclMaskHow how)4371 pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
4372 						  AclMode mask, AclMaskHow how)
4373 {
4374 	AclMode		result;
4375 	HeapTuple	tuple;
4376 	Datum		aclDatum;
4377 	bool		isNull;
4378 	Acl		   *acl;
4379 	Oid			ownerId;
4380 
4381 	Form_pg_foreign_server srvForm;
4382 
4383 	/* Bypass permission checks for superusers */
4384 	if (superuser_arg(roleid))
4385 		return mask;
4386 
4387 	/*
4388 	 * Must get the FDW's tuple from pg_foreign_data_wrapper
4389 	 */
4390 	tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
4391 	if (!HeapTupleIsValid(tuple))
4392 		ereport(ERROR,
4393 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4394 				 errmsg("foreign server with OID %u does not exist",
4395 						srv_oid)));
4396 	srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
4397 
4398 	/*
4399 	 * Normal case: get the foreign server's ACL from pg_foreign_server
4400 	 */
4401 	ownerId = srvForm->srvowner;
4402 
4403 	aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
4404 							   Anum_pg_foreign_server_srvacl, &isNull);
4405 	if (isNull)
4406 	{
4407 		/* No ACL, so build default ACL */
4408 		acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
4409 		aclDatum = (Datum) 0;
4410 	}
4411 	else
4412 	{
4413 		/* detoast rel's ACL if necessary */
4414 		acl = DatumGetAclP(aclDatum);
4415 	}
4416 
4417 	result = aclmask(acl, roleid, ownerId, mask, how);
4418 
4419 	/* if we have a detoasted copy, free it */
4420 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4421 		pfree(acl);
4422 
4423 	ReleaseSysCache(tuple);
4424 
4425 	return result;
4426 }
4427 
4428 /*
4429  * Exported routine for examining a user's privileges for a type.
4430  */
4431 AclMode
pg_type_aclmask(Oid type_oid,Oid roleid,AclMode mask,AclMaskHow how)4432 pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
4433 {
4434 	AclMode		result;
4435 	HeapTuple	tuple;
4436 	Datum		aclDatum;
4437 	bool		isNull;
4438 	Acl		   *acl;
4439 	Oid			ownerId;
4440 
4441 	Form_pg_type typeForm;
4442 
4443 	/* Bypass permission checks for superusers */
4444 	if (superuser_arg(roleid))
4445 		return mask;
4446 
4447 	/*
4448 	 * Must get the type's tuple from pg_type
4449 	 */
4450 	tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
4451 	if (!HeapTupleIsValid(tuple))
4452 		ereport(ERROR,
4453 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4454 				 errmsg("type with OID %u does not exist",
4455 						type_oid)));
4456 	typeForm = (Form_pg_type) GETSTRUCT(tuple);
4457 
4458 	/*
4459 	 * "True" array types don't manage permissions of their own; consult the
4460 	 * element type instead.
4461 	 */
4462 	if (OidIsValid(typeForm->typelem) && typeForm->typlen == -1)
4463 	{
4464 		Oid			elttype_oid = typeForm->typelem;
4465 
4466 		ReleaseSysCache(tuple);
4467 
4468 		tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
4469 		/* this case is not a user-facing error, so elog not ereport */
4470 		if (!HeapTupleIsValid(tuple))
4471 			elog(ERROR, "cache lookup failed for type %u", elttype_oid);
4472 		typeForm = (Form_pg_type) GETSTRUCT(tuple);
4473 	}
4474 
4475 	/*
4476 	 * Now get the type's owner and ACL from the tuple
4477 	 */
4478 	ownerId = typeForm->typowner;
4479 
4480 	aclDatum = SysCacheGetAttr(TYPEOID, tuple,
4481 							   Anum_pg_type_typacl, &isNull);
4482 	if (isNull)
4483 	{
4484 		/* No ACL, so build default ACL */
4485 		acl = acldefault(OBJECT_TYPE, ownerId);
4486 		aclDatum = (Datum) 0;
4487 	}
4488 	else
4489 	{
4490 		/* detoast rel's ACL if necessary */
4491 		acl = DatumGetAclP(aclDatum);
4492 	}
4493 
4494 	result = aclmask(acl, roleid, ownerId, mask, how);
4495 
4496 	/* if we have a detoasted copy, free it */
4497 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4498 		pfree(acl);
4499 
4500 	ReleaseSysCache(tuple);
4501 
4502 	return result;
4503 }
4504 
4505 /*
4506  * Exported routine for checking a user's access privileges to a column
4507  *
4508  * Returns ACLCHECK_OK if the user has any of the privileges identified by
4509  * 'mode'; otherwise returns a suitable error code (in practice, always
4510  * ACLCHECK_NO_PRIV).
4511  *
4512  * As with pg_attribute_aclmask, only privileges granted directly on the
4513  * column are considered here.
4514  */
4515 AclResult
pg_attribute_aclcheck(Oid table_oid,AttrNumber attnum,Oid roleid,AclMode mode)4516 pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
4517 					  Oid roleid, AclMode mode)
4518 {
4519 	if (pg_attribute_aclmask(table_oid, attnum, roleid, mode, ACLMASK_ANY) != 0)
4520 		return ACLCHECK_OK;
4521 	else
4522 		return ACLCHECK_NO_PRIV;
4523 }
4524 
4525 /*
4526  * Exported routine for checking a user's access privileges to any/all columns
4527  *
4528  * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
4529  * privileges identified by 'mode' on any non-dropped column in the relation;
4530  * otherwise returns a suitable error code (in practice, always
4531  * ACLCHECK_NO_PRIV).
4532  *
4533  * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
4534  * privileges identified by 'mode' on each non-dropped column in the relation
4535  * (and there must be at least one such column); otherwise returns a suitable
4536  * error code (in practice, always ACLCHECK_NO_PRIV).
4537  *
4538  * As with pg_attribute_aclmask, only privileges granted directly on the
4539  * column(s) are considered here.
4540  *
4541  * Note: system columns are not considered here; there are cases where that
4542  * might be appropriate but there are also cases where it wouldn't.
4543  */
4544 AclResult
pg_attribute_aclcheck_all(Oid table_oid,Oid roleid,AclMode mode,AclMaskHow how)4545 pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
4546 						  AclMaskHow how)
4547 {
4548 	AclResult	result;
4549 	HeapTuple	classTuple;
4550 	Form_pg_class classForm;
4551 	AttrNumber	nattrs;
4552 	AttrNumber	curr_att;
4553 
4554 	/*
4555 	 * Must fetch pg_class row to check number of attributes.  As in
4556 	 * pg_attribute_aclmask, we prefer to return "no privileges" instead of
4557 	 * throwing an error if we get any unexpected lookup errors.
4558 	 */
4559 	classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
4560 	if (!HeapTupleIsValid(classTuple))
4561 		return ACLCHECK_NO_PRIV;
4562 	classForm = (Form_pg_class) GETSTRUCT(classTuple);
4563 
4564 	nattrs = classForm->relnatts;
4565 
4566 	ReleaseSysCache(classTuple);
4567 
4568 	/*
4569 	 * Initialize result in case there are no non-dropped columns.  We want to
4570 	 * report failure in such cases for either value of 'how'.
4571 	 */
4572 	result = ACLCHECK_NO_PRIV;
4573 
4574 	for (curr_att = 1; curr_att <= nattrs; curr_att++)
4575 	{
4576 		HeapTuple	attTuple;
4577 		AclMode		attmask;
4578 
4579 		attTuple = SearchSysCache2(ATTNUM,
4580 								   ObjectIdGetDatum(table_oid),
4581 								   Int16GetDatum(curr_att));
4582 		if (!HeapTupleIsValid(attTuple))
4583 			continue;
4584 
4585 		/* ignore dropped columns */
4586 		if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4587 		{
4588 			ReleaseSysCache(attTuple);
4589 			continue;
4590 		}
4591 
4592 		/*
4593 		 * Here we hard-wire knowledge that the default ACL for a column
4594 		 * grants no privileges, so that we can fall out quickly in the very
4595 		 * common case where attacl is null.
4596 		 */
4597 		if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
4598 			attmask = 0;
4599 		else
4600 			attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
4601 										   mode, ACLMASK_ANY);
4602 
4603 		ReleaseSysCache(attTuple);
4604 
4605 		if (attmask != 0)
4606 		{
4607 			result = ACLCHECK_OK;
4608 			if (how == ACLMASK_ANY)
4609 				break;			/* succeed on any success */
4610 		}
4611 		else
4612 		{
4613 			result = ACLCHECK_NO_PRIV;
4614 			if (how == ACLMASK_ALL)
4615 				break;			/* fail on any failure */
4616 		}
4617 	}
4618 
4619 	return result;
4620 }
4621 
4622 /*
4623  * Exported routine for checking a user's access privileges to a table
4624  *
4625  * Returns ACLCHECK_OK if the user has any of the privileges identified by
4626  * 'mode'; otherwise returns a suitable error code (in practice, always
4627  * ACLCHECK_NO_PRIV).
4628  */
4629 AclResult
pg_class_aclcheck(Oid table_oid,Oid roleid,AclMode mode)4630 pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
4631 {
4632 	if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
4633 		return ACLCHECK_OK;
4634 	else
4635 		return ACLCHECK_NO_PRIV;
4636 }
4637 
4638 /*
4639  * Exported routine for checking a user's access privileges to a database
4640  */
4641 AclResult
pg_database_aclcheck(Oid db_oid,Oid roleid,AclMode mode)4642 pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
4643 {
4644 	if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
4645 		return ACLCHECK_OK;
4646 	else
4647 		return ACLCHECK_NO_PRIV;
4648 }
4649 
4650 /*
4651  * Exported routine for checking a user's access privileges to a function
4652  */
4653 AclResult
pg_proc_aclcheck(Oid proc_oid,Oid roleid,AclMode mode)4654 pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
4655 {
4656 	if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
4657 		return ACLCHECK_OK;
4658 	else
4659 		return ACLCHECK_NO_PRIV;
4660 }
4661 
4662 /*
4663  * Exported routine for checking a user's access privileges to a language
4664  */
4665 AclResult
pg_language_aclcheck(Oid lang_oid,Oid roleid,AclMode mode)4666 pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
4667 {
4668 	if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
4669 		return ACLCHECK_OK;
4670 	else
4671 		return ACLCHECK_NO_PRIV;
4672 }
4673 
4674 /*
4675  * Exported routine for checking a user's access privileges to a largeobject
4676  */
4677 AclResult
pg_largeobject_aclcheck_snapshot(Oid lobj_oid,Oid roleid,AclMode mode,Snapshot snapshot)4678 pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
4679 								 Snapshot snapshot)
4680 {
4681 	if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4682 										ACLMASK_ANY, snapshot) != 0)
4683 		return ACLCHECK_OK;
4684 	else
4685 		return ACLCHECK_NO_PRIV;
4686 }
4687 
4688 /*
4689  * Exported routine for checking a user's access privileges to a namespace
4690  */
4691 AclResult
pg_namespace_aclcheck(Oid nsp_oid,Oid roleid,AclMode mode)4692 pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
4693 {
4694 	if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
4695 		return ACLCHECK_OK;
4696 	else
4697 		return ACLCHECK_NO_PRIV;
4698 }
4699 
4700 /*
4701  * Exported routine for checking a user's access privileges to a tablespace
4702  */
4703 AclResult
pg_tablespace_aclcheck(Oid spc_oid,Oid roleid,AclMode mode)4704 pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
4705 {
4706 	if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
4707 		return ACLCHECK_OK;
4708 	else
4709 		return ACLCHECK_NO_PRIV;
4710 }
4711 
4712 /*
4713  * Exported routine for checking a user's access privileges to a foreign
4714  * data wrapper
4715  */
4716 AclResult
pg_foreign_data_wrapper_aclcheck(Oid fdw_oid,Oid roleid,AclMode mode)4717 pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode)
4718 {
4719 	if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0)
4720 		return ACLCHECK_OK;
4721 	else
4722 		return ACLCHECK_NO_PRIV;
4723 }
4724 
4725 /*
4726  * Exported routine for checking a user's access privileges to a foreign
4727  * server
4728  */
4729 AclResult
pg_foreign_server_aclcheck(Oid srv_oid,Oid roleid,AclMode mode)4730 pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
4731 {
4732 	if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0)
4733 		return ACLCHECK_OK;
4734 	else
4735 		return ACLCHECK_NO_PRIV;
4736 }
4737 
4738 /*
4739  * Exported routine for checking a user's access privileges to a type
4740  */
4741 AclResult
pg_type_aclcheck(Oid type_oid,Oid roleid,AclMode mode)4742 pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
4743 {
4744 	if (pg_type_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0)
4745 		return ACLCHECK_OK;
4746 	else
4747 		return ACLCHECK_NO_PRIV;
4748 }
4749 
4750 /*
4751  * Ownership check for a relation (specified by OID).
4752  */
4753 bool
pg_class_ownercheck(Oid class_oid,Oid roleid)4754 pg_class_ownercheck(Oid class_oid, Oid roleid)
4755 {
4756 	HeapTuple	tuple;
4757 	Oid			ownerId;
4758 
4759 	/* Superusers bypass all permission checking. */
4760 	if (superuser_arg(roleid))
4761 		return true;
4762 
4763 	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid));
4764 	if (!HeapTupleIsValid(tuple))
4765 		ereport(ERROR,
4766 				(errcode(ERRCODE_UNDEFINED_TABLE),
4767 				 errmsg("relation with OID %u does not exist", class_oid)));
4768 
4769 	ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
4770 
4771 	ReleaseSysCache(tuple);
4772 
4773 	return has_privs_of_role(roleid, ownerId);
4774 }
4775 
4776 /*
4777  * Ownership check for a type (specified by OID).
4778  */
4779 bool
pg_type_ownercheck(Oid type_oid,Oid roleid)4780 pg_type_ownercheck(Oid type_oid, Oid roleid)
4781 {
4782 	HeapTuple	tuple;
4783 	Oid			ownerId;
4784 
4785 	/* Superusers bypass all permission checking. */
4786 	if (superuser_arg(roleid))
4787 		return true;
4788 
4789 	tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
4790 	if (!HeapTupleIsValid(tuple))
4791 		ereport(ERROR,
4792 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4793 				 errmsg("type with OID %u does not exist", type_oid)));
4794 
4795 	ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
4796 
4797 	ReleaseSysCache(tuple);
4798 
4799 	return has_privs_of_role(roleid, ownerId);
4800 }
4801 
4802 /*
4803  * Ownership check for an operator (specified by OID).
4804  */
4805 bool
pg_oper_ownercheck(Oid oper_oid,Oid roleid)4806 pg_oper_ownercheck(Oid oper_oid, Oid roleid)
4807 {
4808 	HeapTuple	tuple;
4809 	Oid			ownerId;
4810 
4811 	/* Superusers bypass all permission checking. */
4812 	if (superuser_arg(roleid))
4813 		return true;
4814 
4815 	tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(oper_oid));
4816 	if (!HeapTupleIsValid(tuple))
4817 		ereport(ERROR,
4818 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
4819 				 errmsg("operator with OID %u does not exist", oper_oid)));
4820 
4821 	ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
4822 
4823 	ReleaseSysCache(tuple);
4824 
4825 	return has_privs_of_role(roleid, ownerId);
4826 }
4827 
4828 /*
4829  * Ownership check for a function (specified by OID).
4830  */
4831 bool
pg_proc_ownercheck(Oid proc_oid,Oid roleid)4832 pg_proc_ownercheck(Oid proc_oid, Oid roleid)
4833 {
4834 	HeapTuple	tuple;
4835 	Oid			ownerId;
4836 
4837 	/* Superusers bypass all permission checking. */
4838 	if (superuser_arg(roleid))
4839 		return true;
4840 
4841 	tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
4842 	if (!HeapTupleIsValid(tuple))
4843 		ereport(ERROR,
4844 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
4845 				 errmsg("function with OID %u does not exist", proc_oid)));
4846 
4847 	ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
4848 
4849 	ReleaseSysCache(tuple);
4850 
4851 	return has_privs_of_role(roleid, ownerId);
4852 }
4853 
4854 /*
4855  * Ownership check for a procedural language (specified by OID)
4856  */
4857 bool
pg_language_ownercheck(Oid lan_oid,Oid roleid)4858 pg_language_ownercheck(Oid lan_oid, Oid roleid)
4859 {
4860 	HeapTuple	tuple;
4861 	Oid			ownerId;
4862 
4863 	/* Superusers bypass all permission checking. */
4864 	if (superuser_arg(roleid))
4865 		return true;
4866 
4867 	tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lan_oid));
4868 	if (!HeapTupleIsValid(tuple))
4869 		ereport(ERROR,
4870 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
4871 				 errmsg("language with OID %u does not exist", lan_oid)));
4872 
4873 	ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
4874 
4875 	ReleaseSysCache(tuple);
4876 
4877 	return has_privs_of_role(roleid, ownerId);
4878 }
4879 
4880 /*
4881  * Ownership check for a largeobject (specified by OID)
4882  *
4883  * This is only used for operations like ALTER LARGE OBJECT that are always
4884  * relative to an up-to-date snapshot.
4885  */
4886 bool
pg_largeobject_ownercheck(Oid lobj_oid,Oid roleid)4887 pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
4888 {
4889 	Relation	pg_lo_meta;
4890 	ScanKeyData entry[1];
4891 	SysScanDesc scan;
4892 	HeapTuple	tuple;
4893 	Oid			ownerId;
4894 
4895 	/* Superusers bypass all permission checking. */
4896 	if (superuser_arg(roleid))
4897 		return true;
4898 
4899 	/* There's no syscache for pg_largeobject_metadata */
4900 	pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
4901 						   AccessShareLock);
4902 
4903 	ScanKeyInit(&entry[0],
4904 				ObjectIdAttributeNumber,
4905 				BTEqualStrategyNumber, F_OIDEQ,
4906 				ObjectIdGetDatum(lobj_oid));
4907 
4908 	scan = systable_beginscan(pg_lo_meta,
4909 							  LargeObjectMetadataOidIndexId, true,
4910 							  NULL, 1, entry);
4911 
4912 	tuple = systable_getnext(scan);
4913 	if (!HeapTupleIsValid(tuple))
4914 		ereport(ERROR,
4915 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4916 				 errmsg("large object %u does not exist", lobj_oid)));
4917 
4918 	ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
4919 
4920 	systable_endscan(scan);
4921 	heap_close(pg_lo_meta, AccessShareLock);
4922 
4923 	return has_privs_of_role(roleid, ownerId);
4924 }
4925 
4926 /*
4927  * Ownership check for a namespace (specified by OID).
4928  */
4929 bool
pg_namespace_ownercheck(Oid nsp_oid,Oid roleid)4930 pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
4931 {
4932 	HeapTuple	tuple;
4933 	Oid			ownerId;
4934 
4935 	/* Superusers bypass all permission checking. */
4936 	if (superuser_arg(roleid))
4937 		return true;
4938 
4939 	tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
4940 	if (!HeapTupleIsValid(tuple))
4941 		ereport(ERROR,
4942 				(errcode(ERRCODE_UNDEFINED_SCHEMA),
4943 				 errmsg("schema with OID %u does not exist", nsp_oid)));
4944 
4945 	ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
4946 
4947 	ReleaseSysCache(tuple);
4948 
4949 	return has_privs_of_role(roleid, ownerId);
4950 }
4951 
4952 /*
4953  * Ownership check for a tablespace (specified by OID).
4954  */
4955 bool
pg_tablespace_ownercheck(Oid spc_oid,Oid roleid)4956 pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
4957 {
4958 	HeapTuple	spctuple;
4959 	Oid			spcowner;
4960 
4961 	/* Superusers bypass all permission checking. */
4962 	if (superuser_arg(roleid))
4963 		return true;
4964 
4965 	/* Search syscache for pg_tablespace */
4966 	spctuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
4967 	if (!HeapTupleIsValid(spctuple))
4968 		ereport(ERROR,
4969 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4970 				 errmsg("tablespace with OID %u does not exist", spc_oid)));
4971 
4972 	spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
4973 
4974 	ReleaseSysCache(spctuple);
4975 
4976 	return has_privs_of_role(roleid, spcowner);
4977 }
4978 
4979 /*
4980  * Ownership check for an operator class (specified by OID).
4981  */
4982 bool
pg_opclass_ownercheck(Oid opc_oid,Oid roleid)4983 pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
4984 {
4985 	HeapTuple	tuple;
4986 	Oid			ownerId;
4987 
4988 	/* Superusers bypass all permission checking. */
4989 	if (superuser_arg(roleid))
4990 		return true;
4991 
4992 	tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opc_oid));
4993 	if (!HeapTupleIsValid(tuple))
4994 		ereport(ERROR,
4995 				(errcode(ERRCODE_UNDEFINED_OBJECT),
4996 				 errmsg("operator class with OID %u does not exist",
4997 						opc_oid)));
4998 
4999 	ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
5000 
5001 	ReleaseSysCache(tuple);
5002 
5003 	return has_privs_of_role(roleid, ownerId);
5004 }
5005 
5006 /*
5007  * Ownership check for an operator family (specified by OID).
5008  */
5009 bool
pg_opfamily_ownercheck(Oid opf_oid,Oid roleid)5010 pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
5011 {
5012 	HeapTuple	tuple;
5013 	Oid			ownerId;
5014 
5015 	/* Superusers bypass all permission checking. */
5016 	if (superuser_arg(roleid))
5017 		return true;
5018 
5019 	tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opf_oid));
5020 	if (!HeapTupleIsValid(tuple))
5021 		ereport(ERROR,
5022 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5023 				 errmsg("operator family with OID %u does not exist",
5024 						opf_oid)));
5025 
5026 	ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
5027 
5028 	ReleaseSysCache(tuple);
5029 
5030 	return has_privs_of_role(roleid, ownerId);
5031 }
5032 
5033 /*
5034  * Ownership check for a text search dictionary (specified by OID).
5035  */
5036 bool
pg_ts_dict_ownercheck(Oid dict_oid,Oid roleid)5037 pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid)
5038 {
5039 	HeapTuple	tuple;
5040 	Oid			ownerId;
5041 
5042 	/* Superusers bypass all permission checking. */
5043 	if (superuser_arg(roleid))
5044 		return true;
5045 
5046 	tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dict_oid));
5047 	if (!HeapTupleIsValid(tuple))
5048 		ereport(ERROR,
5049 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5050 				 errmsg("text search dictionary with OID %u does not exist",
5051 						dict_oid)));
5052 
5053 	ownerId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictowner;
5054 
5055 	ReleaseSysCache(tuple);
5056 
5057 	return has_privs_of_role(roleid, ownerId);
5058 }
5059 
5060 /*
5061  * Ownership check for a text search configuration (specified by OID).
5062  */
5063 bool
pg_ts_config_ownercheck(Oid cfg_oid,Oid roleid)5064 pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid)
5065 {
5066 	HeapTuple	tuple;
5067 	Oid			ownerId;
5068 
5069 	/* Superusers bypass all permission checking. */
5070 	if (superuser_arg(roleid))
5071 		return true;
5072 
5073 	tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfg_oid));
5074 	if (!HeapTupleIsValid(tuple))
5075 		ereport(ERROR,
5076 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5077 				 errmsg("text search configuration with OID %u does not exist",
5078 						cfg_oid)));
5079 
5080 	ownerId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgowner;
5081 
5082 	ReleaseSysCache(tuple);
5083 
5084 	return has_privs_of_role(roleid, ownerId);
5085 }
5086 
5087 /*
5088  * Ownership check for a foreign-data wrapper (specified by OID).
5089  */
5090 bool
pg_foreign_data_wrapper_ownercheck(Oid srv_oid,Oid roleid)5091 pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid)
5092 {
5093 	HeapTuple	tuple;
5094 	Oid			ownerId;
5095 
5096 	/* Superusers bypass all permission checking. */
5097 	if (superuser_arg(roleid))
5098 		return true;
5099 
5100 	tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(srv_oid));
5101 	if (!HeapTupleIsValid(tuple))
5102 		ereport(ERROR,
5103 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5104 				 errmsg("foreign-data wrapper with OID %u does not exist",
5105 						srv_oid)));
5106 
5107 	ownerId = ((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwowner;
5108 
5109 	ReleaseSysCache(tuple);
5110 
5111 	return has_privs_of_role(roleid, ownerId);
5112 }
5113 
5114 /*
5115  * Ownership check for a foreign server (specified by OID).
5116  */
5117 bool
pg_foreign_server_ownercheck(Oid srv_oid,Oid roleid)5118 pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
5119 {
5120 	HeapTuple	tuple;
5121 	Oid			ownerId;
5122 
5123 	/* Superusers bypass all permission checking. */
5124 	if (superuser_arg(roleid))
5125 		return true;
5126 
5127 	tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
5128 	if (!HeapTupleIsValid(tuple))
5129 		ereport(ERROR,
5130 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5131 				 errmsg("foreign server with OID %u does not exist",
5132 						srv_oid)));
5133 
5134 	ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner;
5135 
5136 	ReleaseSysCache(tuple);
5137 
5138 	return has_privs_of_role(roleid, ownerId);
5139 }
5140 
5141 /*
5142  * Ownership check for an event trigger (specified by OID).
5143  */
5144 bool
pg_event_trigger_ownercheck(Oid et_oid,Oid roleid)5145 pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
5146 {
5147 	HeapTuple	tuple;
5148 	Oid			ownerId;
5149 
5150 	/* Superusers bypass all permission checking. */
5151 	if (superuser_arg(roleid))
5152 		return true;
5153 
5154 	tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid));
5155 	if (!HeapTupleIsValid(tuple))
5156 		ereport(ERROR,
5157 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5158 				 errmsg("event trigger with OID %u does not exist",
5159 						et_oid)));
5160 
5161 	ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
5162 
5163 	ReleaseSysCache(tuple);
5164 
5165 	return has_privs_of_role(roleid, ownerId);
5166 }
5167 
5168 /*
5169  * Ownership check for a database (specified by OID).
5170  */
5171 bool
pg_database_ownercheck(Oid db_oid,Oid roleid)5172 pg_database_ownercheck(Oid db_oid, Oid roleid)
5173 {
5174 	HeapTuple	tuple;
5175 	Oid			dba;
5176 
5177 	/* Superusers bypass all permission checking. */
5178 	if (superuser_arg(roleid))
5179 		return true;
5180 
5181 	tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
5182 	if (!HeapTupleIsValid(tuple))
5183 		ereport(ERROR,
5184 				(errcode(ERRCODE_UNDEFINED_DATABASE),
5185 				 errmsg("database with OID %u does not exist", db_oid)));
5186 
5187 	dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
5188 
5189 	ReleaseSysCache(tuple);
5190 
5191 	return has_privs_of_role(roleid, dba);
5192 }
5193 
5194 /*
5195  * Ownership check for a collation (specified by OID).
5196  */
5197 bool
pg_collation_ownercheck(Oid coll_oid,Oid roleid)5198 pg_collation_ownercheck(Oid coll_oid, Oid roleid)
5199 {
5200 	HeapTuple	tuple;
5201 	Oid			ownerId;
5202 
5203 	/* Superusers bypass all permission checking. */
5204 	if (superuser_arg(roleid))
5205 		return true;
5206 
5207 	tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(coll_oid));
5208 	if (!HeapTupleIsValid(tuple))
5209 		ereport(ERROR,
5210 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5211 				 errmsg("collation with OID %u does not exist", coll_oid)));
5212 
5213 	ownerId = ((Form_pg_collation) GETSTRUCT(tuple))->collowner;
5214 
5215 	ReleaseSysCache(tuple);
5216 
5217 	return has_privs_of_role(roleid, ownerId);
5218 }
5219 
5220 /*
5221  * Ownership check for a conversion (specified by OID).
5222  */
5223 bool
pg_conversion_ownercheck(Oid conv_oid,Oid roleid)5224 pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
5225 {
5226 	HeapTuple	tuple;
5227 	Oid			ownerId;
5228 
5229 	/* Superusers bypass all permission checking. */
5230 	if (superuser_arg(roleid))
5231 		return true;
5232 
5233 	tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conv_oid));
5234 	if (!HeapTupleIsValid(tuple))
5235 		ereport(ERROR,
5236 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5237 				 errmsg("conversion with OID %u does not exist", conv_oid)));
5238 
5239 	ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
5240 
5241 	ReleaseSysCache(tuple);
5242 
5243 	return has_privs_of_role(roleid, ownerId);
5244 }
5245 
5246 /*
5247  * Ownership check for an extension (specified by OID).
5248  */
5249 bool
pg_extension_ownercheck(Oid ext_oid,Oid roleid)5250 pg_extension_ownercheck(Oid ext_oid, Oid roleid)
5251 {
5252 	Relation	pg_extension;
5253 	ScanKeyData entry[1];
5254 	SysScanDesc scan;
5255 	HeapTuple	tuple;
5256 	Oid			ownerId;
5257 
5258 	/* Superusers bypass all permission checking. */
5259 	if (superuser_arg(roleid))
5260 		return true;
5261 
5262 	/* There's no syscache for pg_extension, so do it the hard way */
5263 	pg_extension = heap_open(ExtensionRelationId, AccessShareLock);
5264 
5265 	ScanKeyInit(&entry[0],
5266 				ObjectIdAttributeNumber,
5267 				BTEqualStrategyNumber, F_OIDEQ,
5268 				ObjectIdGetDatum(ext_oid));
5269 
5270 	scan = systable_beginscan(pg_extension,
5271 							  ExtensionOidIndexId, true,
5272 							  NULL, 1, entry);
5273 
5274 	tuple = systable_getnext(scan);
5275 	if (!HeapTupleIsValid(tuple))
5276 		ereport(ERROR,
5277 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5278 				 errmsg("extension with OID %u does not exist", ext_oid)));
5279 
5280 	ownerId = ((Form_pg_extension) GETSTRUCT(tuple))->extowner;
5281 
5282 	systable_endscan(scan);
5283 	heap_close(pg_extension, AccessShareLock);
5284 
5285 	return has_privs_of_role(roleid, ownerId);
5286 }
5287 
5288 /*
5289  * Ownership check for a publication (specified by OID).
5290  */
5291 bool
pg_publication_ownercheck(Oid pub_oid,Oid roleid)5292 pg_publication_ownercheck(Oid pub_oid, Oid roleid)
5293 {
5294 	HeapTuple	tuple;
5295 	Oid			ownerId;
5296 
5297 	/* Superusers bypass all permission checking. */
5298 	if (superuser_arg(roleid))
5299 		return true;
5300 
5301 	tuple = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pub_oid));
5302 	if (!HeapTupleIsValid(tuple))
5303 		ereport(ERROR,
5304 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5305 				 errmsg("publication with OID %u does not exist", pub_oid)));
5306 
5307 	ownerId = ((Form_pg_publication) GETSTRUCT(tuple))->pubowner;
5308 
5309 	ReleaseSysCache(tuple);
5310 
5311 	return has_privs_of_role(roleid, ownerId);
5312 }
5313 
5314 /*
5315  * Ownership check for a subscription (specified by OID).
5316  */
5317 bool
pg_subscription_ownercheck(Oid sub_oid,Oid roleid)5318 pg_subscription_ownercheck(Oid sub_oid, Oid roleid)
5319 {
5320 	HeapTuple	tuple;
5321 	Oid			ownerId;
5322 
5323 	/* Superusers bypass all permission checking. */
5324 	if (superuser_arg(roleid))
5325 		return true;
5326 
5327 	tuple = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(sub_oid));
5328 	if (!HeapTupleIsValid(tuple))
5329 		ereport(ERROR,
5330 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5331 				 errmsg("subscription with OID %u does not exist", sub_oid)));
5332 
5333 	ownerId = ((Form_pg_subscription) GETSTRUCT(tuple))->subowner;
5334 
5335 	ReleaseSysCache(tuple);
5336 
5337 	return has_privs_of_role(roleid, ownerId);
5338 }
5339 
5340 /*
5341  * Ownership check for a statistics object (specified by OID).
5342  */
5343 bool
pg_statistics_object_ownercheck(Oid stat_oid,Oid roleid)5344 pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
5345 {
5346 	HeapTuple	tuple;
5347 	Oid			ownerId;
5348 
5349 	/* Superusers bypass all permission checking. */
5350 	if (superuser_arg(roleid))
5351 		return true;
5352 
5353 	tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stat_oid));
5354 	if (!HeapTupleIsValid(tuple))
5355 		ereport(ERROR,
5356 				(errcode(ERRCODE_UNDEFINED_OBJECT),
5357 				 errmsg("statistics object with OID %u does not exist",
5358 						stat_oid)));
5359 
5360 	ownerId = ((Form_pg_statistic_ext) GETSTRUCT(tuple))->stxowner;
5361 
5362 	ReleaseSysCache(tuple);
5363 
5364 	return has_privs_of_role(roleid, ownerId);
5365 }
5366 
5367 /*
5368  * Check whether specified role has CREATEROLE privilege (or is a superuser)
5369  *
5370  * Note: roles do not have owners per se; instead we use this test in
5371  * places where an ownership-like permissions test is needed for a role.
5372  * Be sure to apply it to the role trying to do the operation, not the
5373  * role being operated on!	Also note that this generally should not be
5374  * considered enough privilege if the target role is a superuser.
5375  * (We don't handle that consideration here because we want to give a
5376  * separate error message for such cases, so the caller has to deal with it.)
5377  */
5378 bool
has_createrole_privilege(Oid roleid)5379 has_createrole_privilege(Oid roleid)
5380 {
5381 	bool		result = false;
5382 	HeapTuple	utup;
5383 
5384 	/* Superusers bypass all permission checking. */
5385 	if (superuser_arg(roleid))
5386 		return true;
5387 
5388 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
5389 	if (HeapTupleIsValid(utup))
5390 	{
5391 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
5392 		ReleaseSysCache(utup);
5393 	}
5394 	return result;
5395 }
5396 
5397 bool
has_bypassrls_privilege(Oid roleid)5398 has_bypassrls_privilege(Oid roleid)
5399 {
5400 	bool		result = false;
5401 	HeapTuple	utup;
5402 
5403 	/* Superusers bypass all permission checking. */
5404 	if (superuser_arg(roleid))
5405 		return true;
5406 
5407 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
5408 	if (HeapTupleIsValid(utup))
5409 	{
5410 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
5411 		ReleaseSysCache(utup);
5412 	}
5413 	return result;
5414 }
5415 
5416 /*
5417  * Fetch pg_default_acl entry for given role, namespace and object type
5418  * (object type must be given in pg_default_acl's encoding).
5419  * Returns NULL if no such entry.
5420  */
5421 static Acl *
get_default_acl_internal(Oid roleId,Oid nsp_oid,char objtype)5422 get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
5423 {
5424 	Acl		   *result = NULL;
5425 	HeapTuple	tuple;
5426 
5427 	tuple = SearchSysCache3(DEFACLROLENSPOBJ,
5428 							ObjectIdGetDatum(roleId),
5429 							ObjectIdGetDatum(nsp_oid),
5430 							CharGetDatum(objtype));
5431 
5432 	if (HeapTupleIsValid(tuple))
5433 	{
5434 		Datum		aclDatum;
5435 		bool		isNull;
5436 
5437 		aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
5438 								   Anum_pg_default_acl_defaclacl,
5439 								   &isNull);
5440 		if (!isNull)
5441 			result = DatumGetAclPCopy(aclDatum);
5442 		ReleaseSysCache(tuple);
5443 	}
5444 
5445 	return result;
5446 }
5447 
5448 /*
5449  * Get default permissions for newly created object within given schema
5450  *
5451  * Returns NULL if built-in system defaults should be used.
5452  *
5453  * If the result is not NULL, caller must call recordDependencyOnNewAcl
5454  * once the OID of the new object is known.
5455  */
5456 Acl *
get_user_default_acl(ObjectType objtype,Oid ownerId,Oid nsp_oid)5457 get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
5458 {
5459 	Acl		   *result;
5460 	Acl		   *glob_acl;
5461 	Acl		   *schema_acl;
5462 	Acl		   *def_acl;
5463 	char		defaclobjtype;
5464 
5465 	/*
5466 	 * Use NULL during bootstrap, since pg_default_acl probably isn't there
5467 	 * yet.
5468 	 */
5469 	if (IsBootstrapProcessingMode())
5470 		return NULL;
5471 
5472 	/* Check if object type is supported in pg_default_acl */
5473 	switch (objtype)
5474 	{
5475 		case OBJECT_TABLE:
5476 			defaclobjtype = DEFACLOBJ_RELATION;
5477 			break;
5478 
5479 		case OBJECT_SEQUENCE:
5480 			defaclobjtype = DEFACLOBJ_SEQUENCE;
5481 			break;
5482 
5483 		case OBJECT_FUNCTION:
5484 			defaclobjtype = DEFACLOBJ_FUNCTION;
5485 			break;
5486 
5487 		case OBJECT_TYPE:
5488 			defaclobjtype = DEFACLOBJ_TYPE;
5489 			break;
5490 
5491 		case OBJECT_SCHEMA:
5492 			defaclobjtype = DEFACLOBJ_NAMESPACE;
5493 			break;
5494 
5495 		default:
5496 			return NULL;
5497 	}
5498 
5499 	/* Look up the relevant pg_default_acl entries */
5500 	glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
5501 	schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
5502 
5503 	/* Quick out if neither entry exists */
5504 	if (glob_acl == NULL && schema_acl == NULL)
5505 		return NULL;
5506 
5507 	/* We need to know the hard-wired default value, too */
5508 	def_acl = acldefault(objtype, ownerId);
5509 
5510 	/* If there's no global entry, substitute the hard-wired default */
5511 	if (glob_acl == NULL)
5512 		glob_acl = def_acl;
5513 
5514 	/* Merge in any per-schema privileges */
5515 	result = aclmerge(glob_acl, schema_acl, ownerId);
5516 
5517 	/*
5518 	 * For efficiency, we want to return NULL if the result equals default.
5519 	 * This requires sorting both arrays to get an accurate comparison.
5520 	 */
5521 	aclitemsort(result);
5522 	aclitemsort(def_acl);
5523 	if (aclequal(result, def_acl))
5524 		result = NULL;
5525 
5526 	return result;
5527 }
5528 
5529 /*
5530  * Record dependencies on roles mentioned in a new object's ACL.
5531  */
5532 void
recordDependencyOnNewAcl(Oid classId,Oid objectId,int32 objsubId,Oid ownerId,Acl * acl)5533 recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
5534 						 Oid ownerId, Acl *acl)
5535 {
5536 	int			nmembers;
5537 	Oid		   *members;
5538 
5539 	/* Nothing to do if ACL is defaulted */
5540 	if (acl == NULL)
5541 		return;
5542 
5543 	/* Extract roles mentioned in ACL */
5544 	nmembers = aclmembers(acl, &members);
5545 
5546 	/* Update the shared dependency ACL info */
5547 	updateAclDependencies(classId, objectId, objsubId,
5548 						  ownerId,
5549 						  0, NULL,
5550 						  nmembers, members);
5551 }
5552 
5553 /*
5554  * Record initial privileges for the top-level object passed in.
5555  *
5556  * For the object passed in, this will record its ACL (if any) and the ACLs of
5557  * any sub-objects (eg: columns) into pg_init_privs.
5558  *
5559  * Any new kinds of objects which have ACLs associated with them and can be
5560  * added to an extension should be added to the if-else tree below.
5561  */
5562 void
recordExtObjInitPriv(Oid objoid,Oid classoid)5563 recordExtObjInitPriv(Oid objoid, Oid classoid)
5564 {
5565 	/*
5566 	 * pg_class / pg_attribute
5567 	 *
5568 	 * If this is a relation then we need to see if there are any sub-objects
5569 	 * (eg: columns) for it and, if so, be sure to call
5570 	 * recordExtensionInitPrivWorker() for each one.
5571 	 */
5572 	if (classoid == RelationRelationId)
5573 	{
5574 		Form_pg_class pg_class_tuple;
5575 		Datum		aclDatum;
5576 		bool		isNull;
5577 		HeapTuple	tuple;
5578 
5579 		tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
5580 		if (!HeapTupleIsValid(tuple))
5581 			elog(ERROR, "cache lookup failed for relation %u", objoid);
5582 		pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
5583 
5584 		/* Indexes don't have permissions */
5585 		if (pg_class_tuple->relkind == RELKIND_INDEX ||
5586 			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
5587 			return;
5588 
5589 		/* Composite types don't have permissions either */
5590 		if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
5591 			return;
5592 
5593 		/*
5594 		 * If this isn't a sequence, index, or composite type then it's
5595 		 * possibly going to have columns associated with it that might have
5596 		 * ACLs.
5597 		 */
5598 		if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
5599 		{
5600 			AttrNumber	curr_att;
5601 			AttrNumber	nattrs = pg_class_tuple->relnatts;
5602 
5603 			for (curr_att = 1; curr_att <= nattrs; curr_att++)
5604 			{
5605 				HeapTuple	attTuple;
5606 				Datum		attaclDatum;
5607 
5608 				attTuple = SearchSysCache2(ATTNUM,
5609 										   ObjectIdGetDatum(objoid),
5610 										   Int16GetDatum(curr_att));
5611 
5612 				if (!HeapTupleIsValid(attTuple))
5613 					continue;
5614 
5615 				/* ignore dropped columns */
5616 				if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
5617 				{
5618 					ReleaseSysCache(attTuple);
5619 					continue;
5620 				}
5621 
5622 				attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
5623 											  Anum_pg_attribute_attacl,
5624 											  &isNull);
5625 
5626 				/* no need to do anything for a NULL ACL */
5627 				if (isNull)
5628 				{
5629 					ReleaseSysCache(attTuple);
5630 					continue;
5631 				}
5632 
5633 				recordExtensionInitPrivWorker(objoid, classoid, curr_att,
5634 											  DatumGetAclP(attaclDatum));
5635 
5636 				ReleaseSysCache(attTuple);
5637 			}
5638 		}
5639 
5640 		aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
5641 								   &isNull);
5642 
5643 		/* Add the record, if any, for the top-level object */
5644 		if (!isNull)
5645 			recordExtensionInitPrivWorker(objoid, classoid, 0,
5646 										  DatumGetAclP(aclDatum));
5647 
5648 		ReleaseSysCache(tuple);
5649 	}
5650 	/* pg_foreign_data_wrapper */
5651 	else if (classoid == ForeignDataWrapperRelationId)
5652 	{
5653 		Datum		aclDatum;
5654 		bool		isNull;
5655 		HeapTuple	tuple;
5656 
5657 		tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
5658 								ObjectIdGetDatum(objoid));
5659 		if (!HeapTupleIsValid(tuple))
5660 			elog(ERROR, "cache lookup failed for foreign data wrapper %u",
5661 				 objoid);
5662 
5663 		aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
5664 								   Anum_pg_foreign_data_wrapper_fdwacl,
5665 								   &isNull);
5666 
5667 		/* Add the record, if any, for the top-level object */
5668 		if (!isNull)
5669 			recordExtensionInitPrivWorker(objoid, classoid, 0,
5670 										  DatumGetAclP(aclDatum));
5671 
5672 		ReleaseSysCache(tuple);
5673 	}
5674 	/* pg_foreign_server */
5675 	else if (classoid == ForeignServerRelationId)
5676 	{
5677 		Datum		aclDatum;
5678 		bool		isNull;
5679 		HeapTuple	tuple;
5680 
5681 		tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(objoid));
5682 		if (!HeapTupleIsValid(tuple))
5683 			elog(ERROR, "cache lookup failed for foreign data wrapper %u",
5684 				 objoid);
5685 
5686 		aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
5687 								   Anum_pg_foreign_server_srvacl,
5688 								   &isNull);
5689 
5690 		/* Add the record, if any, for the top-level object */
5691 		if (!isNull)
5692 			recordExtensionInitPrivWorker(objoid, classoid, 0,
5693 										  DatumGetAclP(aclDatum));
5694 
5695 		ReleaseSysCache(tuple);
5696 	}
5697 	/* pg_language */
5698 	else if (classoid == LanguageRelationId)
5699 	{
5700 		Datum		aclDatum;
5701 		bool		isNull;
5702 		HeapTuple	tuple;
5703 
5704 		tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(objoid));
5705 		if (!HeapTupleIsValid(tuple))
5706 			elog(ERROR, "cache lookup failed for language %u", objoid);
5707 
5708 		aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
5709 								   &isNull);
5710 
5711 		/* Add the record, if any, for the top-level object */
5712 		if (!isNull)
5713 			recordExtensionInitPrivWorker(objoid, classoid, 0,
5714 										  DatumGetAclP(aclDatum));
5715 
5716 		ReleaseSysCache(tuple);
5717 	}
5718 	/* pg_largeobject_metadata */
5719 	else if (classoid == LargeObjectMetadataRelationId)
5720 	{
5721 		Datum		aclDatum;
5722 		bool		isNull;
5723 		HeapTuple	tuple;
5724 		ScanKeyData entry[1];
5725 		SysScanDesc scan;
5726 		Relation	relation;
5727 
5728 		relation = heap_open(LargeObjectMetadataRelationId, RowExclusiveLock);
5729 
5730 		/* There's no syscache for pg_largeobject_metadata */
5731 		ScanKeyInit(&entry[0],
5732 					ObjectIdAttributeNumber,
5733 					BTEqualStrategyNumber, F_OIDEQ,
5734 					ObjectIdGetDatum(objoid));
5735 
5736 		scan = systable_beginscan(relation,
5737 								  LargeObjectMetadataOidIndexId, true,
5738 								  NULL, 1, entry);
5739 
5740 		tuple = systable_getnext(scan);
5741 		if (!HeapTupleIsValid(tuple))
5742 			elog(ERROR, "could not find tuple for large object %u", objoid);
5743 
5744 		aclDatum = heap_getattr(tuple,
5745 								Anum_pg_largeobject_metadata_lomacl,
5746 								RelationGetDescr(relation), &isNull);
5747 
5748 		/* Add the record, if any, for the top-level object */
5749 		if (!isNull)
5750 			recordExtensionInitPrivWorker(objoid, classoid, 0,
5751 										  DatumGetAclP(aclDatum));
5752 
5753 		systable_endscan(scan);
5754 	}
5755 	/* pg_namespace */
5756 	else if (classoid == NamespaceRelationId)
5757 	{
5758 		Datum		aclDatum;
5759 		bool		isNull;
5760 		HeapTuple	tuple;
5761 
5762 		tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(objoid));
5763 		if (!HeapTupleIsValid(tuple))
5764 			elog(ERROR, "cache lookup failed for function %u", objoid);
5765 
5766 		aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple,
5767 								   Anum_pg_namespace_nspacl, &isNull);
5768 
5769 		/* Add the record, if any, for the top-level object */
5770 		if (!isNull)
5771 			recordExtensionInitPrivWorker(objoid, classoid, 0,
5772 										  DatumGetAclP(aclDatum));
5773 
5774 		ReleaseSysCache(tuple);
5775 	}
5776 	/* pg_proc */
5777 	else if (classoid == ProcedureRelationId)
5778 	{
5779 		Datum		aclDatum;
5780 		bool		isNull;
5781 		HeapTuple	tuple;
5782 
5783 		tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(objoid));
5784 		if (!HeapTupleIsValid(tuple))
5785 			elog(ERROR, "cache lookup failed for function %u", objoid);
5786 
5787 		aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
5788 								   &isNull);
5789 
5790 		/* Add the record, if any, for the top-level object */
5791 		if (!isNull)
5792 			recordExtensionInitPrivWorker(objoid, classoid, 0,
5793 										  DatumGetAclP(aclDatum));
5794 
5795 		ReleaseSysCache(tuple);
5796 	}
5797 	/* pg_type */
5798 	else if (classoid == TypeRelationId)
5799 	{
5800 		Datum		aclDatum;
5801 		bool		isNull;
5802 		HeapTuple	tuple;
5803 
5804 		tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(objoid));
5805 		if (!HeapTupleIsValid(tuple))
5806 			elog(ERROR, "cache lookup failed for function %u", objoid);
5807 
5808 		aclDatum = SysCacheGetAttr(TYPEOID, tuple, Anum_pg_type_typacl,
5809 								   &isNull);
5810 
5811 		/* Add the record, if any, for the top-level object */
5812 		if (!isNull)
5813 			recordExtensionInitPrivWorker(objoid, classoid, 0,
5814 										  DatumGetAclP(aclDatum));
5815 
5816 		ReleaseSysCache(tuple);
5817 	}
5818 	else if (classoid == AccessMethodRelationId ||
5819 			 classoid == AggregateRelationId ||
5820 			 classoid == CastRelationId ||
5821 			 classoid == CollationRelationId ||
5822 			 classoid == ConversionRelationId ||
5823 			 classoid == EventTriggerRelationId ||
5824 			 classoid == OperatorRelationId ||
5825 			 classoid == OperatorClassRelationId ||
5826 			 classoid == OperatorFamilyRelationId ||
5827 			 classoid == NamespaceRelationId ||
5828 			 classoid == TSConfigRelationId ||
5829 			 classoid == TSDictionaryRelationId ||
5830 			 classoid == TSParserRelationId ||
5831 			 classoid == TSTemplateRelationId ||
5832 			 classoid == TransformRelationId
5833 		)
5834 	{
5835 		/* no ACL for these object types, so do nothing. */
5836 	}
5837 
5838 	/*
5839 	 * complain if we are given a class OID for a class that extensions don't
5840 	 * support or that we don't recognize.
5841 	 */
5842 	else
5843 	{
5844 		elog(ERROR, "unrecognized or unsupported class OID: %u", classoid);
5845 	}
5846 }
5847 
5848 /*
5849  * For the object passed in, remove its ACL and the ACLs of any object subIds
5850  * from pg_init_privs (via recordExtensionInitPrivWorker()).
5851  */
5852 void
removeExtObjInitPriv(Oid objoid,Oid classoid)5853 removeExtObjInitPriv(Oid objoid, Oid classoid)
5854 {
5855 	/*
5856 	 * If this is a relation then we need to see if there are any sub-objects
5857 	 * (eg: columns) for it and, if so, be sure to call
5858 	 * recordExtensionInitPrivWorker() for each one.
5859 	 */
5860 	if (classoid == RelationRelationId)
5861 	{
5862 		Form_pg_class pg_class_tuple;
5863 		HeapTuple	tuple;
5864 
5865 		tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
5866 		if (!HeapTupleIsValid(tuple))
5867 			elog(ERROR, "cache lookup failed for relation %u", objoid);
5868 		pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
5869 
5870 		/* Indexes don't have permissions */
5871 		if (pg_class_tuple->relkind == RELKIND_INDEX ||
5872 			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
5873 			return;
5874 
5875 		/* Composite types don't have permissions either */
5876 		if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
5877 			return;
5878 
5879 		/*
5880 		 * If this isn't a sequence, index, or composite type then it's
5881 		 * possibly going to have columns associated with it that might have
5882 		 * ACLs.
5883 		 */
5884 		if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
5885 		{
5886 			AttrNumber	curr_att;
5887 			AttrNumber	nattrs = pg_class_tuple->relnatts;
5888 
5889 			for (curr_att = 1; curr_att <= nattrs; curr_att++)
5890 			{
5891 				HeapTuple	attTuple;
5892 
5893 				attTuple = SearchSysCache2(ATTNUM,
5894 										   ObjectIdGetDatum(objoid),
5895 										   Int16GetDatum(curr_att));
5896 
5897 				if (!HeapTupleIsValid(attTuple))
5898 					continue;
5899 
5900 				/* when removing, remove all entries, even dropped columns */
5901 
5902 				recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
5903 
5904 				ReleaseSysCache(attTuple);
5905 			}
5906 		}
5907 
5908 		ReleaseSysCache(tuple);
5909 	}
5910 
5911 	/* Remove the record, if any, for the top-level object */
5912 	recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
5913 }
5914 
5915 /*
5916  * Record initial ACL for an extension object
5917  *
5918  * Can be called at any time, we check if 'creating_extension' is set and, if
5919  * not, exit immediately.
5920  *
5921  * Pass in the object OID, the OID of the class (the OID of the table which
5922  * the object is defined in) and the 'sub' id of the object (objsubid), if
5923  * any.  If there is no 'sub' id (they are currently only used for columns of
5924  * tables) then pass in '0'.  Finally, pass in the complete ACL to store.
5925  *
5926  * If an ACL already exists for this object/sub-object then we will replace
5927  * it with what is passed in.
5928  *
5929  * Passing in NULL for 'new_acl' will result in the entry for the object being
5930  * removed, if one is found.
5931  */
5932 static void
recordExtensionInitPriv(Oid objoid,Oid classoid,int objsubid,Acl * new_acl)5933 recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
5934 {
5935 	/*
5936 	 * Generally, we only record the initial privileges when an extension is
5937 	 * being created, but because we don't actually use CREATE EXTENSION
5938 	 * during binary upgrades with pg_upgrade, there is a variable to let us
5939 	 * know that the GRANT and REVOKE statements being issued, while this
5940 	 * variable is true, are for the initial privileges of the extension
5941 	 * object and therefore we need to record them.
5942 	 */
5943 	if (!creating_extension && !binary_upgrade_record_init_privs)
5944 		return;
5945 
5946 	recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
5947 }
5948 
5949 /*
5950  * Record initial ACL for an extension object, worker.
5951  *
5952  * This will perform a wholesale replacement of the entire ACL for the object
5953  * passed in, therefore be sure to pass in the complete new ACL to use.
5954  *
5955  * Generally speaking, do *not* use this function directly but instead use
5956  * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
5957  * This function does *not* check if 'creating_extension' is set as it is also
5958  * used when an object is added to or removed from an extension via ALTER
5959  * EXTENSION ... ADD/DROP.
5960  */
5961 static void
recordExtensionInitPrivWorker(Oid objoid,Oid classoid,int objsubid,Acl * new_acl)5962 recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
5963 {
5964 	Relation	relation;
5965 	ScanKeyData key[3];
5966 	SysScanDesc scan;
5967 	HeapTuple	tuple;
5968 	HeapTuple	oldtuple;
5969 
5970 	relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
5971 
5972 	ScanKeyInit(&key[0],
5973 				Anum_pg_init_privs_objoid,
5974 				BTEqualStrategyNumber, F_OIDEQ,
5975 				ObjectIdGetDatum(objoid));
5976 	ScanKeyInit(&key[1],
5977 				Anum_pg_init_privs_classoid,
5978 				BTEqualStrategyNumber, F_OIDEQ,
5979 				ObjectIdGetDatum(classoid));
5980 	ScanKeyInit(&key[2],
5981 				Anum_pg_init_privs_objsubid,
5982 				BTEqualStrategyNumber, F_INT4EQ,
5983 				Int32GetDatum(objsubid));
5984 
5985 	scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
5986 							  NULL, 3, key);
5987 
5988 	/* There should exist only one entry or none. */
5989 	oldtuple = systable_getnext(scan);
5990 
5991 	/* If we find an entry, update it with the latest ACL. */
5992 	if (HeapTupleIsValid(oldtuple))
5993 	{
5994 		Datum		values[Natts_pg_init_privs];
5995 		bool		nulls[Natts_pg_init_privs];
5996 		bool		replace[Natts_pg_init_privs];
5997 
5998 		/* If we have a new ACL to set, then update the row with it. */
5999 		if (new_acl)
6000 		{
6001 			MemSet(values, 0, sizeof(values));
6002 			MemSet(nulls, false, sizeof(nulls));
6003 			MemSet(replace, false, sizeof(replace));
6004 
6005 			values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
6006 			replace[Anum_pg_init_privs_initprivs - 1] = true;
6007 
6008 			oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
6009 										 values, nulls, replace);
6010 
6011 			CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
6012 		}
6013 		else
6014 		{
6015 			/* new_acl is NULL, so delete the entry we found. */
6016 			CatalogTupleDelete(relation, &oldtuple->t_self);
6017 		}
6018 	}
6019 	else
6020 	{
6021 		Datum		values[Natts_pg_init_privs];
6022 		bool		nulls[Natts_pg_init_privs];
6023 
6024 		/*
6025 		 * Only add a new entry if the new ACL is non-NULL.
6026 		 *
6027 		 * If we are passed in a NULL ACL and no entry exists, we can just
6028 		 * fall through and do nothing.
6029 		 */
6030 		if (new_acl)
6031 		{
6032 			/* No entry found, so add it. */
6033 			MemSet(nulls, false, sizeof(nulls));
6034 
6035 			values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
6036 			values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
6037 			values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
6038 
6039 			/* This function only handles initial privileges of extensions */
6040 			values[Anum_pg_init_privs_privtype - 1] =
6041 				CharGetDatum(INITPRIVS_EXTENSION);
6042 
6043 			values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
6044 
6045 			tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
6046 
6047 			CatalogTupleInsert(relation, tuple);
6048 		}
6049 	}
6050 
6051 	systable_endscan(scan);
6052 
6053 	/* prevent error when processing objects multiple times */
6054 	CommandCounterIncrement();
6055 
6056 	heap_close(relation, RowExclusiveLock);
6057 }
6058