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