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