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