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