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