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