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