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