Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * aclchk.c
4 : * Routines to check access control permissions.
5 : *
6 : * Portions Copyright (c) 1996-2025, 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 : * The xxx_aclmask() functions in this file are wrappers around
17 : * acl.c's aclmask() function; see that for basic usage information.
18 : * The wrapper functions add object-type-specific lookup capability.
19 : * Generally, they will throw error if the object doesn't exist.
20 : *
21 : * The xxx_aclmask_ext() functions add the ability to not throw
22 : * error if the object doesn't exist. If their "is_missing" argument
23 : * isn't NULL, then when the object isn't found they will set
24 : * *is_missing = true and return zero (no privileges) instead of
25 : * throwing an error. Caller must initialize *is_missing = false.
26 : *
27 : * The xxx_aclcheck() functions are simplified wrappers around the
28 : * corresponding xxx_aclmask() functions, simply returning ACLCHECK_OK
29 : * if any of the privileges specified in "mode" are held, and otherwise
30 : * a suitable error code (in practice, always ACLCHECK_NO_PRIV).
31 : * Again, they will throw error if the object doesn't exist.
32 : *
33 : * The xxx_aclcheck_ext() functions add the ability to not throw
34 : * error if the object doesn't exist. Their "is_missing" argument
35 : * works similarly to the xxx_aclmask_ext() functions.
36 : *
37 : *-------------------------------------------------------------------------
38 : */
39 : #include "postgres.h"
40 :
41 : #include "access/genam.h"
42 : #include "access/heapam.h"
43 : #include "access/htup_details.h"
44 : #include "access/sysattr.h"
45 : #include "access/tableam.h"
46 : #include "access/xact.h"
47 : #include "catalog/binary_upgrade.h"
48 : #include "catalog/catalog.h"
49 : #include "catalog/dependency.h"
50 : #include "catalog/indexing.h"
51 : #include "catalog/objectaccess.h"
52 : #include "catalog/pg_authid.h"
53 : #include "catalog/pg_class.h"
54 : #include "catalog/pg_database.h"
55 : #include "catalog/pg_default_acl.h"
56 : #include "catalog/pg_foreign_data_wrapper.h"
57 : #include "catalog/pg_foreign_server.h"
58 : #include "catalog/pg_init_privs.h"
59 : #include "catalog/pg_language.h"
60 : #include "catalog/pg_largeobject.h"
61 : #include "catalog/pg_largeobject_metadata.h"
62 : #include "catalog/pg_namespace.h"
63 : #include "catalog/pg_parameter_acl.h"
64 : #include "catalog/pg_proc.h"
65 : #include "catalog/pg_tablespace.h"
66 : #include "catalog/pg_type.h"
67 : #include "commands/defrem.h"
68 : #include "commands/event_trigger.h"
69 : #include "commands/extension.h"
70 : #include "commands/proclang.h"
71 : #include "commands/tablespace.h"
72 : #include "foreign/foreign.h"
73 : #include "miscadmin.h"
74 : #include "nodes/makefuncs.h"
75 : #include "parser/parse_func.h"
76 : #include "parser/parse_type.h"
77 : #include "storage/lmgr.h"
78 : #include "utils/acl.h"
79 : #include "utils/aclchk_internal.h"
80 : #include "utils/builtins.h"
81 : #include "utils/fmgroids.h"
82 : #include "utils/guc.h"
83 : #include "utils/lsyscache.h"
84 : #include "utils/rel.h"
85 : #include "utils/syscache.h"
86 :
87 : /*
88 : * Internal format used by ALTER DEFAULT PRIVILEGES.
89 : */
90 : typedef struct
91 : {
92 : Oid roleid; /* owning role */
93 : Oid nspid; /* namespace, or InvalidOid if none */
94 : /* remaining fields are same as in InternalGrant: */
95 : bool is_grant;
96 : ObjectType objtype;
97 : bool all_privs;
98 : AclMode privileges;
99 : List *grantees;
100 : bool grant_option;
101 : DropBehavior behavior;
102 : } InternalDefaultACL;
103 :
104 : /*
105 : * When performing a binary-upgrade, pg_dump will call a function to set
106 : * this variable to let us know that we need to populate the pg_init_privs
107 : * table for the GRANT/REVOKE commands while this variable is set to true.
108 : */
109 : bool binary_upgrade_record_init_privs = false;
110 :
111 : static void ExecGrantStmt_oids(InternalGrant *istmt);
112 : static void ExecGrant_Relation(InternalGrant *istmt);
113 : static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
114 : void (*object_check) (InternalGrant *istmt, HeapTuple tuple));
115 : static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple);
116 : static void ExecGrant_Largeobject(InternalGrant *istmt);
117 : static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple);
118 : static void ExecGrant_Parameter(InternalGrant *istmt);
119 :
120 : static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
121 : static void SetDefaultACL(InternalDefaultACL *iacls);
122 :
123 : static List *objectNamesToOids(ObjectType objtype, List *objnames,
124 : bool is_grant);
125 : static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
126 : static List *getRelationsInNamespace(Oid namespaceId, char relkind);
127 : static void expand_col_privileges(List *colnames, Oid table_oid,
128 : AclMode this_privileges,
129 : AclMode *col_privileges,
130 : int num_col_privileges);
131 : static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
132 : AclMode this_privileges,
133 : AclMode *col_privileges,
134 : int num_col_privileges);
135 : static AclMode string_to_privilege(const char *privname);
136 : static const char *privilege_to_string(AclMode privilege);
137 : static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
138 : bool all_privs, AclMode privileges,
139 : Oid objectId, Oid grantorId,
140 : ObjectType objtype, const char *objname,
141 : AttrNumber att_number, const char *colname);
142 : static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum,
143 : Oid roleid, AclMode mask, AclMaskHow how);
144 : static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid,
145 : AclMode mask, AclMaskHow how);
146 : static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
147 : AclMode mask, AclMaskHow how,
148 : bool *is_missing);
149 : static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum,
150 : Oid roleid, AclMode mask, AclMaskHow how);
151 : static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum,
152 : Oid roleid, AclMode mask,
153 : AclMaskHow how, bool *is_missing);
154 : static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid,
155 : AclMode mask, AclMaskHow how,
156 : bool *is_missing);
157 : static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
158 : AclMode mask, AclMaskHow how);
159 : static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
160 : AclMode mask, AclMaskHow how, Snapshot snapshot);
161 : static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
162 : AclMode mask, AclMaskHow how,
163 : bool *is_missing);
164 : static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid,
165 : AclMode mask, AclMaskHow how,
166 : bool *is_missing);
167 : static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
168 : Acl *new_acl);
169 : static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
170 : Acl *new_acl);
171 :
172 :
173 : /*
174 : * If is_grant is true, adds the given privileges for the list of
175 : * grantees to the existing old_acl. If is_grant is false, the
176 : * privileges for the given grantees are removed from old_acl.
177 : *
178 : * NB: the original old_acl is pfree'd.
179 : */
180 : static Acl *
181 79866 : merge_acl_with_grant(Acl *old_acl, bool is_grant,
182 : bool grant_option, DropBehavior behavior,
183 : List *grantees, AclMode privileges,
184 : Oid grantorId, Oid ownerId)
185 : {
186 : unsigned modechg;
187 : ListCell *j;
188 : Acl *new_acl;
189 :
190 79866 : modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
191 :
192 79866 : new_acl = old_acl;
193 :
194 159852 : foreach(j, grantees)
195 : {
196 : AclItem aclitem;
197 : Acl *newer_acl;
198 :
199 79998 : aclitem.ai_grantee = lfirst_oid(j);
200 :
201 : /*
202 : * Grant options can only be granted to individual roles, not PUBLIC.
203 : * The reason is that if a user would re-grant a privilege that he
204 : * held through PUBLIC, and later the user is removed, the situation
205 : * is impossible to clean up.
206 : */
207 79998 : if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
208 0 : ereport(ERROR,
209 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
210 : errmsg("grant options can only be granted to roles")));
211 :
212 79998 : aclitem.ai_grantor = grantorId;
213 :
214 : /*
215 : * The asymmetry in the conditions here comes from the spec. In
216 : * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
217 : * to grant both the basic privilege and its grant option. But in
218 : * REVOKE, plain revoke revokes both the basic privilege and its grant
219 : * option, while REVOKE GRANT OPTION revokes only the option.
220 : */
221 79998 : ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
222 : (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
223 : (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
224 :
225 79998 : newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
226 :
227 : /* avoid memory leak when there are many grantees */
228 79986 : pfree(new_acl);
229 79986 : new_acl = newer_acl;
230 : }
231 :
232 79854 : return new_acl;
233 : }
234 :
235 : /*
236 : * Restrict the privileges to what we can actually grant, and emit
237 : * the standards-mandated warning and error messages.
238 : */
239 : static AclMode
240 79638 : restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
241 : AclMode privileges, Oid objectId, Oid grantorId,
242 : ObjectType objtype, const char *objname,
243 : AttrNumber att_number, const char *colname)
244 : {
245 : AclMode this_privileges;
246 : AclMode whole_mask;
247 :
248 79638 : switch (objtype)
249 : {
250 50432 : case OBJECT_COLUMN:
251 50432 : whole_mask = ACL_ALL_RIGHTS_COLUMN;
252 50432 : break;
253 18590 : case OBJECT_TABLE:
254 18590 : whole_mask = ACL_ALL_RIGHTS_RELATION;
255 18590 : break;
256 174 : case OBJECT_SEQUENCE:
257 174 : whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
258 174 : break;
259 356 : case OBJECT_DATABASE:
260 356 : whole_mask = ACL_ALL_RIGHTS_DATABASE;
261 356 : break;
262 9030 : case OBJECT_FUNCTION:
263 9030 : whole_mask = ACL_ALL_RIGHTS_FUNCTION;
264 9030 : break;
265 36 : case OBJECT_LANGUAGE:
266 36 : whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
267 36 : break;
268 80 : case OBJECT_LARGEOBJECT:
269 80 : whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
270 80 : break;
271 478 : case OBJECT_SCHEMA:
272 478 : whole_mask = ACL_ALL_RIGHTS_SCHEMA;
273 478 : break;
274 6 : case OBJECT_TABLESPACE:
275 6 : whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
276 6 : break;
277 94 : case OBJECT_FDW:
278 94 : whole_mask = ACL_ALL_RIGHTS_FDW;
279 94 : break;
280 102 : case OBJECT_FOREIGN_SERVER:
281 102 : whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
282 102 : break;
283 0 : case OBJECT_EVENT_TRIGGER:
284 0 : elog(ERROR, "grantable rights not supported for event triggers");
285 : /* not reached, but keep compiler quiet */
286 : return ACL_NO_RIGHTS;
287 126 : case OBJECT_TYPE:
288 126 : whole_mask = ACL_ALL_RIGHTS_TYPE;
289 126 : break;
290 134 : case OBJECT_PARAMETER_ACL:
291 134 : whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
292 134 : break;
293 0 : default:
294 0 : elog(ERROR, "unrecognized object type: %d", objtype);
295 : /* not reached, but keep compiler quiet */
296 : return ACL_NO_RIGHTS;
297 : }
298 :
299 : /*
300 : * If we found no grant options, consider whether to issue a hard error.
301 : * Per spec, having any privilege at all on the object will get you by
302 : * here.
303 : */
304 79638 : if (avail_goptions == ACL_NO_RIGHTS)
305 : {
306 72 : if (pg_aclmask(objtype, objectId, att_number, grantorId,
307 72 : whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
308 : ACLMASK_ANY) == ACL_NO_RIGHTS)
309 : {
310 36 : if (objtype == OBJECT_COLUMN && colname)
311 0 : aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
312 : else
313 36 : aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
314 : }
315 : }
316 :
317 : /*
318 : * Restrict the operation to what we can actually grant or revoke, and
319 : * issue a warning if appropriate. (For REVOKE this isn't quite what the
320 : * spec says to do: the spec seems to want a warning only if no privilege
321 : * bits actually change in the ACL. In practice that behavior seems much
322 : * too noisy, as well as inconsistent with the GRANT case.)
323 : */
324 79602 : this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
325 79602 : if (is_grant)
326 : {
327 17310 : if (this_privileges == 0)
328 : {
329 30 : if (objtype == OBJECT_COLUMN && colname)
330 0 : ereport(WARNING,
331 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
332 : errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
333 : colname, objname)));
334 : else
335 30 : ereport(WARNING,
336 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
337 : errmsg("no privileges were granted for \"%s\"",
338 : objname)));
339 : }
340 17280 : else if (!all_privs && this_privileges != privileges)
341 : {
342 6 : if (objtype == OBJECT_COLUMN && colname)
343 0 : ereport(WARNING,
344 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
345 : errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
346 : colname, objname)));
347 : else
348 6 : ereport(WARNING,
349 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
350 : errmsg("not all privileges were granted for \"%s\"",
351 : objname)));
352 : }
353 : }
354 : else
355 : {
356 62292 : if (this_privileges == 0)
357 : {
358 6 : if (objtype == OBJECT_COLUMN && colname)
359 0 : ereport(WARNING,
360 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
361 : errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
362 : colname, objname)));
363 : else
364 6 : ereport(WARNING,
365 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
366 : errmsg("no privileges could be revoked for \"%s\"",
367 : objname)));
368 : }
369 62286 : else if (!all_privs && this_privileges != privileges)
370 : {
371 0 : if (objtype == OBJECT_COLUMN && colname)
372 0 : ereport(WARNING,
373 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
374 : errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
375 : colname, objname)));
376 : else
377 0 : ereport(WARNING,
378 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
379 : errmsg("not all privileges could be revoked for \"%s\"",
380 : objname)));
381 : }
382 : }
383 :
384 79602 : return this_privileges;
385 : }
386 :
387 : /*
388 : * Called to execute the utility commands GRANT and REVOKE
389 : */
390 : void
391 29238 : ExecuteGrantStmt(GrantStmt *stmt)
392 : {
393 : InternalGrant istmt;
394 : ListCell *cell;
395 : const char *errormsg;
396 : AclMode all_privileges;
397 :
398 29238 : if (stmt->grantor)
399 : {
400 : Oid grantor;
401 :
402 18 : grantor = get_rolespec_oid(stmt->grantor, false);
403 :
404 : /*
405 : * Currently, this clause is only for SQL compatibility, not very
406 : * interesting otherwise.
407 : */
408 18 : if (grantor != GetUserId())
409 6 : ereport(ERROR,
410 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
411 : errmsg("grantor must be current user")));
412 : }
413 :
414 : /*
415 : * Turn the regular GrantStmt into the InternalGrant form.
416 : */
417 29232 : istmt.is_grant = stmt->is_grant;
418 29232 : istmt.objtype = stmt->objtype;
419 :
420 : /* Collect the OIDs of the target objects */
421 29232 : switch (stmt->targtype)
422 : {
423 29202 : case ACL_TARGET_OBJECT:
424 58372 : istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
425 29202 : stmt->is_grant);
426 29170 : break;
427 30 : case ACL_TARGET_ALL_IN_SCHEMA:
428 30 : istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
429 30 : break;
430 : /* ACL_TARGET_DEFAULTS should not be seen here */
431 0 : default:
432 0 : elog(ERROR, "unrecognized GrantStmt.targtype: %d",
433 : (int) stmt->targtype);
434 : }
435 :
436 : /* all_privs to be filled below */
437 : /* privileges to be filled below */
438 29200 : istmt.col_privs = NIL; /* may get filled below */
439 29200 : istmt.grantees = NIL; /* filled below */
440 29200 : istmt.grant_option = stmt->grant_option;
441 29200 : istmt.behavior = stmt->behavior;
442 :
443 : /*
444 : * Convert the RoleSpec list into an Oid list. Note that at this point we
445 : * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
446 : * there shouldn't be any additional work needed to support this case.
447 : */
448 58496 : foreach(cell, stmt->grantees)
449 : {
450 29302 : RoleSpec *grantee = (RoleSpec *) lfirst(cell);
451 : Oid grantee_uid;
452 :
453 29302 : switch (grantee->roletype)
454 : {
455 24604 : case ROLESPEC_PUBLIC:
456 24604 : grantee_uid = ACL_ID_PUBLIC;
457 24604 : break;
458 4698 : default:
459 4698 : grantee_uid = get_rolespec_oid(grantee, false);
460 4692 : break;
461 : }
462 29296 : istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
463 : }
464 :
465 : /*
466 : * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
467 : * bitmask. Note: objtype can't be OBJECT_COLUMN.
468 : */
469 29194 : switch (stmt->objtype)
470 : {
471 19002 : case OBJECT_TABLE:
472 :
473 : /*
474 : * Because this might be a sequence, we test both relation and
475 : * sequence bits, and later do a more limited test when we know
476 : * the object type.
477 : */
478 19002 : all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
479 19002 : errormsg = gettext_noop("invalid privilege type %s for relation");
480 19002 : break;
481 22 : case OBJECT_SEQUENCE:
482 22 : all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
483 22 : errormsg = gettext_noop("invalid privilege type %s for sequence");
484 22 : break;
485 346 : case OBJECT_DATABASE:
486 346 : all_privileges = ACL_ALL_RIGHTS_DATABASE;
487 346 : errormsg = gettext_noop("invalid privilege type %s for database");
488 346 : break;
489 20 : case OBJECT_DOMAIN:
490 20 : all_privileges = ACL_ALL_RIGHTS_TYPE;
491 20 : errormsg = gettext_noop("invalid privilege type %s for domain");
492 20 : break;
493 8914 : case OBJECT_FUNCTION:
494 8914 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
495 8914 : errormsg = gettext_noop("invalid privilege type %s for function");
496 8914 : break;
497 42 : case OBJECT_LANGUAGE:
498 42 : all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
499 42 : errormsg = gettext_noop("invalid privilege type %s for language");
500 42 : break;
501 62 : case OBJECT_LARGEOBJECT:
502 62 : all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
503 62 : errormsg = gettext_noop("invalid privilege type %s for large object");
504 62 : break;
505 362 : case OBJECT_SCHEMA:
506 362 : all_privileges = ACL_ALL_RIGHTS_SCHEMA;
507 362 : errormsg = gettext_noop("invalid privilege type %s for schema");
508 362 : break;
509 48 : case OBJECT_PROCEDURE:
510 48 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
511 48 : errormsg = gettext_noop("invalid privilege type %s for procedure");
512 48 : break;
513 6 : case OBJECT_ROUTINE:
514 6 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
515 6 : errormsg = gettext_noop("invalid privilege type %s for routine");
516 6 : break;
517 6 : case OBJECT_TABLESPACE:
518 6 : all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
519 6 : errormsg = gettext_noop("invalid privilege type %s for tablespace");
520 6 : break;
521 112 : case OBJECT_TYPE:
522 112 : all_privileges = ACL_ALL_RIGHTS_TYPE;
523 112 : errormsg = gettext_noop("invalid privilege type %s for type");
524 112 : break;
525 92 : case OBJECT_FDW:
526 92 : all_privileges = ACL_ALL_RIGHTS_FDW;
527 92 : errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
528 92 : break;
529 88 : case OBJECT_FOREIGN_SERVER:
530 88 : all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
531 88 : errormsg = gettext_noop("invalid privilege type %s for foreign server");
532 88 : break;
533 72 : case OBJECT_PARAMETER_ACL:
534 72 : all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
535 72 : errormsg = gettext_noop("invalid privilege type %s for parameter");
536 72 : break;
537 0 : default:
538 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
539 : (int) stmt->objtype);
540 : /* keep compiler quiet */
541 : all_privileges = ACL_NO_RIGHTS;
542 : errormsg = NULL;
543 : }
544 :
545 29194 : if (stmt->privileges == NIL)
546 : {
547 2710 : istmt.all_privs = true;
548 :
549 : /*
550 : * will be turned into ACL_ALL_RIGHTS_* by the internal routines
551 : * depending on the object type
552 : */
553 2710 : istmt.privileges = ACL_NO_RIGHTS;
554 : }
555 : else
556 : {
557 26484 : istmt.all_privs = false;
558 26484 : istmt.privileges = ACL_NO_RIGHTS;
559 :
560 53480 : foreach(cell, stmt->privileges)
561 : {
562 27020 : AccessPriv *privnode = (AccessPriv *) lfirst(cell);
563 : AclMode priv;
564 :
565 : /*
566 : * If it's a column-level specification, we just set it aside in
567 : * col_privs for the moment; but insist it's for a relation.
568 : */
569 27020 : if (privnode->cols)
570 : {
571 442 : if (stmt->objtype != OBJECT_TABLE)
572 0 : ereport(ERROR,
573 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
574 : errmsg("column privileges are only valid for relations")));
575 442 : istmt.col_privs = lappend(istmt.col_privs, privnode);
576 442 : continue;
577 : }
578 :
579 26578 : if (privnode->priv_name == NULL) /* parser mistake? */
580 0 : elog(ERROR, "AccessPriv node must specify privilege or columns");
581 26578 : priv = string_to_privilege(privnode->priv_name);
582 :
583 26578 : if (priv & ~((AclMode) all_privileges))
584 24 : ereport(ERROR,
585 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
586 : errmsg(errormsg, privilege_to_string(priv))));
587 :
588 26554 : istmt.privileges |= priv;
589 : }
590 : }
591 :
592 29170 : ExecGrantStmt_oids(&istmt);
593 29098 : }
594 :
595 : /*
596 : * ExecGrantStmt_oids
597 : *
598 : * Internal entry point for granting and revoking privileges.
599 : */
600 : static void
601 29396 : ExecGrantStmt_oids(InternalGrant *istmt)
602 : {
603 29396 : switch (istmt->objtype)
604 : {
605 19124 : case OBJECT_TABLE:
606 : case OBJECT_SEQUENCE:
607 19124 : ExecGrant_Relation(istmt);
608 19106 : break;
609 356 : case OBJECT_DATABASE:
610 356 : ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
611 356 : break;
612 138 : case OBJECT_DOMAIN:
613 : case OBJECT_TYPE:
614 138 : ExecGrant_common(istmt, TypeRelationId, ACL_ALL_RIGHTS_TYPE, ExecGrant_Type_check);
615 120 : break;
616 94 : case OBJECT_FDW:
617 94 : ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
618 76 : break;
619 102 : case OBJECT_FOREIGN_SERVER:
620 102 : ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
621 90 : break;
622 8988 : case OBJECT_FUNCTION:
623 : case OBJECT_PROCEDURE:
624 : case OBJECT_ROUTINE:
625 8988 : ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
626 8988 : break;
627 42 : case OBJECT_LANGUAGE:
628 42 : ExecGrant_common(istmt, LanguageRelationId, ACL_ALL_RIGHTS_LANGUAGE, ExecGrant_Language_check);
629 36 : break;
630 74 : case OBJECT_LARGEOBJECT:
631 74 : ExecGrant_Largeobject(istmt);
632 74 : break;
633 376 : case OBJECT_SCHEMA:
634 376 : ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
635 376 : break;
636 6 : case OBJECT_TABLESPACE:
637 6 : ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
638 6 : break;
639 96 : case OBJECT_PARAMETER_ACL:
640 96 : ExecGrant_Parameter(istmt);
641 96 : break;
642 0 : default:
643 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
644 : (int) istmt->objtype);
645 : }
646 :
647 : /*
648 : * Pass the info to event triggers about the just-executed GRANT. Note
649 : * that we prefer to do it after actually executing it, because that gives
650 : * the functions a chance to adjust the istmt with privileges actually
651 : * granted.
652 : */
653 29324 : if (EventTriggerSupportsObjectType(istmt->objtype))
654 28866 : EventTriggerCollectGrant(istmt);
655 29324 : }
656 :
657 : /*
658 : * objectNamesToOids
659 : *
660 : * Turn a list of object names of a given type into an Oid list.
661 : *
662 : * XXX This function intentionally takes only an AccessShareLock. In the face
663 : * of concurrent DDL, we might easily latch onto an old version of an object,
664 : * causing the GRANT or REVOKE statement to fail. But it does prevent the
665 : * object from disappearing altogether. To do better, we would need to use a
666 : * self-exclusive lock, perhaps ShareUpdateExclusiveLock, here and before
667 : * *every* CatalogTupleUpdate() of a row that GRANT/REVOKE can affect.
668 : * Besides that additional work, this could have operational costs. For
669 : * example, it would make GRANT ALL TABLES IN SCHEMA terminate every
670 : * autovacuum running in the schema and consume a shared lock table entry per
671 : * table in the schema. The user-visible benefit of that additional work is
672 : * just changing "ERROR: tuple concurrently updated" to blocking. That's not
673 : * nothing, but it might not outweigh autovacuum termination and lock table
674 : * consumption spikes.
675 : */
676 : static List *
677 29202 : objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
678 : {
679 29202 : List *objects = NIL;
680 : ListCell *cell;
681 29202 : const LOCKMODE lockmode = AccessShareLock;
682 :
683 : Assert(objnames != NIL);
684 :
685 29202 : switch (objtype)
686 : {
687 9978 : default:
688 :
689 : /*
690 : * For most object types, we use get_object_address() directly.
691 : */
692 20064 : foreach(cell, objnames)
693 : {
694 : ObjectAddress address;
695 :
696 10110 : address = get_object_address(objtype, lfirst(cell), NULL, lockmode, false);
697 10086 : objects = lappend_oid(objects, address.objectId);
698 : }
699 9954 : break;
700 :
701 19012 : case OBJECT_TABLE:
702 : case OBJECT_SEQUENCE:
703 :
704 : /*
705 : * Here, we don't use get_object_address(). It requires that the
706 : * specified object type match the actual type of the object, but
707 : * in GRANT/REVOKE, all table-like things are addressed as TABLE.
708 : */
709 38078 : foreach(cell, objnames)
710 : {
711 19066 : RangeVar *relvar = (RangeVar *) lfirst(cell);
712 : Oid relOid;
713 :
714 19066 : relOid = RangeVarGetRelid(relvar, lockmode, false);
715 19066 : objects = lappend_oid(objects, relOid);
716 : }
717 19012 : break;
718 :
719 138 : case OBJECT_DOMAIN:
720 : case OBJECT_TYPE:
721 :
722 : /*
723 : * The parse representation of types and domains in privilege
724 : * targets is different from that expected by get_object_address()
725 : * (for parse conflict reasons), so we have to do a bit of
726 : * conversion here.
727 : */
728 270 : foreach(cell, objnames)
729 : {
730 138 : List *typname = (List *) lfirst(cell);
731 138 : TypeName *tn = makeTypeNameFromNameList(typname);
732 : ObjectAddress address;
733 : Relation relation;
734 :
735 138 : address = get_object_address(objtype, (Node *) tn, &relation, lockmode, false);
736 : Assert(relation == NULL);
737 132 : objects = lappend_oid(objects, address.objectId);
738 : }
739 132 : break;
740 :
741 74 : case OBJECT_PARAMETER_ACL:
742 :
743 : /*
744 : * Parameters are handled completely differently.
745 : */
746 196 : foreach(cell, objnames)
747 : {
748 : /*
749 : * In this code we represent a GUC by the OID of its entry in
750 : * pg_parameter_acl, which we have to manufacture here if it
751 : * doesn't exist yet. (That's a hack for sure, but it avoids
752 : * messing with all the GRANT/REVOKE infrastructure that
753 : * expects to use OIDs for object identities.) However, if
754 : * this is a REVOKE, we can instead just ignore any GUCs that
755 : * don't have such an entry, as they must not have any
756 : * privileges needing removal.
757 : */
758 124 : char *parameter = strVal(lfirst(cell));
759 124 : Oid parameterId = ParameterAclLookup(parameter, true);
760 :
761 124 : if (!OidIsValid(parameterId) && is_grant)
762 : {
763 68 : parameterId = ParameterAclCreate(parameter);
764 :
765 : /*
766 : * Prevent error when processing duplicate objects, and
767 : * make this new entry visible so that ExecGrant_Parameter
768 : * can update it.
769 : */
770 66 : CommandCounterIncrement();
771 : }
772 122 : if (OidIsValid(parameterId))
773 110 : objects = lappend_oid(objects, parameterId);
774 : }
775 72 : break;
776 : }
777 :
778 29170 : return objects;
779 : }
780 :
781 : /*
782 : * objectsInSchemaToOids
783 : *
784 : * Find all objects of a given type in specified schemas, and make a list
785 : * of their Oids. We check USAGE privilege on the schemas, but there is
786 : * no privilege checking on the individual objects here.
787 : */
788 : static List *
789 30 : objectsInSchemaToOids(ObjectType objtype, List *nspnames)
790 : {
791 30 : List *objects = NIL;
792 : ListCell *cell;
793 :
794 60 : foreach(cell, nspnames)
795 : {
796 30 : char *nspname = strVal(lfirst(cell));
797 : Oid namespaceId;
798 : List *objs;
799 :
800 30 : namespaceId = LookupExplicitNamespace(nspname, false);
801 :
802 30 : switch (objtype)
803 : {
804 12 : case OBJECT_TABLE:
805 12 : objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
806 12 : objects = list_concat(objects, objs);
807 12 : objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
808 12 : objects = list_concat(objects, objs);
809 12 : objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
810 12 : objects = list_concat(objects, objs);
811 12 : objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
812 12 : objects = list_concat(objects, objs);
813 12 : objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
814 12 : objects = list_concat(objects, objs);
815 12 : break;
816 0 : case OBJECT_SEQUENCE:
817 0 : objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
818 0 : objects = list_concat(objects, objs);
819 0 : break;
820 18 : case OBJECT_FUNCTION:
821 : case OBJECT_PROCEDURE:
822 : case OBJECT_ROUTINE:
823 : {
824 : ScanKeyData key[2];
825 : int keycount;
826 : Relation rel;
827 : TableScanDesc scan;
828 : HeapTuple tuple;
829 :
830 18 : keycount = 0;
831 18 : ScanKeyInit(&key[keycount++],
832 : Anum_pg_proc_pronamespace,
833 : BTEqualStrategyNumber, F_OIDEQ,
834 : ObjectIdGetDatum(namespaceId));
835 :
836 18 : if (objtype == OBJECT_FUNCTION)
837 : /* includes aggregates and window functions */
838 6 : ScanKeyInit(&key[keycount++],
839 : Anum_pg_proc_prokind,
840 : BTEqualStrategyNumber, F_CHARNE,
841 : CharGetDatum(PROKIND_PROCEDURE));
842 12 : else if (objtype == OBJECT_PROCEDURE)
843 6 : ScanKeyInit(&key[keycount++],
844 : Anum_pg_proc_prokind,
845 : BTEqualStrategyNumber, F_CHAREQ,
846 : CharGetDatum(PROKIND_PROCEDURE));
847 :
848 18 : rel = table_open(ProcedureRelationId, AccessShareLock);
849 18 : scan = table_beginscan_catalog(rel, keycount, key);
850 :
851 54 : while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
852 : {
853 36 : Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
854 :
855 36 : objects = lappend_oid(objects, oid);
856 : }
857 :
858 18 : table_endscan(scan);
859 18 : table_close(rel, AccessShareLock);
860 : }
861 18 : break;
862 0 : default:
863 : /* should not happen */
864 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
865 : (int) objtype);
866 : }
867 : }
868 :
869 30 : return objects;
870 : }
871 :
872 : /*
873 : * getRelationsInNamespace
874 : *
875 : * Return Oid list of relations in given namespace filtered by relation kind
876 : */
877 : static List *
878 60 : getRelationsInNamespace(Oid namespaceId, char relkind)
879 : {
880 60 : List *relations = NIL;
881 : ScanKeyData key[2];
882 : Relation rel;
883 : TableScanDesc scan;
884 : HeapTuple tuple;
885 :
886 60 : ScanKeyInit(&key[0],
887 : Anum_pg_class_relnamespace,
888 : BTEqualStrategyNumber, F_OIDEQ,
889 : ObjectIdGetDatum(namespaceId));
890 60 : ScanKeyInit(&key[1],
891 : Anum_pg_class_relkind,
892 : BTEqualStrategyNumber, F_CHAREQ,
893 : CharGetDatum(relkind));
894 :
895 60 : rel = table_open(RelationRelationId, AccessShareLock);
896 60 : scan = table_beginscan_catalog(rel, 2, key);
897 :
898 84 : while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
899 : {
900 24 : Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
901 :
902 24 : relations = lappend_oid(relations, oid);
903 : }
904 :
905 60 : table_endscan(scan);
906 60 : table_close(rel, AccessShareLock);
907 :
908 60 : return relations;
909 : }
910 :
911 :
912 : /*
913 : * ALTER DEFAULT PRIVILEGES statement
914 : */
915 : void
916 206 : ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
917 : {
918 206 : GrantStmt *action = stmt->action;
919 : InternalDefaultACL iacls;
920 : ListCell *cell;
921 206 : List *rolespecs = NIL;
922 206 : List *nspnames = NIL;
923 206 : DefElem *drolespecs = NULL;
924 206 : DefElem *dnspnames = NULL;
925 : AclMode all_privileges;
926 : const char *errormsg;
927 :
928 : /* Deconstruct the "options" part of the statement */
929 350 : foreach(cell, stmt->options)
930 : {
931 144 : DefElem *defel = (DefElem *) lfirst(cell);
932 :
933 144 : if (strcmp(defel->defname, "schemas") == 0)
934 : {
935 60 : if (dnspnames)
936 0 : errorConflictingDefElem(defel, pstate);
937 60 : dnspnames = defel;
938 : }
939 84 : else if (strcmp(defel->defname, "roles") == 0)
940 : {
941 84 : if (drolespecs)
942 0 : errorConflictingDefElem(defel, pstate);
943 84 : drolespecs = defel;
944 : }
945 : else
946 0 : elog(ERROR, "option \"%s\" not recognized", defel->defname);
947 : }
948 :
949 206 : if (dnspnames)
950 60 : nspnames = (List *) dnspnames->arg;
951 206 : if (drolespecs)
952 84 : rolespecs = (List *) drolespecs->arg;
953 :
954 : /* Prepare the InternalDefaultACL representation of the statement */
955 : /* roleid to be filled below */
956 : /* nspid to be filled in SetDefaultACLsInSchemas */
957 206 : iacls.is_grant = action->is_grant;
958 206 : iacls.objtype = action->objtype;
959 : /* all_privs to be filled below */
960 : /* privileges to be filled below */
961 206 : iacls.grantees = NIL; /* filled below */
962 206 : iacls.grant_option = action->grant_option;
963 206 : iacls.behavior = action->behavior;
964 :
965 : /*
966 : * Convert the RoleSpec list into an Oid list. Note that at this point we
967 : * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
968 : * there shouldn't be any additional work needed to support this case.
969 : */
970 418 : foreach(cell, action->grantees)
971 : {
972 212 : RoleSpec *grantee = (RoleSpec *) lfirst(cell);
973 : Oid grantee_uid;
974 :
975 212 : switch (grantee->roletype)
976 : {
977 46 : case ROLESPEC_PUBLIC:
978 46 : grantee_uid = ACL_ID_PUBLIC;
979 46 : break;
980 166 : default:
981 166 : grantee_uid = get_rolespec_oid(grantee, false);
982 166 : break;
983 : }
984 212 : iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
985 : }
986 :
987 : /*
988 : * Convert action->privileges, a list of privilege strings, into an
989 : * AclMode bitmask.
990 : */
991 206 : switch (action->objtype)
992 : {
993 78 : case OBJECT_TABLE:
994 78 : all_privileges = ACL_ALL_RIGHTS_RELATION;
995 78 : errormsg = gettext_noop("invalid privilege type %s for relation");
996 78 : break;
997 6 : case OBJECT_SEQUENCE:
998 6 : all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
999 6 : errormsg = gettext_noop("invalid privilege type %s for sequence");
1000 6 : break;
1001 22 : case OBJECT_FUNCTION:
1002 22 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1003 22 : errormsg = gettext_noop("invalid privilege type %s for function");
1004 22 : break;
1005 0 : case OBJECT_PROCEDURE:
1006 0 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1007 0 : errormsg = gettext_noop("invalid privilege type %s for procedure");
1008 0 : break;
1009 0 : case OBJECT_ROUTINE:
1010 0 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1011 0 : errormsg = gettext_noop("invalid privilege type %s for routine");
1012 0 : break;
1013 34 : case OBJECT_TYPE:
1014 34 : all_privileges = ACL_ALL_RIGHTS_TYPE;
1015 34 : errormsg = gettext_noop("invalid privilege type %s for type");
1016 34 : break;
1017 36 : case OBJECT_SCHEMA:
1018 36 : all_privileges = ACL_ALL_RIGHTS_SCHEMA;
1019 36 : errormsg = gettext_noop("invalid privilege type %s for schema");
1020 36 : break;
1021 30 : case OBJECT_LARGEOBJECT:
1022 30 : all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
1023 30 : errormsg = gettext_noop("invalid privilege type %s for large object");
1024 30 : break;
1025 0 : default:
1026 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1027 : (int) action->objtype);
1028 : /* keep compiler quiet */
1029 : all_privileges = ACL_NO_RIGHTS;
1030 : errormsg = NULL;
1031 : }
1032 :
1033 206 : if (action->privileges == NIL)
1034 : {
1035 78 : iacls.all_privs = true;
1036 :
1037 : /*
1038 : * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1039 : * depending on the object type
1040 : */
1041 78 : iacls.privileges = ACL_NO_RIGHTS;
1042 : }
1043 : else
1044 : {
1045 128 : iacls.all_privs = false;
1046 128 : iacls.privileges = ACL_NO_RIGHTS;
1047 :
1048 256 : foreach(cell, action->privileges)
1049 : {
1050 128 : AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1051 : AclMode priv;
1052 :
1053 128 : if (privnode->cols)
1054 0 : ereport(ERROR,
1055 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1056 : errmsg("default privileges cannot be set for columns")));
1057 :
1058 128 : if (privnode->priv_name == NULL) /* parser mistake? */
1059 0 : elog(ERROR, "AccessPriv node must specify privilege");
1060 128 : priv = string_to_privilege(privnode->priv_name);
1061 :
1062 128 : if (priv & ~((AclMode) all_privileges))
1063 0 : ereport(ERROR,
1064 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1065 : errmsg(errormsg, privilege_to_string(priv))));
1066 :
1067 128 : iacls.privileges |= priv;
1068 : }
1069 : }
1070 :
1071 206 : if (rolespecs == NIL)
1072 : {
1073 : /* Set permissions for myself */
1074 122 : iacls.roleid = GetUserId();
1075 :
1076 122 : SetDefaultACLsInSchemas(&iacls, nspnames);
1077 : }
1078 : else
1079 : {
1080 : /* Look up the role OIDs and do permissions checks */
1081 : ListCell *rolecell;
1082 :
1083 168 : foreach(rolecell, rolespecs)
1084 : {
1085 84 : RoleSpec *rolespec = lfirst(rolecell);
1086 :
1087 84 : iacls.roleid = get_rolespec_oid(rolespec, false);
1088 :
1089 84 : if (!has_privs_of_role(GetUserId(), iacls.roleid))
1090 0 : ereport(ERROR,
1091 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1092 : errmsg("permission denied to change default privileges")));
1093 :
1094 84 : SetDefaultACLsInSchemas(&iacls, nspnames);
1095 : }
1096 : }
1097 194 : }
1098 :
1099 : /*
1100 : * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1101 : *
1102 : * All fields of *iacls except nspid were filled already
1103 : */
1104 : static void
1105 206 : SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
1106 : {
1107 206 : if (nspnames == NIL)
1108 : {
1109 : /* Set database-wide permissions if no schema was specified */
1110 146 : iacls->nspid = InvalidOid;
1111 :
1112 146 : SetDefaultACL(iacls);
1113 : }
1114 : else
1115 : {
1116 : /* Look up the schema OIDs and set permissions for each one */
1117 : ListCell *nspcell;
1118 :
1119 114 : foreach(nspcell, nspnames)
1120 : {
1121 66 : char *nspname = strVal(lfirst(nspcell));
1122 :
1123 66 : iacls->nspid = get_namespace_oid(nspname, false);
1124 :
1125 : /*
1126 : * We used to insist that the target role have CREATE privileges
1127 : * on the schema, since without that it wouldn't be able to create
1128 : * an object for which these default privileges would apply.
1129 : * However, this check proved to be more confusing than helpful,
1130 : * and it also caused certain database states to not be
1131 : * dumpable/restorable, since revoking CREATE doesn't cause
1132 : * default privileges for the schema to go away. So now, we just
1133 : * allow the ALTER; if the user lacks CREATE he'll find out when
1134 : * he tries to create an object.
1135 : */
1136 :
1137 66 : SetDefaultACL(iacls);
1138 : }
1139 : }
1140 194 : }
1141 :
1142 :
1143 : /*
1144 : * Create or update a pg_default_acl entry
1145 : */
1146 : static void
1147 248 : SetDefaultACL(InternalDefaultACL *iacls)
1148 : {
1149 248 : AclMode this_privileges = iacls->privileges;
1150 : char objtype;
1151 : Relation rel;
1152 : HeapTuple tuple;
1153 : bool isNew;
1154 : Acl *def_acl;
1155 : Acl *old_acl;
1156 : Acl *new_acl;
1157 : HeapTuple newtuple;
1158 : int noldmembers;
1159 : int nnewmembers;
1160 : Oid *oldmembers;
1161 : Oid *newmembers;
1162 :
1163 248 : rel = table_open(DefaultAclRelationId, RowExclusiveLock);
1164 :
1165 : /*
1166 : * The default for a global entry is the hard-wired default ACL for the
1167 : * particular object type. The default for non-global entries is an empty
1168 : * ACL. This must be so because global entries replace the hard-wired
1169 : * defaults, while others are added on.
1170 : */
1171 248 : if (!OidIsValid(iacls->nspid))
1172 182 : def_acl = acldefault(iacls->objtype, iacls->roleid);
1173 : else
1174 66 : def_acl = make_empty_acl();
1175 :
1176 : /*
1177 : * Convert ACL object type to pg_default_acl object type and handle
1178 : * all_privs option
1179 : */
1180 248 : switch (iacls->objtype)
1181 : {
1182 90 : case OBJECT_TABLE:
1183 90 : objtype = DEFACLOBJ_RELATION;
1184 90 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1185 26 : this_privileges = ACL_ALL_RIGHTS_RELATION;
1186 90 : break;
1187 :
1188 12 : case OBJECT_SEQUENCE:
1189 12 : objtype = DEFACLOBJ_SEQUENCE;
1190 12 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1191 12 : this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1192 12 : break;
1193 :
1194 28 : case OBJECT_FUNCTION:
1195 28 : objtype = DEFACLOBJ_FUNCTION;
1196 28 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1197 12 : this_privileges = ACL_ALL_RIGHTS_FUNCTION;
1198 28 : break;
1199 :
1200 40 : case OBJECT_TYPE:
1201 40 : objtype = DEFACLOBJ_TYPE;
1202 40 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1203 16 : this_privileges = ACL_ALL_RIGHTS_TYPE;
1204 40 : break;
1205 :
1206 42 : case OBJECT_SCHEMA:
1207 42 : if (OidIsValid(iacls->nspid))
1208 6 : ereport(ERROR,
1209 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1210 : errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1211 36 : objtype = DEFACLOBJ_NAMESPACE;
1212 36 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1213 24 : this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1214 36 : break;
1215 :
1216 36 : case OBJECT_LARGEOBJECT:
1217 36 : if (OidIsValid(iacls->nspid))
1218 6 : ereport(ERROR,
1219 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1220 : errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON LARGE OBJECTS")));
1221 30 : objtype = DEFACLOBJ_LARGEOBJECT;
1222 30 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1223 18 : this_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
1224 30 : break;
1225 :
1226 0 : default:
1227 0 : elog(ERROR, "unrecognized object type: %d",
1228 : (int) iacls->objtype);
1229 : objtype = 0; /* keep compiler quiet */
1230 : break;
1231 : }
1232 :
1233 : /* Search for existing row for this object type in catalog */
1234 236 : tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1235 : ObjectIdGetDatum(iacls->roleid),
1236 : ObjectIdGetDatum(iacls->nspid),
1237 : CharGetDatum(objtype));
1238 :
1239 236 : if (HeapTupleIsValid(tuple))
1240 : {
1241 : Datum aclDatum;
1242 : bool isNull;
1243 :
1244 90 : aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1245 : Anum_pg_default_acl_defaclacl,
1246 : &isNull);
1247 90 : if (!isNull)
1248 90 : old_acl = DatumGetAclPCopy(aclDatum);
1249 : else
1250 0 : old_acl = NULL; /* this case shouldn't happen, probably */
1251 90 : isNew = false;
1252 : }
1253 : else
1254 : {
1255 146 : old_acl = NULL;
1256 146 : isNew = true;
1257 : }
1258 :
1259 236 : if (old_acl != NULL)
1260 : {
1261 : /*
1262 : * We need the members of both old and new ACLs so we can correct the
1263 : * shared dependency information. Collect data before
1264 : * merge_acl_with_grant throws away old_acl.
1265 : */
1266 90 : noldmembers = aclmembers(old_acl, &oldmembers);
1267 : }
1268 : else
1269 : {
1270 : /* If no or null entry, start with the default ACL value */
1271 146 : old_acl = aclcopy(def_acl);
1272 : /* There are no old member roles according to the catalogs */
1273 146 : noldmembers = 0;
1274 146 : oldmembers = NULL;
1275 : }
1276 :
1277 : /*
1278 : * Generate new ACL. Grantor of rights is always the same as the target
1279 : * role.
1280 : */
1281 236 : new_acl = merge_acl_with_grant(old_acl,
1282 236 : iacls->is_grant,
1283 236 : iacls->grant_option,
1284 : iacls->behavior,
1285 : iacls->grantees,
1286 : this_privileges,
1287 : iacls->roleid,
1288 : iacls->roleid);
1289 :
1290 : /*
1291 : * If the result is the same as the default value, we do not need an
1292 : * explicit pg_default_acl entry, and should in fact remove the entry if
1293 : * it exists. Must sort both arrays to compare properly.
1294 : */
1295 236 : aclitemsort(new_acl);
1296 236 : aclitemsort(def_acl);
1297 236 : if (aclequal(new_acl, def_acl))
1298 : {
1299 : /* delete old entry, if indeed there is one */
1300 62 : if (!isNew)
1301 : {
1302 : ObjectAddress myself;
1303 :
1304 : /*
1305 : * The dependency machinery will take care of removing all
1306 : * associated dependency entries. We use DROP_RESTRICT since
1307 : * there shouldn't be anything depending on this entry.
1308 : */
1309 60 : myself.classId = DefaultAclRelationId;
1310 60 : myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1311 60 : myself.objectSubId = 0;
1312 :
1313 60 : performDeletion(&myself, DROP_RESTRICT, 0);
1314 : }
1315 : }
1316 : else
1317 : {
1318 174 : Datum values[Natts_pg_default_acl] = {0};
1319 174 : bool nulls[Natts_pg_default_acl] = {0};
1320 174 : bool replaces[Natts_pg_default_acl] = {0};
1321 : Oid defAclOid;
1322 :
1323 174 : if (isNew)
1324 : {
1325 : /* insert new entry */
1326 144 : defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1327 : Anum_pg_default_acl_oid);
1328 144 : values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1329 144 : values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1330 144 : values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1331 144 : values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1332 144 : values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1333 :
1334 144 : newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1335 144 : CatalogTupleInsert(rel, newtuple);
1336 : }
1337 : else
1338 : {
1339 30 : defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1340 :
1341 : /* update existing entry */
1342 30 : values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1343 30 : replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1344 :
1345 30 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1346 : values, nulls, replaces);
1347 30 : CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1348 : }
1349 :
1350 : /* these dependencies don't change in an update */
1351 174 : if (isNew)
1352 : {
1353 : /* dependency on role */
1354 144 : recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1355 : iacls->roleid);
1356 :
1357 : /* dependency on namespace */
1358 144 : if (OidIsValid(iacls->nspid))
1359 : {
1360 : ObjectAddress myself,
1361 : referenced;
1362 :
1363 34 : myself.classId = DefaultAclRelationId;
1364 34 : myself.objectId = defAclOid;
1365 34 : myself.objectSubId = 0;
1366 :
1367 34 : referenced.classId = NamespaceRelationId;
1368 34 : referenced.objectId = iacls->nspid;
1369 34 : referenced.objectSubId = 0;
1370 :
1371 34 : recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1372 : }
1373 : }
1374 :
1375 : /*
1376 : * Update the shared dependency ACL info
1377 : */
1378 174 : nnewmembers = aclmembers(new_acl, &newmembers);
1379 :
1380 174 : updateAclDependencies(DefaultAclRelationId,
1381 : defAclOid, 0,
1382 : iacls->roleid,
1383 : noldmembers, oldmembers,
1384 : nnewmembers, newmembers);
1385 :
1386 174 : if (isNew)
1387 144 : InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1388 : else
1389 30 : InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1390 : }
1391 :
1392 236 : if (HeapTupleIsValid(tuple))
1393 90 : ReleaseSysCache(tuple);
1394 :
1395 236 : table_close(rel, RowExclusiveLock);
1396 :
1397 : /* prevent error when processing duplicate objects */
1398 236 : CommandCounterIncrement();
1399 236 : }
1400 :
1401 :
1402 : /*
1403 : * RemoveRoleFromObjectACL
1404 : *
1405 : * Used by shdepDropOwned to remove mentions of a role in ACLs.
1406 : *
1407 : * Notice that this doesn't accept an objsubid parameter, which is a bit bogus
1408 : * since the pg_shdepend record that caused us to call it certainly had one.
1409 : * If, for example, pg_shdepend records the existence of a permission on
1410 : * mytable.mycol, this function will effectively issue a REVOKE ALL ON TABLE
1411 : * mytable. That gets the job done because (per SQL spec) such a REVOKE also
1412 : * revokes per-column permissions. We could not recreate a situation where
1413 : * the role has table-level but not column-level permissions; but it's okay
1414 : * (for now anyway) because this is only used when we're dropping the role
1415 : * and so all its permissions everywhere must go away. At worst it's a bit
1416 : * inefficient if the role has column permissions on several columns of the
1417 : * same table.
1418 : */
1419 : void
1420 262 : RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1421 : {
1422 262 : if (classid == DefaultAclRelationId)
1423 : {
1424 : InternalDefaultACL iacls;
1425 : Form_pg_default_acl pg_default_acl_tuple;
1426 : Relation rel;
1427 : ScanKeyData skey[1];
1428 : SysScanDesc scan;
1429 : HeapTuple tuple;
1430 :
1431 : /* first fetch info needed by SetDefaultACL */
1432 36 : rel = table_open(DefaultAclRelationId, AccessShareLock);
1433 :
1434 36 : ScanKeyInit(&skey[0],
1435 : Anum_pg_default_acl_oid,
1436 : BTEqualStrategyNumber, F_OIDEQ,
1437 : ObjectIdGetDatum(objid));
1438 :
1439 36 : scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1440 : NULL, 1, skey);
1441 :
1442 36 : tuple = systable_getnext(scan);
1443 :
1444 36 : if (!HeapTupleIsValid(tuple))
1445 0 : elog(ERROR, "could not find tuple for default ACL %u", objid);
1446 :
1447 36 : pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1448 :
1449 36 : iacls.roleid = pg_default_acl_tuple->defaclrole;
1450 36 : iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1451 :
1452 36 : switch (pg_default_acl_tuple->defaclobjtype)
1453 : {
1454 6 : case DEFACLOBJ_RELATION:
1455 6 : iacls.objtype = OBJECT_TABLE;
1456 6 : break;
1457 6 : case DEFACLOBJ_SEQUENCE:
1458 6 : iacls.objtype = OBJECT_SEQUENCE;
1459 6 : break;
1460 6 : case DEFACLOBJ_FUNCTION:
1461 6 : iacls.objtype = OBJECT_FUNCTION;
1462 6 : break;
1463 6 : case DEFACLOBJ_TYPE:
1464 6 : iacls.objtype = OBJECT_TYPE;
1465 6 : break;
1466 6 : case DEFACLOBJ_NAMESPACE:
1467 6 : iacls.objtype = OBJECT_SCHEMA;
1468 6 : break;
1469 6 : case DEFACLOBJ_LARGEOBJECT:
1470 6 : iacls.objtype = OBJECT_LARGEOBJECT;
1471 6 : break;
1472 0 : default:
1473 : /* Shouldn't get here */
1474 0 : elog(ERROR, "unexpected default ACL type: %d",
1475 : (int) pg_default_acl_tuple->defaclobjtype);
1476 : break;
1477 : }
1478 :
1479 36 : systable_endscan(scan);
1480 36 : table_close(rel, AccessShareLock);
1481 :
1482 36 : iacls.is_grant = false;
1483 36 : iacls.all_privs = true;
1484 36 : iacls.privileges = ACL_NO_RIGHTS;
1485 36 : iacls.grantees = list_make1_oid(roleid);
1486 36 : iacls.grant_option = false;
1487 36 : iacls.behavior = DROP_CASCADE;
1488 :
1489 : /* Do it */
1490 36 : SetDefaultACL(&iacls);
1491 : }
1492 : else
1493 : {
1494 : InternalGrant istmt;
1495 :
1496 226 : switch (classid)
1497 : {
1498 100 : case RelationRelationId:
1499 : /* it's OK to use TABLE for a sequence */
1500 100 : istmt.objtype = OBJECT_TABLE;
1501 100 : break;
1502 10 : case DatabaseRelationId:
1503 10 : istmt.objtype = OBJECT_DATABASE;
1504 10 : break;
1505 6 : case TypeRelationId:
1506 6 : istmt.objtype = OBJECT_TYPE;
1507 6 : break;
1508 38 : case ProcedureRelationId:
1509 38 : istmt.objtype = OBJECT_ROUTINE;
1510 38 : break;
1511 0 : case LanguageRelationId:
1512 0 : istmt.objtype = OBJECT_LANGUAGE;
1513 0 : break;
1514 18 : case LargeObjectRelationId:
1515 18 : istmt.objtype = OBJECT_LARGEOBJECT;
1516 18 : break;
1517 14 : case NamespaceRelationId:
1518 14 : istmt.objtype = OBJECT_SCHEMA;
1519 14 : break;
1520 0 : case TableSpaceRelationId:
1521 0 : istmt.objtype = OBJECT_TABLESPACE;
1522 0 : break;
1523 14 : case ForeignServerRelationId:
1524 14 : istmt.objtype = OBJECT_FOREIGN_SERVER;
1525 14 : break;
1526 2 : case ForeignDataWrapperRelationId:
1527 2 : istmt.objtype = OBJECT_FDW;
1528 2 : break;
1529 24 : case ParameterAclRelationId:
1530 24 : istmt.objtype = OBJECT_PARAMETER_ACL;
1531 24 : break;
1532 0 : default:
1533 0 : elog(ERROR, "unexpected object class %u", classid);
1534 : break;
1535 : }
1536 226 : istmt.is_grant = false;
1537 226 : istmt.objects = list_make1_oid(objid);
1538 226 : istmt.all_privs = true;
1539 226 : istmt.privileges = ACL_NO_RIGHTS;
1540 226 : istmt.col_privs = NIL;
1541 226 : istmt.grantees = list_make1_oid(roleid);
1542 226 : istmt.grant_option = false;
1543 226 : istmt.behavior = DROP_CASCADE;
1544 :
1545 226 : ExecGrantStmt_oids(&istmt);
1546 : }
1547 262 : }
1548 :
1549 :
1550 : /*
1551 : * expand_col_privileges
1552 : *
1553 : * OR the specified privilege(s) into per-column array entries for each
1554 : * specified attribute. The per-column array is indexed starting at
1555 : * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1556 : */
1557 : static void
1558 442 : expand_col_privileges(List *colnames, Oid table_oid,
1559 : AclMode this_privileges,
1560 : AclMode *col_privileges,
1561 : int num_col_privileges)
1562 : {
1563 : ListCell *cell;
1564 :
1565 2796 : foreach(cell, colnames)
1566 : {
1567 2354 : char *colname = strVal(lfirst(cell));
1568 : AttrNumber attnum;
1569 :
1570 2354 : attnum = get_attnum(table_oid, colname);
1571 2354 : if (attnum == InvalidAttrNumber)
1572 0 : ereport(ERROR,
1573 : (errcode(ERRCODE_UNDEFINED_COLUMN),
1574 : errmsg("column \"%s\" of relation \"%s\" does not exist",
1575 : colname, get_rel_name(table_oid))));
1576 2354 : attnum -= FirstLowInvalidHeapAttributeNumber;
1577 2354 : if (attnum <= 0 || attnum >= num_col_privileges)
1578 0 : elog(ERROR, "column number out of range"); /* safety check */
1579 2354 : col_privileges[attnum] |= this_privileges;
1580 : }
1581 442 : }
1582 :
1583 : /*
1584 : * expand_all_col_privileges
1585 : *
1586 : * OR the specified privilege(s) into per-column array entries for each valid
1587 : * attribute of a relation. The per-column array is indexed starting at
1588 : * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1589 : */
1590 : static void
1591 6532 : expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
1592 : AclMode this_privileges,
1593 : AclMode *col_privileges,
1594 : int num_col_privileges)
1595 : {
1596 : AttrNumber curr_att;
1597 :
1598 : Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1599 6532 : for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1600 67706 : curr_att <= classForm->relnatts;
1601 61174 : curr_att++)
1602 : {
1603 : HeapTuple attTuple;
1604 : bool isdropped;
1605 :
1606 61174 : if (curr_att == InvalidAttrNumber)
1607 6532 : continue;
1608 :
1609 : /* Views don't have any system columns at all */
1610 54642 : if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1611 6516 : continue;
1612 :
1613 48126 : attTuple = SearchSysCache2(ATTNUM,
1614 : ObjectIdGetDatum(table_oid),
1615 : Int16GetDatum(curr_att));
1616 48126 : if (!HeapTupleIsValid(attTuple))
1617 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1618 : curr_att, table_oid);
1619 :
1620 48126 : isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1621 :
1622 48126 : ReleaseSysCache(attTuple);
1623 :
1624 : /* ignore dropped columns */
1625 48126 : if (isdropped)
1626 6 : continue;
1627 :
1628 48120 : col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1629 : }
1630 6532 : }
1631 :
1632 : /*
1633 : * This processes attributes, but expects to be called from
1634 : * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1635 : */
1636 : static void
1637 50432 : ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1638 : AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1639 : Relation attRelation, const Acl *old_rel_acl)
1640 : {
1641 : HeapTuple attr_tuple;
1642 : Form_pg_attribute pg_attribute_tuple;
1643 : Acl *old_acl;
1644 : Acl *new_acl;
1645 : Acl *merged_acl;
1646 : Datum aclDatum;
1647 : bool isNull;
1648 : Oid grantorId;
1649 : AclMode avail_goptions;
1650 : bool need_update;
1651 : HeapTuple newtuple;
1652 50432 : Datum values[Natts_pg_attribute] = {0};
1653 50432 : bool nulls[Natts_pg_attribute] = {0};
1654 50432 : bool replaces[Natts_pg_attribute] = {0};
1655 : int noldmembers;
1656 : int nnewmembers;
1657 : Oid *oldmembers;
1658 : Oid *newmembers;
1659 :
1660 50432 : attr_tuple = SearchSysCache2(ATTNUM,
1661 : ObjectIdGetDatum(relOid),
1662 : Int16GetDatum(attnum));
1663 50432 : if (!HeapTupleIsValid(attr_tuple))
1664 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1665 : attnum, relOid);
1666 50432 : pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1667 :
1668 : /*
1669 : * Get working copy of existing ACL. If there's no ACL, substitute the
1670 : * proper default.
1671 : */
1672 50432 : aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1673 : &isNull);
1674 50432 : if (isNull)
1675 : {
1676 50122 : old_acl = acldefault(OBJECT_COLUMN, ownerId);
1677 : /* There are no old member roles according to the catalogs */
1678 50122 : noldmembers = 0;
1679 50122 : oldmembers = NULL;
1680 : }
1681 : else
1682 : {
1683 310 : old_acl = DatumGetAclPCopy(aclDatum);
1684 : /* Get the roles mentioned in the existing ACL */
1685 310 : noldmembers = aclmembers(old_acl, &oldmembers);
1686 : }
1687 :
1688 : /*
1689 : * In select_best_grantor we should consider existing table-level ACL bits
1690 : * as well as the per-column ACL. Build a new ACL that is their
1691 : * concatenation. (This is a bit cheap and dirty compared to merging them
1692 : * properly with no duplications, but it's all we need here.)
1693 : */
1694 50432 : merged_acl = aclconcat(old_rel_acl, old_acl);
1695 :
1696 : /* Determine ID to do the grant as, and available grant options */
1697 50432 : select_best_grantor(GetUserId(), col_privileges,
1698 : merged_acl, ownerId,
1699 : &grantorId, &avail_goptions);
1700 :
1701 50432 : pfree(merged_acl);
1702 :
1703 : /*
1704 : * Restrict the privileges to what we can actually grant, and emit the
1705 : * standards-mandated warning and error messages. Note: we don't track
1706 : * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1707 : * each column; we just approximate it by whether all the possible
1708 : * privileges are specified now. Since the all_privs flag only determines
1709 : * whether a warning is issued, this seems close enough.
1710 : */
1711 : col_privileges =
1712 50432 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
1713 : (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1714 : col_privileges,
1715 : relOid, grantorId, OBJECT_COLUMN,
1716 : relname, attnum,
1717 50432 : NameStr(pg_attribute_tuple->attname));
1718 :
1719 : /*
1720 : * Generate new ACL.
1721 : */
1722 50432 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1723 50432 : istmt->grant_option,
1724 : istmt->behavior, istmt->grantees,
1725 : col_privileges, grantorId,
1726 : ownerId);
1727 :
1728 : /*
1729 : * We need the members of both old and new ACLs so we can correct the
1730 : * shared dependency information.
1731 : */
1732 50432 : nnewmembers = aclmembers(new_acl, &newmembers);
1733 :
1734 : /* finished building new ACL value, now insert it */
1735 :
1736 : /*
1737 : * If the updated ACL is empty, we can set attacl to null, and maybe even
1738 : * avoid an update of the pg_attribute row. This is worth testing because
1739 : * we'll come through here multiple times for any relation-level REVOKE,
1740 : * even if there were never any column GRANTs. Note we are assuming that
1741 : * the "default" ACL state for columns is empty.
1742 : */
1743 50432 : if (ACL_NUM(new_acl) > 0)
1744 : {
1745 2378 : values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1746 2378 : need_update = true;
1747 : }
1748 : else
1749 : {
1750 48054 : nulls[Anum_pg_attribute_attacl - 1] = true;
1751 48054 : need_update = !isNull;
1752 : }
1753 50432 : replaces[Anum_pg_attribute_attacl - 1] = true;
1754 :
1755 50432 : if (need_update)
1756 : {
1757 2474 : newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1758 : values, nulls, replaces);
1759 :
1760 2474 : CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1761 :
1762 : /* Update initial privileges for extensions */
1763 2474 : recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1764 2474 : ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1765 :
1766 : /* Update the shared dependency ACL info */
1767 2474 : updateAclDependencies(RelationRelationId, relOid, attnum,
1768 : ownerId,
1769 : noldmembers, oldmembers,
1770 : nnewmembers, newmembers);
1771 : }
1772 :
1773 50432 : pfree(new_acl);
1774 :
1775 50432 : ReleaseSysCache(attr_tuple);
1776 50432 : }
1777 :
1778 : /*
1779 : * This processes both sequences and non-sequences.
1780 : */
1781 : static void
1782 19124 : ExecGrant_Relation(InternalGrant *istmt)
1783 : {
1784 : Relation relation;
1785 : Relation attRelation;
1786 : ListCell *cell;
1787 :
1788 19124 : relation = table_open(RelationRelationId, RowExclusiveLock);
1789 19124 : attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1790 :
1791 38296 : foreach(cell, istmt->objects)
1792 : {
1793 19190 : Oid relOid = lfirst_oid(cell);
1794 : Datum aclDatum;
1795 : Form_pg_class pg_class_tuple;
1796 : bool isNull;
1797 : AclMode this_privileges;
1798 : AclMode *col_privileges;
1799 : int num_col_privileges;
1800 : bool have_col_privileges;
1801 : Acl *old_acl;
1802 : Acl *old_rel_acl;
1803 : int noldmembers;
1804 : Oid *oldmembers;
1805 : Oid ownerId;
1806 : HeapTuple tuple;
1807 : ListCell *cell_colprivs;
1808 :
1809 19190 : tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relOid));
1810 19190 : if (!HeapTupleIsValid(tuple))
1811 2 : elog(ERROR, "cache lookup failed for relation %u", relOid);
1812 19188 : pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1813 :
1814 : /* Not sensible to grant on an index */
1815 19188 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
1816 19188 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1817 0 : ereport(ERROR,
1818 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1819 : errmsg("\"%s\" is an index",
1820 : NameStr(pg_class_tuple->relname))));
1821 :
1822 : /* Composite types aren't tables either */
1823 19188 : if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1824 0 : ereport(ERROR,
1825 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1826 : errmsg("\"%s\" is a composite type",
1827 : NameStr(pg_class_tuple->relname))));
1828 :
1829 : /* Used GRANT SEQUENCE on a non-sequence? */
1830 19188 : if (istmt->objtype == OBJECT_SEQUENCE &&
1831 22 : pg_class_tuple->relkind != RELKIND_SEQUENCE)
1832 0 : ereport(ERROR,
1833 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1834 : errmsg("\"%s\" is not a sequence",
1835 : NameStr(pg_class_tuple->relname))));
1836 :
1837 : /* Adjust the default permissions based on object type */
1838 19188 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1839 : {
1840 2150 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1841 80 : this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1842 : else
1843 2070 : this_privileges = ACL_ALL_RIGHTS_RELATION;
1844 : }
1845 : else
1846 17038 : this_privileges = istmt->privileges;
1847 :
1848 : /*
1849 : * The GRANT TABLE syntax can be used for sequences and non-sequences,
1850 : * so we have to look at the relkind to determine the supported
1851 : * permissions. The OR of table and sequence permissions were already
1852 : * checked.
1853 : */
1854 19188 : if (istmt->objtype == OBJECT_TABLE)
1855 : {
1856 19166 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1857 : {
1858 : /*
1859 : * For backward compatibility, just throw a warning for
1860 : * invalid sequence permissions when using the non-sequence
1861 : * GRANT syntax.
1862 : */
1863 152 : if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1864 : {
1865 : /*
1866 : * Mention the object name because the user needs to know
1867 : * which operations succeeded. This is required because
1868 : * WARNING allows the command to continue.
1869 : */
1870 0 : ereport(WARNING,
1871 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1872 : errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1873 : NameStr(pg_class_tuple->relname))));
1874 0 : this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1875 : }
1876 : }
1877 : else
1878 : {
1879 19014 : if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1880 : {
1881 : /*
1882 : * USAGE is the only permission supported by sequences but
1883 : * not by non-sequences. Don't mention the object name
1884 : * because we didn't in the combined TABLE | SEQUENCE
1885 : * check.
1886 : */
1887 0 : ereport(ERROR,
1888 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1889 : errmsg("invalid privilege type %s for table",
1890 : "USAGE")));
1891 : }
1892 : }
1893 : }
1894 :
1895 : /*
1896 : * Set up array in which we'll accumulate any column privilege bits
1897 : * that need modification. The array is indexed such that entry [0]
1898 : * corresponds to FirstLowInvalidHeapAttributeNumber.
1899 : */
1900 19188 : num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1901 19188 : col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1902 19188 : have_col_privileges = false;
1903 :
1904 : /*
1905 : * If we are revoking relation privileges that are also column
1906 : * privileges, we must implicitly revoke them from each column too,
1907 : * per SQL spec. (We don't need to implicitly add column privileges
1908 : * during GRANT because the permissions-checking code always checks
1909 : * both relation and per-column privileges.)
1910 : */
1911 19188 : if (!istmt->is_grant &&
1912 6590 : (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1913 : {
1914 6532 : expand_all_col_privileges(relOid, pg_class_tuple,
1915 : this_privileges & ACL_ALL_RIGHTS_COLUMN,
1916 : col_privileges,
1917 : num_col_privileges);
1918 6532 : have_col_privileges = true;
1919 : }
1920 :
1921 : /*
1922 : * Get owner ID and working copy of existing ACL. If there's no ACL,
1923 : * substitute the proper default.
1924 : */
1925 19188 : ownerId = pg_class_tuple->relowner;
1926 19188 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1927 : &isNull);
1928 19188 : if (isNull)
1929 : {
1930 8846 : switch (pg_class_tuple->relkind)
1931 : {
1932 92 : case RELKIND_SEQUENCE:
1933 92 : old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1934 92 : break;
1935 8754 : default:
1936 8754 : old_acl = acldefault(OBJECT_TABLE, ownerId);
1937 8754 : break;
1938 : }
1939 : /* There are no old member roles according to the catalogs */
1940 8846 : noldmembers = 0;
1941 8846 : oldmembers = NULL;
1942 : }
1943 : else
1944 : {
1945 10342 : old_acl = DatumGetAclPCopy(aclDatum);
1946 : /* Get the roles mentioned in the existing ACL */
1947 10342 : noldmembers = aclmembers(old_acl, &oldmembers);
1948 : }
1949 :
1950 : /* Need an extra copy of original rel ACL for column handling */
1951 19188 : old_rel_acl = aclcopy(old_acl);
1952 :
1953 : /*
1954 : * Handle relation-level privileges, if any were specified
1955 : */
1956 19188 : if (this_privileges != ACL_NO_RIGHTS)
1957 : {
1958 : AclMode avail_goptions;
1959 : Acl *new_acl;
1960 : Oid grantorId;
1961 : HeapTuple newtuple;
1962 18764 : Datum values[Natts_pg_class] = {0};
1963 18764 : bool nulls[Natts_pg_class] = {0};
1964 18764 : bool replaces[Natts_pg_class] = {0};
1965 : int nnewmembers;
1966 : Oid *newmembers;
1967 : ObjectType objtype;
1968 :
1969 : /* Determine ID to do the grant as, and available grant options */
1970 18764 : select_best_grantor(GetUserId(), this_privileges,
1971 : old_acl, ownerId,
1972 : &grantorId, &avail_goptions);
1973 :
1974 18764 : switch (pg_class_tuple->relkind)
1975 : {
1976 174 : case RELKIND_SEQUENCE:
1977 174 : objtype = OBJECT_SEQUENCE;
1978 174 : break;
1979 18590 : default:
1980 18590 : objtype = OBJECT_TABLE;
1981 18590 : break;
1982 : }
1983 :
1984 : /*
1985 : * Restrict the privileges to what we can actually grant, and emit
1986 : * the standards-mandated warning and error messages.
1987 : */
1988 : this_privileges =
1989 18764 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
1990 18764 : istmt->all_privs, this_privileges,
1991 : relOid, grantorId, objtype,
1992 18764 : NameStr(pg_class_tuple->relname),
1993 : 0, NULL);
1994 :
1995 : /*
1996 : * Generate new ACL.
1997 : */
1998 18758 : new_acl = merge_acl_with_grant(old_acl,
1999 18758 : istmt->is_grant,
2000 18758 : istmt->grant_option,
2001 : istmt->behavior,
2002 : istmt->grantees,
2003 : this_privileges,
2004 : grantorId,
2005 : ownerId);
2006 :
2007 : /*
2008 : * We need the members of both old and new ACLs so we can correct
2009 : * the shared dependency information.
2010 : */
2011 18752 : nnewmembers = aclmembers(new_acl, &newmembers);
2012 :
2013 : /* finished building new ACL value, now insert it */
2014 18752 : replaces[Anum_pg_class_relacl - 1] = true;
2015 18752 : values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
2016 :
2017 18752 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2018 : values, nulls, replaces);
2019 :
2020 18752 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2021 18748 : UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2022 :
2023 : /* Update initial privileges for extensions */
2024 18748 : recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2025 :
2026 : /* Update the shared dependency ACL info */
2027 18748 : updateAclDependencies(RelationRelationId, relOid, 0,
2028 : ownerId,
2029 : noldmembers, oldmembers,
2030 : nnewmembers, newmembers);
2031 :
2032 18748 : pfree(new_acl);
2033 : }
2034 : else
2035 424 : UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2036 :
2037 : /*
2038 : * Handle column-level privileges, if any were specified or implied.
2039 : * We first expand the user-specified column privileges into the
2040 : * array, and then iterate over all nonempty array entries.
2041 : */
2042 19614 : foreach(cell_colprivs, istmt->col_privs)
2043 : {
2044 442 : AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2045 :
2046 442 : if (col_privs->priv_name == NULL)
2047 18 : this_privileges = ACL_ALL_RIGHTS_COLUMN;
2048 : else
2049 424 : this_privileges = string_to_privilege(col_privs->priv_name);
2050 :
2051 442 : if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2052 0 : ereport(ERROR,
2053 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2054 : errmsg("invalid privilege type %s for column",
2055 : privilege_to_string(this_privileges))));
2056 :
2057 442 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2058 0 : this_privileges & ~((AclMode) ACL_SELECT))
2059 : {
2060 : /*
2061 : * The only column privilege allowed on sequences is SELECT.
2062 : * This is a warning not error because we do it that way for
2063 : * relation-level privileges.
2064 : */
2065 0 : ereport(WARNING,
2066 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2067 : errmsg("sequence \"%s\" only supports SELECT column privileges",
2068 : NameStr(pg_class_tuple->relname))));
2069 :
2070 0 : this_privileges &= (AclMode) ACL_SELECT;
2071 : }
2072 :
2073 442 : expand_col_privileges(col_privs->cols, relOid,
2074 : this_privileges,
2075 : col_privileges,
2076 : num_col_privileges);
2077 442 : have_col_privileges = true;
2078 : }
2079 :
2080 19172 : if (have_col_privileges)
2081 : {
2082 : AttrNumber i;
2083 :
2084 81274 : for (i = 0; i < num_col_privileges; i++)
2085 : {
2086 74318 : if (col_privileges[i] == ACL_NO_RIGHTS)
2087 23886 : continue;
2088 50432 : ExecGrant_Attribute(istmt,
2089 : relOid,
2090 50432 : NameStr(pg_class_tuple->relname),
2091 50432 : i + FirstLowInvalidHeapAttributeNumber,
2092 : ownerId,
2093 50432 : col_privileges[i],
2094 : attRelation,
2095 : old_rel_acl);
2096 : }
2097 : }
2098 :
2099 19172 : pfree(old_rel_acl);
2100 19172 : pfree(col_privileges);
2101 :
2102 19172 : ReleaseSysCache(tuple);
2103 :
2104 : /* prevent error when processing duplicate objects */
2105 19172 : CommandCounterIncrement();
2106 : }
2107 :
2108 19106 : table_close(attRelation, RowExclusiveLock);
2109 19106 : table_close(relation, RowExclusiveLock);
2110 19106 : }
2111 :
2112 : static void
2113 10102 : ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
2114 : void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
2115 : {
2116 : int cacheid;
2117 : Relation relation;
2118 : ListCell *cell;
2119 :
2120 10102 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2121 742 : istmt->privileges = default_privs;
2122 :
2123 10102 : cacheid = get_object_catcache_oid(classid);
2124 :
2125 10102 : relation = table_open(classid, RowExclusiveLock);
2126 :
2127 20294 : foreach(cell, istmt->objects)
2128 : {
2129 10246 : Oid objectid = lfirst_oid(cell);
2130 : Datum aclDatum;
2131 : Datum nameDatum;
2132 : bool isNull;
2133 : AclMode avail_goptions;
2134 : AclMode this_privileges;
2135 : Acl *old_acl;
2136 : Acl *new_acl;
2137 : Oid grantorId;
2138 : Oid ownerId;
2139 : HeapTuple tuple;
2140 : HeapTuple newtuple;
2141 10246 : Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2142 10246 : bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2143 10246 : bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2144 : int noldmembers;
2145 : int nnewmembers;
2146 : Oid *oldmembers;
2147 : Oid *newmembers;
2148 :
2149 10246 : tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid));
2150 10246 : if (!HeapTupleIsValid(tuple))
2151 0 : elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2152 :
2153 : /*
2154 : * Additional object-type-specific checks
2155 : */
2156 10246 : if (object_check)
2157 180 : object_check(istmt, tuple);
2158 :
2159 : /*
2160 : * Get owner ID and working copy of existing ACL. If there's no ACL,
2161 : * substitute the proper default.
2162 : */
2163 10228 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2164 : tuple,
2165 10228 : get_object_attnum_owner(classid)));
2166 10228 : aclDatum = SysCacheGetAttr(cacheid,
2167 : tuple,
2168 10228 : get_object_attnum_acl(classid),
2169 : &isNull);
2170 10228 : if (isNull)
2171 : {
2172 7832 : old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2173 : /* There are no old member roles according to the catalogs */
2174 7832 : noldmembers = 0;
2175 7832 : oldmembers = NULL;
2176 : }
2177 : else
2178 : {
2179 2396 : old_acl = DatumGetAclPCopy(aclDatum);
2180 : /* Get the roles mentioned in the existing ACL */
2181 2396 : noldmembers = aclmembers(old_acl, &oldmembers);
2182 : }
2183 :
2184 : /* Determine ID to do the grant as, and available grant options */
2185 10228 : select_best_grantor(GetUserId(), istmt->privileges,
2186 : old_acl, ownerId,
2187 : &grantorId, &avail_goptions);
2188 :
2189 10228 : nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2190 10228 : get_object_attnum_name(classid));
2191 :
2192 : /*
2193 : * Restrict the privileges to what we can actually grant, and emit the
2194 : * standards-mandated warning and error messages.
2195 : */
2196 : this_privileges =
2197 20456 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
2198 10228 : istmt->all_privs, istmt->privileges,
2199 : objectid, grantorId, get_object_type(classid, objectid),
2200 10228 : NameStr(*DatumGetName(nameDatum)),
2201 : 0, NULL);
2202 :
2203 : /*
2204 : * Generate new ACL.
2205 : */
2206 10198 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2207 10198 : istmt->grant_option, istmt->behavior,
2208 : istmt->grantees, this_privileges,
2209 : grantorId, ownerId);
2210 :
2211 : /*
2212 : * We need the members of both old and new ACLs so we can correct the
2213 : * shared dependency information.
2214 : */
2215 10192 : nnewmembers = aclmembers(new_acl, &newmembers);
2216 :
2217 : /* finished building new ACL value, now insert it */
2218 10192 : replaces[get_object_attnum_acl(classid) - 1] = true;
2219 10192 : values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2220 :
2221 10192 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2222 : nulls, replaces);
2223 :
2224 10192 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2225 10192 : UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2226 :
2227 : /* Update initial privileges for extensions */
2228 10192 : recordExtensionInitPriv(objectid, classid, 0, new_acl);
2229 :
2230 : /* Update the shared dependency ACL info */
2231 10192 : updateAclDependencies(classid,
2232 : objectid, 0,
2233 : ownerId,
2234 : noldmembers, oldmembers,
2235 : nnewmembers, newmembers);
2236 :
2237 10192 : ReleaseSysCache(tuple);
2238 :
2239 10192 : pfree(new_acl);
2240 :
2241 : /* prevent error when processing duplicate objects */
2242 10192 : CommandCounterIncrement();
2243 : }
2244 :
2245 10048 : table_close(relation, RowExclusiveLock);
2246 10048 : }
2247 :
2248 : static void
2249 42 : ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
2250 : {
2251 : Form_pg_language pg_language_tuple;
2252 :
2253 42 : pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2254 :
2255 42 : if (!pg_language_tuple->lanpltrusted)
2256 6 : ereport(ERROR,
2257 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2258 : errmsg("language \"%s\" is not trusted",
2259 : NameStr(pg_language_tuple->lanname)),
2260 : errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2261 : "because only superusers can use untrusted languages.")));
2262 36 : }
2263 :
2264 : static void
2265 74 : ExecGrant_Largeobject(InternalGrant *istmt)
2266 : {
2267 : Relation relation;
2268 : ListCell *cell;
2269 :
2270 74 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2271 44 : istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
2272 :
2273 74 : relation = table_open(LargeObjectMetadataRelationId,
2274 : RowExclusiveLock);
2275 :
2276 154 : foreach(cell, istmt->objects)
2277 : {
2278 80 : Oid loid = lfirst_oid(cell);
2279 : Form_pg_largeobject_metadata form_lo_meta;
2280 : char loname[NAMEDATALEN];
2281 : Datum aclDatum;
2282 : bool isNull;
2283 : AclMode avail_goptions;
2284 : AclMode this_privileges;
2285 : Acl *old_acl;
2286 : Acl *new_acl;
2287 : Oid grantorId;
2288 : Oid ownerId;
2289 : HeapTuple newtuple;
2290 80 : Datum values[Natts_pg_largeobject_metadata] = {0};
2291 80 : bool nulls[Natts_pg_largeobject_metadata] = {0};
2292 80 : bool replaces[Natts_pg_largeobject_metadata] = {0};
2293 : int noldmembers;
2294 : int nnewmembers;
2295 : Oid *oldmembers;
2296 : Oid *newmembers;
2297 : ScanKeyData entry[1];
2298 : SysScanDesc scan;
2299 : HeapTuple tuple;
2300 :
2301 : /* There's no syscache for pg_largeobject_metadata */
2302 80 : ScanKeyInit(&entry[0],
2303 : Anum_pg_largeobject_metadata_oid,
2304 : BTEqualStrategyNumber, F_OIDEQ,
2305 : ObjectIdGetDatum(loid));
2306 :
2307 80 : scan = systable_beginscan(relation,
2308 : LargeObjectMetadataOidIndexId, true,
2309 : NULL, 1, entry);
2310 :
2311 80 : tuple = systable_getnext(scan);
2312 80 : if (!HeapTupleIsValid(tuple))
2313 0 : elog(ERROR, "could not find tuple for large object %u", loid);
2314 :
2315 80 : form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2316 :
2317 : /*
2318 : * Get owner ID and working copy of existing ACL. If there's no ACL,
2319 : * substitute the proper default.
2320 : */
2321 80 : ownerId = form_lo_meta->lomowner;
2322 80 : aclDatum = heap_getattr(tuple,
2323 : Anum_pg_largeobject_metadata_lomacl,
2324 : RelationGetDescr(relation), &isNull);
2325 80 : if (isNull)
2326 : {
2327 44 : old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2328 : /* There are no old member roles according to the catalogs */
2329 44 : noldmembers = 0;
2330 44 : oldmembers = NULL;
2331 : }
2332 : else
2333 : {
2334 36 : old_acl = DatumGetAclPCopy(aclDatum);
2335 : /* Get the roles mentioned in the existing ACL */
2336 36 : noldmembers = aclmembers(old_acl, &oldmembers);
2337 : }
2338 :
2339 : /* Determine ID to do the grant as, and available grant options */
2340 80 : select_best_grantor(GetUserId(), istmt->privileges,
2341 : old_acl, ownerId,
2342 : &grantorId, &avail_goptions);
2343 :
2344 : /*
2345 : * Restrict the privileges to what we can actually grant, and emit the
2346 : * standards-mandated warning and error messages.
2347 : */
2348 80 : snprintf(loname, sizeof(loname), "large object %u", loid);
2349 : this_privileges =
2350 80 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
2351 80 : istmt->all_privs, istmt->privileges,
2352 : loid, grantorId, OBJECT_LARGEOBJECT,
2353 : loname, 0, NULL);
2354 :
2355 : /*
2356 : * Generate new ACL.
2357 : */
2358 80 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2359 80 : istmt->grant_option, istmt->behavior,
2360 : istmt->grantees, this_privileges,
2361 : grantorId, ownerId);
2362 :
2363 : /*
2364 : * We need the members of both old and new ACLs so we can correct the
2365 : * shared dependency information.
2366 : */
2367 80 : nnewmembers = aclmembers(new_acl, &newmembers);
2368 :
2369 : /* finished building new ACL value, now insert it */
2370 80 : replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2371 : values[Anum_pg_largeobject_metadata_lomacl - 1]
2372 80 : = PointerGetDatum(new_acl);
2373 :
2374 80 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2375 : values, nulls, replaces);
2376 :
2377 80 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2378 :
2379 : /* Update initial privileges for extensions */
2380 80 : recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2381 :
2382 : /* Update the shared dependency ACL info */
2383 80 : updateAclDependencies(LargeObjectRelationId,
2384 : form_lo_meta->oid, 0,
2385 : ownerId,
2386 : noldmembers, oldmembers,
2387 : nnewmembers, newmembers);
2388 :
2389 80 : systable_endscan(scan);
2390 :
2391 80 : pfree(new_acl);
2392 :
2393 : /* prevent error when processing duplicate objects */
2394 80 : CommandCounterIncrement();
2395 : }
2396 :
2397 74 : table_close(relation, RowExclusiveLock);
2398 74 : }
2399 :
2400 : static void
2401 138 : ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
2402 : {
2403 : Form_pg_type pg_type_tuple;
2404 :
2405 138 : pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2406 :
2407 : /* Disallow GRANT on dependent types */
2408 138 : if (IsTrueArrayType(pg_type_tuple))
2409 6 : ereport(ERROR,
2410 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2411 : errmsg("cannot set privileges of array types"),
2412 : errhint("Set the privileges of the element type instead.")));
2413 132 : if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2414 6 : ereport(ERROR,
2415 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2416 : errmsg("cannot set privileges of multirange types"),
2417 : errhint("Set the privileges of the range type instead.")));
2418 126 : }
2419 :
2420 : static void
2421 96 : ExecGrant_Parameter(InternalGrant *istmt)
2422 : {
2423 : Relation relation;
2424 : ListCell *cell;
2425 :
2426 96 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2427 42 : istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
2428 :
2429 96 : relation = table_open(ParameterAclRelationId, RowExclusiveLock);
2430 :
2431 230 : foreach(cell, istmt->objects)
2432 : {
2433 134 : Oid parameterId = lfirst_oid(cell);
2434 : Datum nameDatum;
2435 : const char *parname;
2436 : Datum aclDatum;
2437 : bool isNull;
2438 : AclMode avail_goptions;
2439 : AclMode this_privileges;
2440 : Acl *old_acl;
2441 : Acl *new_acl;
2442 : Oid grantorId;
2443 : Oid ownerId;
2444 : HeapTuple tuple;
2445 : int noldmembers;
2446 : int nnewmembers;
2447 : Oid *oldmembers;
2448 : Oid *newmembers;
2449 :
2450 134 : tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
2451 134 : if (!HeapTupleIsValid(tuple))
2452 0 : elog(ERROR, "cache lookup failed for parameter ACL %u",
2453 : parameterId);
2454 :
2455 : /* We'll need the GUC's name */
2456 134 : nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
2457 : Anum_pg_parameter_acl_parname);
2458 134 : parname = TextDatumGetCString(nameDatum);
2459 :
2460 : /* Treat all parameters as belonging to the bootstrap superuser. */
2461 134 : ownerId = BOOTSTRAP_SUPERUSERID;
2462 :
2463 : /*
2464 : * Get working copy of existing ACL. If there's no ACL, substitute the
2465 : * proper default.
2466 : */
2467 134 : aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
2468 : Anum_pg_parameter_acl_paracl,
2469 : &isNull);
2470 :
2471 134 : if (isNull)
2472 : {
2473 66 : old_acl = acldefault(istmt->objtype, ownerId);
2474 : /* There are no old member roles according to the catalogs */
2475 66 : noldmembers = 0;
2476 66 : oldmembers = NULL;
2477 : }
2478 : else
2479 : {
2480 68 : old_acl = DatumGetAclPCopy(aclDatum);
2481 : /* Get the roles mentioned in the existing ACL */
2482 68 : noldmembers = aclmembers(old_acl, &oldmembers);
2483 : }
2484 :
2485 : /* Determine ID to do the grant as, and available grant options */
2486 134 : select_best_grantor(GetUserId(), istmt->privileges,
2487 : old_acl, ownerId,
2488 : &grantorId, &avail_goptions);
2489 :
2490 : /*
2491 : * Restrict the privileges to what we can actually grant, and emit the
2492 : * standards-mandated warning and error messages.
2493 : */
2494 : this_privileges =
2495 134 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
2496 134 : istmt->all_privs, istmt->privileges,
2497 : parameterId, grantorId,
2498 : OBJECT_PARAMETER_ACL,
2499 : parname,
2500 : 0, NULL);
2501 :
2502 : /*
2503 : * Generate new ACL.
2504 : */
2505 134 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2506 134 : istmt->grant_option, istmt->behavior,
2507 : istmt->grantees, this_privileges,
2508 : grantorId, ownerId);
2509 :
2510 : /*
2511 : * We need the members of both old and new ACLs so we can correct the
2512 : * shared dependency information.
2513 : */
2514 134 : nnewmembers = aclmembers(new_acl, &newmembers);
2515 :
2516 : /*
2517 : * If the new ACL is equal to the default, we don't need the catalog
2518 : * entry any longer. Delete it rather than updating it, to avoid
2519 : * leaving a degenerate entry.
2520 : */
2521 134 : if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
2522 : {
2523 58 : CatalogTupleDelete(relation, &tuple->t_self);
2524 : }
2525 : else
2526 : {
2527 : /* finished building new ACL value, now insert it */
2528 : HeapTuple newtuple;
2529 76 : Datum values[Natts_pg_parameter_acl] = {0};
2530 76 : bool nulls[Natts_pg_parameter_acl] = {0};
2531 76 : bool replaces[Natts_pg_parameter_acl] = {0};
2532 :
2533 76 : replaces[Anum_pg_parameter_acl_paracl - 1] = true;
2534 76 : values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
2535 :
2536 76 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2537 : values, nulls, replaces);
2538 :
2539 76 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2540 : }
2541 :
2542 : /* Update initial privileges for extensions */
2543 134 : recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
2544 : new_acl);
2545 :
2546 : /* Update the shared dependency ACL info */
2547 134 : updateAclDependencies(ParameterAclRelationId, parameterId, 0,
2548 : ownerId,
2549 : noldmembers, oldmembers,
2550 : nnewmembers, newmembers);
2551 :
2552 134 : ReleaseSysCache(tuple);
2553 134 : pfree(new_acl);
2554 :
2555 : /* prevent error when processing duplicate objects */
2556 134 : CommandCounterIncrement();
2557 : }
2558 :
2559 96 : table_close(relation, RowExclusiveLock);
2560 96 : }
2561 :
2562 :
2563 : static AclMode
2564 27130 : string_to_privilege(const char *privname)
2565 : {
2566 27130 : if (strcmp(privname, "insert") == 0)
2567 234 : return ACL_INSERT;
2568 26896 : if (strcmp(privname, "select") == 0)
2569 16556 : return ACL_SELECT;
2570 10340 : if (strcmp(privname, "update") == 0)
2571 372 : return ACL_UPDATE;
2572 9968 : if (strcmp(privname, "delete") == 0)
2573 120 : return ACL_DELETE;
2574 9848 : if (strcmp(privname, "truncate") == 0)
2575 34 : return ACL_TRUNCATE;
2576 9814 : if (strcmp(privname, "references") == 0)
2577 14 : return ACL_REFERENCES;
2578 9800 : if (strcmp(privname, "trigger") == 0)
2579 8 : return ACL_TRIGGER;
2580 9792 : if (strcmp(privname, "execute") == 0)
2581 8464 : return ACL_EXECUTE;
2582 1328 : if (strcmp(privname, "usage") == 0)
2583 690 : return ACL_USAGE;
2584 638 : if (strcmp(privname, "create") == 0)
2585 290 : return ACL_CREATE;
2586 348 : if (strcmp(privname, "temporary") == 0)
2587 208 : return ACL_CREATE_TEMP;
2588 140 : if (strcmp(privname, "temp") == 0)
2589 2 : return ACL_CREATE_TEMP;
2590 138 : if (strcmp(privname, "connect") == 0)
2591 34 : return ACL_CONNECT;
2592 104 : if (strcmp(privname, "set") == 0)
2593 48 : return ACL_SET;
2594 56 : if (strcmp(privname, "alter system") == 0)
2595 24 : return ACL_ALTER_SYSTEM;
2596 32 : if (strcmp(privname, "maintain") == 0)
2597 32 : return ACL_MAINTAIN;
2598 0 : ereport(ERROR,
2599 : (errcode(ERRCODE_SYNTAX_ERROR),
2600 : errmsg("unrecognized privilege type \"%s\"", privname)));
2601 : return 0; /* appease compiler */
2602 : }
2603 :
2604 : static const char *
2605 24 : privilege_to_string(AclMode privilege)
2606 : {
2607 24 : switch (privilege)
2608 : {
2609 6 : case ACL_INSERT:
2610 6 : return "INSERT";
2611 0 : case ACL_SELECT:
2612 0 : return "SELECT";
2613 0 : case ACL_UPDATE:
2614 0 : return "UPDATE";
2615 0 : case ACL_DELETE:
2616 0 : return "DELETE";
2617 0 : case ACL_TRUNCATE:
2618 0 : return "TRUNCATE";
2619 0 : case ACL_REFERENCES:
2620 0 : return "REFERENCES";
2621 0 : case ACL_TRIGGER:
2622 0 : return "TRIGGER";
2623 0 : case ACL_EXECUTE:
2624 0 : return "EXECUTE";
2625 18 : case ACL_USAGE:
2626 18 : return "USAGE";
2627 0 : case ACL_CREATE:
2628 0 : return "CREATE";
2629 0 : case ACL_CREATE_TEMP:
2630 0 : return "TEMP";
2631 0 : case ACL_CONNECT:
2632 0 : return "CONNECT";
2633 0 : case ACL_SET:
2634 0 : return "SET";
2635 0 : case ACL_ALTER_SYSTEM:
2636 0 : return "ALTER SYSTEM";
2637 0 : case ACL_MAINTAIN:
2638 0 : return "MAINTAIN";
2639 0 : default:
2640 0 : elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2641 : }
2642 : return NULL; /* appease compiler */
2643 : }
2644 :
2645 : /*
2646 : * Standardized reporting of aclcheck permissions failures.
2647 : *
2648 : * Note: we do not double-quote the %s's below, because many callers
2649 : * supply strings that might be already quoted.
2650 : */
2651 : void
2652 2710 : aclcheck_error(AclResult aclerr, ObjectType objtype,
2653 : const char *objectname)
2654 : {
2655 2710 : switch (aclerr)
2656 : {
2657 0 : case ACLCHECK_OK:
2658 : /* no error, so return to caller */
2659 0 : break;
2660 2196 : case ACLCHECK_NO_PRIV:
2661 : {
2662 2196 : const char *msg = "???";
2663 :
2664 : switch (objtype)
2665 : {
2666 6 : case OBJECT_AGGREGATE:
2667 6 : msg = gettext_noop("permission denied for aggregate %s");
2668 6 : break;
2669 0 : case OBJECT_COLLATION:
2670 0 : msg = gettext_noop("permission denied for collation %s");
2671 0 : break;
2672 0 : case OBJECT_COLUMN:
2673 0 : msg = gettext_noop("permission denied for column %s");
2674 0 : break;
2675 0 : case OBJECT_CONVERSION:
2676 0 : msg = gettext_noop("permission denied for conversion %s");
2677 0 : break;
2678 18 : case OBJECT_DATABASE:
2679 18 : msg = gettext_noop("permission denied for database %s");
2680 18 : break;
2681 0 : case OBJECT_DOMAIN:
2682 0 : msg = gettext_noop("permission denied for domain %s");
2683 0 : break;
2684 0 : case OBJECT_EVENT_TRIGGER:
2685 0 : msg = gettext_noop("permission denied for event trigger %s");
2686 0 : break;
2687 0 : case OBJECT_EXTENSION:
2688 0 : msg = gettext_noop("permission denied for extension %s");
2689 0 : break;
2690 44 : case OBJECT_FDW:
2691 44 : msg = gettext_noop("permission denied for foreign-data wrapper %s");
2692 44 : break;
2693 20 : case OBJECT_FOREIGN_SERVER:
2694 20 : msg = gettext_noop("permission denied for foreign server %s");
2695 20 : break;
2696 2 : case OBJECT_FOREIGN_TABLE:
2697 2 : msg = gettext_noop("permission denied for foreign table %s");
2698 2 : break;
2699 102 : case OBJECT_FUNCTION:
2700 102 : msg = gettext_noop("permission denied for function %s");
2701 102 : break;
2702 12 : case OBJECT_INDEX:
2703 12 : msg = gettext_noop("permission denied for index %s");
2704 12 : break;
2705 8 : case OBJECT_LANGUAGE:
2706 8 : msg = gettext_noop("permission denied for language %s");
2707 8 : break;
2708 0 : case OBJECT_LARGEOBJECT:
2709 0 : msg = gettext_noop("permission denied for large object %s");
2710 0 : break;
2711 6 : case OBJECT_MATVIEW:
2712 6 : msg = gettext_noop("permission denied for materialized view %s");
2713 6 : break;
2714 0 : case OBJECT_OPCLASS:
2715 0 : msg = gettext_noop("permission denied for operator class %s");
2716 0 : break;
2717 0 : case OBJECT_OPERATOR:
2718 0 : msg = gettext_noop("permission denied for operator %s");
2719 0 : break;
2720 0 : case OBJECT_OPFAMILY:
2721 0 : msg = gettext_noop("permission denied for operator family %s");
2722 0 : break;
2723 0 : case OBJECT_PARAMETER_ACL:
2724 0 : msg = gettext_noop("permission denied for parameter %s");
2725 0 : break;
2726 0 : case OBJECT_POLICY:
2727 0 : msg = gettext_noop("permission denied for policy %s");
2728 0 : break;
2729 12 : case OBJECT_PROCEDURE:
2730 12 : msg = gettext_noop("permission denied for procedure %s");
2731 12 : break;
2732 0 : case OBJECT_PUBLICATION:
2733 0 : msg = gettext_noop("permission denied for publication %s");
2734 0 : break;
2735 0 : case OBJECT_ROUTINE:
2736 0 : msg = gettext_noop("permission denied for routine %s");
2737 0 : break;
2738 14 : case OBJECT_SCHEMA:
2739 14 : msg = gettext_noop("permission denied for schema %s");
2740 14 : break;
2741 0 : case OBJECT_SEQUENCE:
2742 0 : msg = gettext_noop("permission denied for sequence %s");
2743 0 : break;
2744 0 : case OBJECT_STATISTIC_EXT:
2745 0 : msg = gettext_noop("permission denied for statistics object %s");
2746 0 : break;
2747 0 : case OBJECT_SUBSCRIPTION:
2748 0 : msg = gettext_noop("permission denied for subscription %s");
2749 0 : break;
2750 1410 : case OBJECT_TABLE:
2751 1410 : msg = gettext_noop("permission denied for table %s");
2752 1410 : break;
2753 18 : case OBJECT_TABLESPACE:
2754 18 : msg = gettext_noop("permission denied for tablespace %s");
2755 18 : break;
2756 0 : case OBJECT_TSCONFIGURATION:
2757 0 : msg = gettext_noop("permission denied for text search configuration %s");
2758 0 : break;
2759 0 : case OBJECT_TSDICTIONARY:
2760 0 : msg = gettext_noop("permission denied for text search dictionary %s");
2761 0 : break;
2762 120 : case OBJECT_TYPE:
2763 120 : msg = gettext_noop("permission denied for type %s");
2764 120 : break;
2765 404 : case OBJECT_VIEW:
2766 404 : msg = gettext_noop("permission denied for view %s");
2767 404 : break;
2768 : /* these currently aren't used */
2769 0 : case OBJECT_ACCESS_METHOD:
2770 : case OBJECT_AMOP:
2771 : case OBJECT_AMPROC:
2772 : case OBJECT_ATTRIBUTE:
2773 : case OBJECT_CAST:
2774 : case OBJECT_DEFAULT:
2775 : case OBJECT_DEFACL:
2776 : case OBJECT_DOMCONSTRAINT:
2777 : case OBJECT_PUBLICATION_NAMESPACE:
2778 : case OBJECT_PUBLICATION_REL:
2779 : case OBJECT_ROLE:
2780 : case OBJECT_RULE:
2781 : case OBJECT_TABCONSTRAINT:
2782 : case OBJECT_TRANSFORM:
2783 : case OBJECT_TRIGGER:
2784 : case OBJECT_TSPARSER:
2785 : case OBJECT_TSTEMPLATE:
2786 : case OBJECT_USER_MAPPING:
2787 0 : elog(ERROR, "unsupported object type: %d", objtype);
2788 : }
2789 :
2790 2196 : ereport(ERROR,
2791 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2792 : errmsg(msg, objectname)));
2793 : break;
2794 : }
2795 514 : case ACLCHECK_NOT_OWNER:
2796 : {
2797 514 : const char *msg = "???";
2798 :
2799 : switch (objtype)
2800 : {
2801 6 : case OBJECT_AGGREGATE:
2802 6 : msg = gettext_noop("must be owner of aggregate %s");
2803 6 : break;
2804 0 : case OBJECT_COLLATION:
2805 0 : msg = gettext_noop("must be owner of collation %s");
2806 0 : break;
2807 18 : case OBJECT_CONVERSION:
2808 18 : msg = gettext_noop("must be owner of conversion %s");
2809 18 : break;
2810 0 : case OBJECT_DATABASE:
2811 0 : msg = gettext_noop("must be owner of database %s");
2812 0 : break;
2813 0 : case OBJECT_DOMAIN:
2814 0 : msg = gettext_noop("must be owner of domain %s");
2815 0 : break;
2816 0 : case OBJECT_EVENT_TRIGGER:
2817 0 : msg = gettext_noop("must be owner of event trigger %s");
2818 0 : break;
2819 0 : case OBJECT_EXTENSION:
2820 0 : msg = gettext_noop("must be owner of extension %s");
2821 0 : break;
2822 18 : case OBJECT_FDW:
2823 18 : msg = gettext_noop("must be owner of foreign-data wrapper %s");
2824 18 : break;
2825 114 : case OBJECT_FOREIGN_SERVER:
2826 114 : msg = gettext_noop("must be owner of foreign server %s");
2827 114 : break;
2828 0 : case OBJECT_FOREIGN_TABLE:
2829 0 : msg = gettext_noop("must be owner of foreign table %s");
2830 0 : break;
2831 42 : case OBJECT_FUNCTION:
2832 42 : msg = gettext_noop("must be owner of function %s");
2833 42 : break;
2834 24 : case OBJECT_INDEX:
2835 24 : msg = gettext_noop("must be owner of index %s");
2836 24 : break;
2837 12 : case OBJECT_LANGUAGE:
2838 12 : msg = gettext_noop("must be owner of language %s");
2839 12 : break;
2840 0 : case OBJECT_LARGEOBJECT:
2841 0 : msg = gettext_noop("must be owner of large object %s");
2842 0 : break;
2843 0 : case OBJECT_MATVIEW:
2844 0 : msg = gettext_noop("must be owner of materialized view %s");
2845 0 : break;
2846 18 : case OBJECT_OPCLASS:
2847 18 : msg = gettext_noop("must be owner of operator class %s");
2848 18 : break;
2849 18 : case OBJECT_OPERATOR:
2850 18 : msg = gettext_noop("must be owner of operator %s");
2851 18 : break;
2852 18 : case OBJECT_OPFAMILY:
2853 18 : msg = gettext_noop("must be owner of operator family %s");
2854 18 : break;
2855 6 : case OBJECT_PROCEDURE:
2856 6 : msg = gettext_noop("must be owner of procedure %s");
2857 6 : break;
2858 6 : case OBJECT_PUBLICATION:
2859 6 : msg = gettext_noop("must be owner of publication %s");
2860 6 : break;
2861 0 : case OBJECT_ROUTINE:
2862 0 : msg = gettext_noop("must be owner of routine %s");
2863 0 : break;
2864 6 : case OBJECT_SEQUENCE:
2865 6 : msg = gettext_noop("must be owner of sequence %s");
2866 6 : break;
2867 6 : case OBJECT_SUBSCRIPTION:
2868 6 : msg = gettext_noop("must be owner of subscription %s");
2869 6 : break;
2870 70 : case OBJECT_TABLE:
2871 70 : msg = gettext_noop("must be owner of table %s");
2872 70 : break;
2873 6 : case OBJECT_TYPE:
2874 6 : msg = gettext_noop("must be owner of type %s");
2875 6 : break;
2876 18 : case OBJECT_VIEW:
2877 18 : msg = gettext_noop("must be owner of view %s");
2878 18 : break;
2879 18 : case OBJECT_SCHEMA:
2880 18 : msg = gettext_noop("must be owner of schema %s");
2881 18 : break;
2882 36 : case OBJECT_STATISTIC_EXT:
2883 36 : msg = gettext_noop("must be owner of statistics object %s");
2884 36 : break;
2885 0 : case OBJECT_TABLESPACE:
2886 0 : msg = gettext_noop("must be owner of tablespace %s");
2887 0 : break;
2888 18 : case OBJECT_TSCONFIGURATION:
2889 18 : msg = gettext_noop("must be owner of text search configuration %s");
2890 18 : break;
2891 18 : case OBJECT_TSDICTIONARY:
2892 18 : msg = gettext_noop("must be owner of text search dictionary %s");
2893 18 : break;
2894 :
2895 : /*
2896 : * Special cases: For these, the error message talks
2897 : * about "relation", because that's where the
2898 : * ownership is attached. See also
2899 : * check_object_ownership().
2900 : */
2901 18 : case OBJECT_COLUMN:
2902 : case OBJECT_POLICY:
2903 : case OBJECT_RULE:
2904 : case OBJECT_TABCONSTRAINT:
2905 : case OBJECT_TRIGGER:
2906 18 : msg = gettext_noop("must be owner of relation %s");
2907 18 : break;
2908 : /* these currently aren't used */
2909 0 : case OBJECT_ACCESS_METHOD:
2910 : case OBJECT_AMOP:
2911 : case OBJECT_AMPROC:
2912 : case OBJECT_ATTRIBUTE:
2913 : case OBJECT_CAST:
2914 : case OBJECT_DEFAULT:
2915 : case OBJECT_DEFACL:
2916 : case OBJECT_DOMCONSTRAINT:
2917 : case OBJECT_PARAMETER_ACL:
2918 : case OBJECT_PUBLICATION_NAMESPACE:
2919 : case OBJECT_PUBLICATION_REL:
2920 : case OBJECT_ROLE:
2921 : case OBJECT_TRANSFORM:
2922 : case OBJECT_TSPARSER:
2923 : case OBJECT_TSTEMPLATE:
2924 : case OBJECT_USER_MAPPING:
2925 0 : elog(ERROR, "unsupported object type: %d", objtype);
2926 : }
2927 :
2928 514 : ereport(ERROR,
2929 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2930 : errmsg(msg, objectname)));
2931 : break;
2932 : }
2933 0 : default:
2934 0 : elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2935 : break;
2936 : }
2937 0 : }
2938 :
2939 :
2940 : void
2941 0 : aclcheck_error_col(AclResult aclerr, ObjectType objtype,
2942 : const char *objectname, const char *colname)
2943 : {
2944 0 : switch (aclerr)
2945 : {
2946 0 : case ACLCHECK_OK:
2947 : /* no error, so return to caller */
2948 0 : break;
2949 0 : case ACLCHECK_NO_PRIV:
2950 0 : ereport(ERROR,
2951 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2952 : errmsg("permission denied for column \"%s\" of relation \"%s\"",
2953 : colname, objectname)));
2954 : break;
2955 0 : case ACLCHECK_NOT_OWNER:
2956 : /* relation msg is OK since columns don't have separate owners */
2957 0 : aclcheck_error(aclerr, objtype, objectname);
2958 0 : break;
2959 0 : default:
2960 0 : elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2961 : break;
2962 : }
2963 0 : }
2964 :
2965 :
2966 : /*
2967 : * Special common handling for types: use element type instead of array type,
2968 : * and format nicely
2969 : */
2970 : void
2971 120 : aclcheck_error_type(AclResult aclerr, Oid typeOid)
2972 : {
2973 120 : Oid element_type = get_element_type(typeOid);
2974 :
2975 120 : aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
2976 0 : }
2977 :
2978 :
2979 : /*
2980 : * Relay for the various pg_*_mask routines depending on object kind
2981 : */
2982 : static AclMode
2983 72 : pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
2984 : AclMode mask, AclMaskHow how)
2985 : {
2986 72 : switch (objtype)
2987 : {
2988 0 : case OBJECT_COLUMN:
2989 : return
2990 0 : pg_class_aclmask(object_oid, roleid, mask, how) |
2991 0 : pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
2992 18 : case OBJECT_TABLE:
2993 : case OBJECT_SEQUENCE:
2994 18 : return pg_class_aclmask(object_oid, roleid, mask, how);
2995 0 : case OBJECT_DATABASE:
2996 0 : return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
2997 0 : case OBJECT_FUNCTION:
2998 0 : return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
2999 6 : case OBJECT_LANGUAGE:
3000 6 : return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
3001 0 : case OBJECT_LARGEOBJECT:
3002 0 : return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3003 : mask, how, NULL);
3004 0 : case OBJECT_PARAMETER_ACL:
3005 0 : return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
3006 0 : case OBJECT_SCHEMA:
3007 0 : return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
3008 0 : case OBJECT_STATISTIC_EXT:
3009 0 : elog(ERROR, "grantable rights not supported for statistics objects");
3010 : /* not reached, but keep compiler quiet */
3011 : return ACL_NO_RIGHTS;
3012 0 : case OBJECT_TABLESPACE:
3013 0 : return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3014 18 : case OBJECT_FDW:
3015 18 : return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3016 18 : case OBJECT_FOREIGN_SERVER:
3017 18 : return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3018 0 : case OBJECT_EVENT_TRIGGER:
3019 0 : elog(ERROR, "grantable rights not supported for event triggers");
3020 : /* not reached, but keep compiler quiet */
3021 : return ACL_NO_RIGHTS;
3022 12 : case OBJECT_TYPE:
3023 12 : return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3024 0 : default:
3025 0 : elog(ERROR, "unrecognized object type: %d",
3026 : (int) objtype);
3027 : /* not reached, but keep compiler quiet */
3028 : return ACL_NO_RIGHTS;
3029 : }
3030 : }
3031 :
3032 :
3033 : /* ****************************************************************
3034 : * Exported routines for examining a user's privileges for various objects
3035 : *
3036 : * See aclmask() for a description of the common API for these functions.
3037 : * ****************************************************************
3038 : */
3039 :
3040 : /*
3041 : * Generic routine for examining a user's privileges for an object
3042 : */
3043 : static AclMode
3044 54 : object_aclmask(Oid classid, Oid objectid, Oid roleid,
3045 : AclMode mask, AclMaskHow how)
3046 : {
3047 54 : return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3048 : }
3049 :
3050 : /*
3051 : * Generic routine for examining a user's privileges for an object,
3052 : * with is_missing
3053 : */
3054 : static AclMode
3055 3171916 : object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
3056 : AclMode mask, AclMaskHow how,
3057 : bool *is_missing)
3058 : {
3059 : int cacheid;
3060 : AclMode result;
3061 : HeapTuple tuple;
3062 : Datum aclDatum;
3063 : bool isNull;
3064 : Acl *acl;
3065 : Oid ownerId;
3066 :
3067 : /* Special cases */
3068 3171916 : switch (classid)
3069 : {
3070 961100 : case NamespaceRelationId:
3071 961100 : return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
3072 : is_missing);
3073 347782 : case TypeRelationId:
3074 347782 : return pg_type_aclmask_ext(objectid, roleid, mask, how,
3075 : is_missing);
3076 : }
3077 :
3078 : /* Even more special cases */
3079 : Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3080 : Assert(classid != LargeObjectMetadataRelationId); /* should use
3081 : * pg_largeobject_acl* */
3082 :
3083 : /* Superusers bypass all permission checking. */
3084 1863034 : if (superuser_arg(roleid))
3085 1821284 : return mask;
3086 :
3087 : /*
3088 : * Get the object's ACL from its catalog
3089 : */
3090 :
3091 41750 : cacheid = get_object_catcache_oid(classid);
3092 :
3093 41750 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3094 41750 : if (!HeapTupleIsValid(tuple))
3095 : {
3096 0 : if (is_missing != NULL)
3097 : {
3098 : /* return "no privileges" instead of throwing an error */
3099 0 : *is_missing = true;
3100 0 : return 0;
3101 : }
3102 : else
3103 0 : elog(ERROR, "cache lookup failed for %s %u",
3104 : get_object_class_descr(classid), objectid);
3105 : }
3106 :
3107 41750 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3108 : tuple,
3109 41750 : get_object_attnum_owner(classid)));
3110 :
3111 41750 : aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3112 : &isNull);
3113 41750 : if (isNull)
3114 : {
3115 : /* No ACL, so build default ACL */
3116 39142 : acl = acldefault(get_object_type(classid, objectid), ownerId);
3117 39142 : aclDatum = (Datum) 0;
3118 : }
3119 : else
3120 : {
3121 : /* detoast ACL if necessary */
3122 2608 : acl = DatumGetAclP(aclDatum);
3123 : }
3124 :
3125 41750 : result = aclmask(acl, roleid, ownerId, mask, how);
3126 :
3127 : /* if we have a detoasted copy, free it */
3128 41750 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3129 41750 : pfree(acl);
3130 :
3131 41750 : ReleaseSysCache(tuple);
3132 :
3133 41750 : return result;
3134 : }
3135 :
3136 : /*
3137 : * Routine for examining a user's privileges for a column
3138 : *
3139 : * Note: this considers only privileges granted specifically on the column.
3140 : * It is caller's responsibility to take relation-level privileges into account
3141 : * as appropriate. (For the same reason, we have no special case for
3142 : * superuser-ness here.)
3143 : */
3144 : static AclMode
3145 0 : pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
3146 : AclMode mask, AclMaskHow how)
3147 : {
3148 0 : return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3149 : mask, how, NULL);
3150 : }
3151 :
3152 : /*
3153 : * Routine for examining a user's privileges for a column, with is_missing
3154 : */
3155 : static AclMode
3156 7798 : pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid,
3157 : AclMode mask, AclMaskHow how, bool *is_missing)
3158 : {
3159 : AclMode result;
3160 : HeapTuple classTuple;
3161 : HeapTuple attTuple;
3162 : Form_pg_class classForm;
3163 : Form_pg_attribute attributeForm;
3164 : Datum aclDatum;
3165 : bool isNull;
3166 : Acl *acl;
3167 : Oid ownerId;
3168 :
3169 : /*
3170 : * First, get the column's ACL from its pg_attribute entry
3171 : */
3172 7798 : attTuple = SearchSysCache2(ATTNUM,
3173 : ObjectIdGetDatum(table_oid),
3174 : Int16GetDatum(attnum));
3175 7798 : if (!HeapTupleIsValid(attTuple))
3176 : {
3177 30 : if (is_missing != NULL)
3178 : {
3179 : /* return "no privileges" instead of throwing an error */
3180 30 : *is_missing = true;
3181 30 : return 0;
3182 : }
3183 : else
3184 0 : ereport(ERROR,
3185 : (errcode(ERRCODE_UNDEFINED_COLUMN),
3186 : errmsg("attribute %d of relation with OID %u does not exist",
3187 : attnum, table_oid)));
3188 : }
3189 :
3190 7768 : attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3191 :
3192 : /* Check dropped columns, too */
3193 7768 : if (attributeForm->attisdropped)
3194 : {
3195 12 : if (is_missing != NULL)
3196 : {
3197 : /* return "no privileges" instead of throwing an error */
3198 12 : *is_missing = true;
3199 12 : ReleaseSysCache(attTuple);
3200 12 : return 0;
3201 : }
3202 : else
3203 0 : ereport(ERROR,
3204 : (errcode(ERRCODE_UNDEFINED_COLUMN),
3205 : errmsg("attribute %d of relation with OID %u does not exist",
3206 : attnum, table_oid)));
3207 : }
3208 :
3209 7756 : aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3210 : &isNull);
3211 :
3212 : /*
3213 : * Here we hard-wire knowledge that the default ACL for a column grants no
3214 : * privileges, so that we can fall out quickly in the very common case
3215 : * where attacl is null.
3216 : */
3217 7756 : if (isNull)
3218 : {
3219 4926 : ReleaseSysCache(attTuple);
3220 4926 : return 0;
3221 : }
3222 :
3223 : /*
3224 : * Must get the relation's ownerId from pg_class. Since we already found
3225 : * a pg_attribute entry, the only likely reason for this to fail is that a
3226 : * concurrent DROP of the relation committed since then (which could only
3227 : * happen if we don't have lock on the relation). Treat that similarly to
3228 : * not finding the attribute entry.
3229 : */
3230 2830 : classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3231 2830 : if (!HeapTupleIsValid(classTuple))
3232 : {
3233 0 : ReleaseSysCache(attTuple);
3234 0 : if (is_missing != NULL)
3235 : {
3236 : /* return "no privileges" instead of throwing an error */
3237 0 : *is_missing = true;
3238 0 : return 0;
3239 : }
3240 : else
3241 0 : ereport(ERROR,
3242 : (errcode(ERRCODE_UNDEFINED_TABLE),
3243 : errmsg("relation with OID %u does not exist",
3244 : table_oid)));
3245 : }
3246 2830 : classForm = (Form_pg_class) GETSTRUCT(classTuple);
3247 :
3248 2830 : ownerId = classForm->relowner;
3249 :
3250 2830 : ReleaseSysCache(classTuple);
3251 :
3252 : /* detoast column's ACL if necessary */
3253 2830 : acl = DatumGetAclP(aclDatum);
3254 :
3255 2830 : result = aclmask(acl, roleid, ownerId, mask, how);
3256 :
3257 : /* if we have a detoasted copy, free it */
3258 2830 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3259 2830 : pfree(acl);
3260 :
3261 2830 : ReleaseSysCache(attTuple);
3262 :
3263 2830 : return result;
3264 : }
3265 :
3266 : /*
3267 : * Exported routine for examining a user's privileges for a table
3268 : */
3269 : AclMode
3270 574084 : pg_class_aclmask(Oid table_oid, Oid roleid,
3271 : AclMode mask, AclMaskHow how)
3272 : {
3273 574084 : return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3274 : }
3275 :
3276 : /*
3277 : * Routine for examining a user's privileges for a table, with is_missing
3278 : */
3279 : static AclMode
3280 2945782 : pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
3281 : AclMaskHow how, bool *is_missing)
3282 : {
3283 : AclMode result;
3284 : HeapTuple tuple;
3285 : Form_pg_class classForm;
3286 : Datum aclDatum;
3287 : bool isNull;
3288 : Acl *acl;
3289 : Oid ownerId;
3290 :
3291 : /*
3292 : * Must get the relation's tuple from pg_class
3293 : */
3294 2945782 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3295 2945782 : if (!HeapTupleIsValid(tuple))
3296 : {
3297 8 : if (is_missing != NULL)
3298 : {
3299 : /* return "no privileges" instead of throwing an error */
3300 8 : *is_missing = true;
3301 8 : return 0;
3302 : }
3303 : else
3304 0 : ereport(ERROR,
3305 : (errcode(ERRCODE_UNDEFINED_TABLE),
3306 : errmsg("relation with OID %u does not exist",
3307 : table_oid)));
3308 : }
3309 :
3310 2945774 : classForm = (Form_pg_class) GETSTRUCT(tuple);
3311 :
3312 : /*
3313 : * Deny anyone permission to update a system catalog unless
3314 : * pg_authid.rolsuper is set.
3315 : *
3316 : * As of 7.4 we have some updatable system views; those shouldn't be
3317 : * protected in this way. Assume the view rules can take care of
3318 : * themselves. ACL_USAGE is if we ever have system sequences.
3319 : */
3320 3779352 : if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3321 833578 : IsSystemClass(table_oid, classForm) &&
3322 5116 : classForm->relkind != RELKIND_VIEW &&
3323 5116 : !superuser_arg(roleid))
3324 70 : mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
3325 :
3326 : /*
3327 : * Otherwise, superusers bypass all permission-checking.
3328 : */
3329 2945774 : if (superuser_arg(roleid))
3330 : {
3331 2904974 : ReleaseSysCache(tuple);
3332 2904974 : return mask;
3333 : }
3334 :
3335 : /*
3336 : * Normal case: get the relation's ACL from pg_class
3337 : */
3338 40800 : ownerId = classForm->relowner;
3339 :
3340 40800 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3341 : &isNull);
3342 40800 : if (isNull)
3343 : {
3344 : /* No ACL, so build default ACL */
3345 9084 : switch (classForm->relkind)
3346 : {
3347 48 : case RELKIND_SEQUENCE:
3348 48 : acl = acldefault(OBJECT_SEQUENCE, ownerId);
3349 48 : break;
3350 9036 : default:
3351 9036 : acl = acldefault(OBJECT_TABLE, ownerId);
3352 9036 : break;
3353 : }
3354 9084 : aclDatum = (Datum) 0;
3355 : }
3356 : else
3357 : {
3358 : /* detoast rel's ACL if necessary */
3359 31716 : acl = DatumGetAclP(aclDatum);
3360 : }
3361 :
3362 40800 : result = aclmask(acl, roleid, ownerId, mask, how);
3363 :
3364 : /* if we have a detoasted copy, free it */
3365 40800 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3366 40800 : pfree(acl);
3367 :
3368 40800 : ReleaseSysCache(tuple);
3369 :
3370 : /*
3371 : * Check if ACL_SELECT is being checked and, if so, and not set already as
3372 : * part of the result, then check if the user is a member of the
3373 : * pg_read_all_data role, which allows read access to all relations.
3374 : */
3375 43042 : if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
3376 2242 : has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
3377 12 : result |= ACL_SELECT;
3378 :
3379 : /*
3380 : * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3381 : * so, and not set already as part of the result, then check if the user
3382 : * is a member of the pg_write_all_data role, which allows
3383 : * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3384 : * which requires superuser, see above).
3385 : */
3386 40800 : if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
3387 8566 : !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
3388 1926 : has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
3389 18 : result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
3390 :
3391 : /*
3392 : * Check if ACL_MAINTAIN is being checked and, if so, and not already set
3393 : * as part of the result, then check if the user is a member of the
3394 : * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
3395 : * MATERIALIZED VIEW, REINDEX, and LOCK TABLE on all relations.
3396 : */
3397 40800 : if (mask & ACL_MAINTAIN &&
3398 7432 : !(result & ACL_MAINTAIN) &&
3399 3426 : has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
3400 66 : result |= ACL_MAINTAIN;
3401 :
3402 40800 : return result;
3403 : }
3404 :
3405 : /*
3406 : * Routine for examining a user's privileges for a configuration
3407 : * parameter (GUC), identified by GUC name.
3408 : */
3409 : static AclMode
3410 160 : pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
3411 : {
3412 : AclMode result;
3413 : char *parname;
3414 : text *partext;
3415 : HeapTuple tuple;
3416 :
3417 : /* Superusers bypass all permission checking. */
3418 160 : if (superuser_arg(roleid))
3419 2 : return mask;
3420 :
3421 : /* Convert name to the form it should have in pg_parameter_acl... */
3422 158 : parname = convert_GUC_name_for_parameter_acl(name);
3423 158 : partext = cstring_to_text(parname);
3424 :
3425 : /* ... and look it up */
3426 158 : tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3427 :
3428 158 : if (!HeapTupleIsValid(tuple))
3429 : {
3430 : /* If no entry, GUC has no permissions for non-superusers */
3431 70 : result = ACL_NO_RIGHTS;
3432 : }
3433 : else
3434 : {
3435 : Datum aclDatum;
3436 : bool isNull;
3437 : Acl *acl;
3438 :
3439 88 : aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3440 : Anum_pg_parameter_acl_paracl,
3441 : &isNull);
3442 88 : if (isNull)
3443 : {
3444 : /* No ACL, so build default ACL */
3445 0 : acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3446 0 : aclDatum = (Datum) 0;
3447 : }
3448 : else
3449 : {
3450 : /* detoast ACL if necessary */
3451 88 : acl = DatumGetAclP(aclDatum);
3452 : }
3453 :
3454 88 : result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3455 :
3456 : /* if we have a detoasted copy, free it */
3457 88 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3458 88 : pfree(acl);
3459 :
3460 88 : ReleaseSysCache(tuple);
3461 : }
3462 :
3463 158 : pfree(parname);
3464 158 : pfree(partext);
3465 :
3466 158 : return result;
3467 : }
3468 :
3469 : /*
3470 : * Routine for examining a user's privileges for a configuration
3471 : * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
3472 : */
3473 : static AclMode
3474 0 : pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
3475 : {
3476 : AclMode result;
3477 : HeapTuple tuple;
3478 : Datum aclDatum;
3479 : bool isNull;
3480 : Acl *acl;
3481 :
3482 : /* Superusers bypass all permission checking. */
3483 0 : if (superuser_arg(roleid))
3484 0 : return mask;
3485 :
3486 : /* Get the ACL from pg_parameter_acl */
3487 0 : tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3488 0 : if (!HeapTupleIsValid(tuple))
3489 0 : ereport(ERROR,
3490 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3491 : errmsg("parameter ACL with OID %u does not exist",
3492 : acl_oid)));
3493 :
3494 0 : aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3495 : Anum_pg_parameter_acl_paracl,
3496 : &isNull);
3497 0 : if (isNull)
3498 : {
3499 : /* No ACL, so build default ACL */
3500 0 : acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3501 0 : aclDatum = (Datum) 0;
3502 : }
3503 : else
3504 : {
3505 : /* detoast ACL if necessary */
3506 0 : acl = DatumGetAclP(aclDatum);
3507 : }
3508 :
3509 0 : result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3510 :
3511 : /* if we have a detoasted copy, free it */
3512 0 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3513 0 : pfree(acl);
3514 :
3515 0 : ReleaseSysCache(tuple);
3516 :
3517 0 : return result;
3518 : }
3519 :
3520 : /*
3521 : * Routine for examining a user's privileges for a largeobject
3522 : *
3523 : * When a large object is opened for reading, it is opened relative to the
3524 : * caller's snapshot, but when it is opened for writing, a current
3525 : * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
3526 : * takes a snapshot argument so that the permissions check can be made
3527 : * relative to the same snapshot that will be used to read the underlying
3528 : * data. The caller will actually pass NULL for an instantaneous MVCC
3529 : * snapshot, since all we do with the snapshot argument is pass it through
3530 : * to systable_beginscan().
3531 : */
3532 : static AclMode
3533 774 : pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
3534 : AclMode mask, AclMaskHow how,
3535 : Snapshot snapshot)
3536 : {
3537 : AclMode result;
3538 : Relation pg_lo_meta;
3539 : ScanKeyData entry[1];
3540 : SysScanDesc scan;
3541 : HeapTuple tuple;
3542 : Datum aclDatum;
3543 : bool isNull;
3544 : Acl *acl;
3545 : Oid ownerId;
3546 :
3547 : /* Superusers bypass all permission checking. */
3548 774 : if (superuser_arg(roleid))
3549 480 : return mask;
3550 :
3551 : /*
3552 : * Get the largeobject's ACL from pg_largeobject_metadata
3553 : */
3554 294 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
3555 : AccessShareLock);
3556 :
3557 294 : ScanKeyInit(&entry[0],
3558 : Anum_pg_largeobject_metadata_oid,
3559 : BTEqualStrategyNumber, F_OIDEQ,
3560 : ObjectIdGetDatum(lobj_oid));
3561 :
3562 294 : scan = systable_beginscan(pg_lo_meta,
3563 : LargeObjectMetadataOidIndexId, true,
3564 : snapshot, 1, entry);
3565 :
3566 294 : tuple = systable_getnext(scan);
3567 294 : if (!HeapTupleIsValid(tuple))
3568 0 : ereport(ERROR,
3569 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3570 : errmsg("large object %u does not exist", lobj_oid)));
3571 :
3572 294 : ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
3573 :
3574 294 : aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
3575 : RelationGetDescr(pg_lo_meta), &isNull);
3576 :
3577 294 : if (isNull)
3578 : {
3579 : /* No ACL, so build default ACL */
3580 72 : acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
3581 72 : aclDatum = (Datum) 0;
3582 : }
3583 : else
3584 : {
3585 : /* detoast ACL if necessary */
3586 222 : acl = DatumGetAclP(aclDatum);
3587 : }
3588 :
3589 294 : result = aclmask(acl, roleid, ownerId, mask, how);
3590 :
3591 : /* if we have a detoasted copy, free it */
3592 294 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3593 294 : pfree(acl);
3594 :
3595 294 : systable_endscan(scan);
3596 :
3597 294 : table_close(pg_lo_meta, AccessShareLock);
3598 :
3599 294 : return result;
3600 : }
3601 :
3602 : /*
3603 : * Routine for examining a user's privileges for a namespace, with is_missing
3604 : */
3605 : static AclMode
3606 961100 : pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
3607 : AclMode mask, AclMaskHow how,
3608 : bool *is_missing)
3609 : {
3610 : AclMode result;
3611 : HeapTuple tuple;
3612 : Datum aclDatum;
3613 : bool isNull;
3614 : Acl *acl;
3615 : Oid ownerId;
3616 :
3617 : /* Superusers bypass all permission checking. */
3618 961100 : if (superuser_arg(roleid))
3619 943822 : return mask;
3620 :
3621 : /*
3622 : * If we have been assigned this namespace as a temp namespace, check to
3623 : * make sure we have CREATE TEMP permission on the database, and if so act
3624 : * as though we have all standard (but not GRANT OPTION) permissions on
3625 : * the namespace. If we don't have CREATE TEMP, act as though we have
3626 : * only USAGE (and not CREATE) rights.
3627 : *
3628 : * This may seem redundant given the check in InitTempTableNamespace, but
3629 : * it really isn't since current user ID may have changed since then. The
3630 : * upshot of this behavior is that a SECURITY DEFINER function can create
3631 : * temp tables that can then be accessed (if permission is granted) by
3632 : * code in the same session that doesn't have permissions to create temp
3633 : * tables.
3634 : *
3635 : * XXX Would it be safe to ereport a special error message as
3636 : * InitTempTableNamespace does? Returning zero here means we'll get a
3637 : * generic "permission denied for schema pg_temp_N" message, which is not
3638 : * remarkably user-friendly.
3639 : */
3640 17278 : if (isTempNamespace(nsp_oid))
3641 : {
3642 314 : if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
3643 : ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
3644 314 : return mask & ACL_ALL_RIGHTS_SCHEMA;
3645 : else
3646 0 : return mask & ACL_USAGE;
3647 : }
3648 :
3649 : /*
3650 : * Get the schema's ACL from pg_namespace
3651 : */
3652 16964 : tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
3653 16964 : if (!HeapTupleIsValid(tuple))
3654 : {
3655 0 : if (is_missing != NULL)
3656 : {
3657 : /* return "no privileges" instead of throwing an error */
3658 0 : *is_missing = true;
3659 0 : return 0;
3660 : }
3661 : else
3662 0 : ereport(ERROR,
3663 : (errcode(ERRCODE_UNDEFINED_SCHEMA),
3664 : errmsg("schema with OID %u does not exist", nsp_oid)));
3665 : }
3666 :
3667 16964 : ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3668 :
3669 16964 : aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
3670 : &isNull);
3671 16964 : if (isNull)
3672 : {
3673 : /* No ACL, so build default ACL */
3674 304 : acl = acldefault(OBJECT_SCHEMA, ownerId);
3675 304 : aclDatum = (Datum) 0;
3676 : }
3677 : else
3678 : {
3679 : /* detoast ACL if necessary */
3680 16660 : acl = DatumGetAclP(aclDatum);
3681 : }
3682 :
3683 16964 : result = aclmask(acl, roleid, ownerId, mask, how);
3684 :
3685 : /* if we have a detoasted copy, free it */
3686 16964 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3687 16964 : pfree(acl);
3688 :
3689 16964 : ReleaseSysCache(tuple);
3690 :
3691 : /*
3692 : * Check if ACL_USAGE is being checked and, if so, and not set already as
3693 : * part of the result, then check if the user is a member of the
3694 : * pg_read_all_data or pg_write_all_data roles, which allow usage access
3695 : * to all schemas.
3696 : */
3697 17026 : if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
3698 118 : (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
3699 56 : has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
3700 12 : result |= ACL_USAGE;
3701 16964 : return result;
3702 : }
3703 :
3704 : /*
3705 : * Routine for examining a user's privileges for a type, with is_missing
3706 : */
3707 : static AclMode
3708 347782 : pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
3709 : bool *is_missing)
3710 : {
3711 : AclMode result;
3712 : HeapTuple tuple;
3713 : Form_pg_type typeForm;
3714 : Datum aclDatum;
3715 : bool isNull;
3716 : Acl *acl;
3717 : Oid ownerId;
3718 :
3719 : /* Bypass permission checks for superusers */
3720 347782 : if (superuser_arg(roleid))
3721 343388 : return mask;
3722 :
3723 : /*
3724 : * Must get the type's tuple from pg_type
3725 : */
3726 4394 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3727 4394 : if (!HeapTupleIsValid(tuple))
3728 : {
3729 0 : if (is_missing != NULL)
3730 : {
3731 : /* return "no privileges" instead of throwing an error */
3732 0 : *is_missing = true;
3733 0 : return 0;
3734 : }
3735 : else
3736 0 : ereport(ERROR,
3737 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3738 : errmsg("type with OID %u does not exist",
3739 : type_oid)));
3740 : }
3741 4394 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
3742 :
3743 : /*
3744 : * "True" array types don't manage permissions of their own; consult the
3745 : * element type instead.
3746 : */
3747 4394 : if (IsTrueArrayType(typeForm))
3748 : {
3749 48 : Oid elttype_oid = typeForm->typelem;
3750 :
3751 48 : ReleaseSysCache(tuple);
3752 :
3753 48 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3754 48 : if (!HeapTupleIsValid(tuple))
3755 : {
3756 0 : if (is_missing != NULL)
3757 : {
3758 : /* return "no privileges" instead of throwing an error */
3759 0 : *is_missing = true;
3760 0 : return 0;
3761 : }
3762 : else
3763 0 : ereport(ERROR,
3764 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3765 : errmsg("type with OID %u does not exist",
3766 : elttype_oid)));
3767 : }
3768 48 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
3769 : }
3770 :
3771 : /*
3772 : * Likewise, multirange types don't manage their own permissions; consult
3773 : * the associated range type. (Note we must do this after the array step
3774 : * to get the right answer for arrays of multiranges.)
3775 : */
3776 4394 : if (typeForm->typtype == TYPTYPE_MULTIRANGE)
3777 : {
3778 12 : Oid rangetype = get_multirange_range(typeForm->oid);
3779 :
3780 12 : ReleaseSysCache(tuple);
3781 :
3782 12 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
3783 12 : if (!HeapTupleIsValid(tuple))
3784 : {
3785 0 : if (is_missing != NULL)
3786 : {
3787 : /* return "no privileges" instead of throwing an error */
3788 0 : *is_missing = true;
3789 0 : return 0;
3790 : }
3791 : else
3792 0 : ereport(ERROR,
3793 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3794 : errmsg("type with OID %u does not exist",
3795 : rangetype)));
3796 : }
3797 12 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
3798 : }
3799 :
3800 : /*
3801 : * Now get the type's owner and ACL from the tuple
3802 : */
3803 4394 : ownerId = typeForm->typowner;
3804 :
3805 4394 : aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3806 : Anum_pg_type_typacl, &isNull);
3807 4394 : if (isNull)
3808 : {
3809 : /* No ACL, so build default ACL */
3810 4160 : acl = acldefault(OBJECT_TYPE, ownerId);
3811 4160 : aclDatum = (Datum) 0;
3812 : }
3813 : else
3814 : {
3815 : /* detoast rel's ACL if necessary */
3816 234 : acl = DatumGetAclP(aclDatum);
3817 : }
3818 :
3819 4394 : result = aclmask(acl, roleid, ownerId, mask, how);
3820 :
3821 : /* if we have a detoasted copy, free it */
3822 4394 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3823 4394 : pfree(acl);
3824 :
3825 4394 : ReleaseSysCache(tuple);
3826 :
3827 4394 : return result;
3828 : }
3829 :
3830 : /*
3831 : * Exported generic routine for checking a user's access privileges to an object
3832 : */
3833 : AclResult
3834 3171440 : object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
3835 : {
3836 3171440 : return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3837 : }
3838 :
3839 : /*
3840 : * Exported generic routine for checking a user's access privileges to an
3841 : * object, with is_missing
3842 : */
3843 : AclResult
3844 3171862 : object_aclcheck_ext(Oid classid, Oid objectid,
3845 : Oid roleid, AclMode mode,
3846 : bool *is_missing)
3847 : {
3848 3171862 : if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
3849 : is_missing) != 0)
3850 3171272 : return ACLCHECK_OK;
3851 : else
3852 590 : return ACLCHECK_NO_PRIV;
3853 : }
3854 :
3855 : /*
3856 : * Exported routine for checking a user's access privileges to a column
3857 : *
3858 : * Returns ACLCHECK_OK if the user has any of the privileges identified by
3859 : * 'mode'; otherwise returns a suitable error code (in practice, always
3860 : * ACLCHECK_NO_PRIV).
3861 : *
3862 : * As with pg_attribute_aclmask, only privileges granted directly on the
3863 : * column are considered here.
3864 : */
3865 : AclResult
3866 4090 : pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
3867 : Oid roleid, AclMode mode)
3868 : {
3869 4090 : return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3870 : }
3871 :
3872 :
3873 : /*
3874 : * Exported routine for checking a user's access privileges to a column,
3875 : * with is_missing
3876 : */
3877 : AclResult
3878 7798 : pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
3879 : Oid roleid, AclMode mode, bool *is_missing)
3880 : {
3881 7798 : if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3882 : ACLMASK_ANY, is_missing) != 0)
3883 2296 : return ACLCHECK_OK;
3884 : else
3885 5502 : return ACLCHECK_NO_PRIV;
3886 : }
3887 :
3888 : /*
3889 : * Exported routine for checking a user's access privileges to any/all columns
3890 : *
3891 : * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
3892 : * privileges identified by 'mode' on any non-dropped column in the relation;
3893 : * otherwise returns a suitable error code (in practice, always
3894 : * ACLCHECK_NO_PRIV).
3895 : *
3896 : * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
3897 : * privileges identified by 'mode' on each non-dropped column in the relation
3898 : * (and there must be at least one such column); otherwise returns a suitable
3899 : * error code (in practice, always ACLCHECK_NO_PRIV).
3900 : *
3901 : * As with pg_attribute_aclmask, only privileges granted directly on the
3902 : * column(s) are considered here.
3903 : *
3904 : * Note: system columns are not considered here; there are cases where that
3905 : * might be appropriate but there are also cases where it wouldn't.
3906 : */
3907 : AclResult
3908 174 : pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
3909 : AclMaskHow how)
3910 : {
3911 174 : return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3912 : }
3913 :
3914 : /*
3915 : * Exported routine for checking a user's access privileges to any/all columns,
3916 : * with is_missing
3917 : */
3918 : AclResult
3919 174 : pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid,
3920 : AclMode mode, AclMaskHow how,
3921 : bool *is_missing)
3922 : {
3923 : AclResult result;
3924 : HeapTuple classTuple;
3925 : Form_pg_class classForm;
3926 : Oid ownerId;
3927 : AttrNumber nattrs;
3928 : AttrNumber curr_att;
3929 :
3930 : /*
3931 : * Must fetch pg_class row to get owner ID and number of attributes.
3932 : */
3933 174 : classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3934 174 : if (!HeapTupleIsValid(classTuple))
3935 : {
3936 0 : if (is_missing != NULL)
3937 : {
3938 : /* return "no privileges" instead of throwing an error */
3939 0 : *is_missing = true;
3940 0 : return ACLCHECK_NO_PRIV;
3941 : }
3942 : else
3943 0 : ereport(ERROR,
3944 : (errcode(ERRCODE_UNDEFINED_TABLE),
3945 : errmsg("relation with OID %u does not exist",
3946 : table_oid)));
3947 : }
3948 174 : classForm = (Form_pg_class) GETSTRUCT(classTuple);
3949 :
3950 174 : ownerId = classForm->relowner;
3951 174 : nattrs = classForm->relnatts;
3952 :
3953 174 : ReleaseSysCache(classTuple);
3954 :
3955 : /*
3956 : * Initialize result in case there are no non-dropped columns. We want to
3957 : * report failure in such cases for either value of 'how'.
3958 : */
3959 174 : result = ACLCHECK_NO_PRIV;
3960 :
3961 426 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
3962 : {
3963 : HeapTuple attTuple;
3964 : Datum aclDatum;
3965 : bool isNull;
3966 : Acl *acl;
3967 : AclMode attmask;
3968 :
3969 342 : attTuple = SearchSysCache2(ATTNUM,
3970 : ObjectIdGetDatum(table_oid),
3971 : Int16GetDatum(curr_att));
3972 :
3973 : /*
3974 : * Lookup failure probably indicates that the table was just dropped,
3975 : * but we'll treat it the same as a dropped column rather than
3976 : * throwing error.
3977 : */
3978 342 : if (!HeapTupleIsValid(attTuple))
3979 18 : continue;
3980 :
3981 : /* ignore dropped columns */
3982 342 : if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
3983 : {
3984 18 : ReleaseSysCache(attTuple);
3985 18 : continue;
3986 : }
3987 :
3988 324 : aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3989 : &isNull);
3990 :
3991 : /*
3992 : * Here we hard-wire knowledge that the default ACL for a column
3993 : * grants no privileges, so that we can fall out quickly in the very
3994 : * common case where attacl is null.
3995 : */
3996 324 : if (isNull)
3997 168 : attmask = 0;
3998 : else
3999 : {
4000 : /* detoast column's ACL if necessary */
4001 156 : acl = DatumGetAclP(aclDatum);
4002 :
4003 156 : attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
4004 :
4005 : /* if we have a detoasted copy, free it */
4006 156 : if ((Pointer) acl != DatumGetPointer(aclDatum))
4007 156 : pfree(acl);
4008 : }
4009 :
4010 324 : ReleaseSysCache(attTuple);
4011 :
4012 324 : if (attmask != 0)
4013 : {
4014 138 : result = ACLCHECK_OK;
4015 138 : if (how == ACLMASK_ANY)
4016 90 : break; /* succeed on any success */
4017 : }
4018 : else
4019 : {
4020 186 : result = ACLCHECK_NO_PRIV;
4021 186 : if (how == ACLMASK_ALL)
4022 48 : break; /* fail on any failure */
4023 : }
4024 : }
4025 :
4026 174 : return result;
4027 : }
4028 :
4029 : /*
4030 : * Exported routine for checking a user's access privileges to a table
4031 : *
4032 : * Returns ACLCHECK_OK if the user has any of the privileges identified by
4033 : * 'mode'; otherwise returns a suitable error code (in practice, always
4034 : * ACLCHECK_NO_PRIV).
4035 : */
4036 : AclResult
4037 2367874 : pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
4038 : {
4039 2367874 : return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
4040 : }
4041 :
4042 : /*
4043 : * Exported routine for checking a user's access privileges to a table,
4044 : * with is_missing
4045 : */
4046 : AclResult
4047 2371698 : pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
4048 : AclMode mode, bool *is_missing)
4049 : {
4050 2371698 : if (pg_class_aclmask_ext(table_oid, roleid, mode,
4051 : ACLMASK_ANY, is_missing) != 0)
4052 2367636 : return ACLCHECK_OK;
4053 : else
4054 4062 : return ACLCHECK_NO_PRIV;
4055 : }
4056 :
4057 : /*
4058 : * Exported routine for checking a user's access privileges to a configuration
4059 : * parameter (GUC), identified by GUC name.
4060 : */
4061 : AclResult
4062 160 : pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
4063 : {
4064 160 : if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4065 68 : return ACLCHECK_OK;
4066 : else
4067 92 : return ACLCHECK_NO_PRIV;
4068 : }
4069 :
4070 : /*
4071 : * Exported routine for checking a user's access privileges to a largeobject
4072 : */
4073 : AclResult
4074 774 : pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
4075 : Snapshot snapshot)
4076 : {
4077 774 : if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4078 : ACLMASK_ANY, snapshot) != 0)
4079 648 : return ACLCHECK_OK;
4080 : else
4081 126 : return ACLCHECK_NO_PRIV;
4082 : }
4083 :
4084 : /*
4085 : * Generic ownership check for an object
4086 : */
4087 : bool
4088 488050 : object_ownercheck(Oid classid, Oid objectid, Oid roleid)
4089 : {
4090 : int cacheid;
4091 : Oid ownerId;
4092 :
4093 : /* Superusers bypass all permission checking. */
4094 488050 : if (superuser_arg(roleid))
4095 477094 : return true;
4096 :
4097 : /* For large objects, the catalog to consult is pg_largeobject_metadata */
4098 10956 : if (classid == LargeObjectRelationId)
4099 24 : classid = LargeObjectMetadataRelationId;
4100 :
4101 10956 : cacheid = get_object_catcache_oid(classid);
4102 10956 : if (cacheid != -1)
4103 : {
4104 : /* we can get the object's tuple from the syscache */
4105 : HeapTuple tuple;
4106 :
4107 10928 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4108 10928 : if (!HeapTupleIsValid(tuple))
4109 0 : elog(ERROR, "cache lookup failed for %s %u",
4110 : get_object_class_descr(classid), objectid);
4111 :
4112 10928 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4113 : tuple,
4114 10928 : get_object_attnum_owner(classid)));
4115 10928 : ReleaseSysCache(tuple);
4116 : }
4117 : else
4118 : {
4119 : /* for catalogs without an appropriate syscache */
4120 : Relation rel;
4121 : ScanKeyData entry[1];
4122 : SysScanDesc scan;
4123 : HeapTuple tuple;
4124 : bool isnull;
4125 :
4126 28 : rel = table_open(classid, AccessShareLock);
4127 :
4128 56 : ScanKeyInit(&entry[0],
4129 28 : get_object_attnum_oid(classid),
4130 : BTEqualStrategyNumber, F_OIDEQ,
4131 : ObjectIdGetDatum(objectid));
4132 :
4133 28 : scan = systable_beginscan(rel,
4134 : get_object_oid_index(classid), true,
4135 : NULL, 1, entry);
4136 :
4137 28 : tuple = systable_getnext(scan);
4138 28 : if (!HeapTupleIsValid(tuple))
4139 0 : elog(ERROR, "could not find tuple for %s %u",
4140 : get_object_class_descr(classid), objectid);
4141 :
4142 28 : ownerId = DatumGetObjectId(heap_getattr(tuple,
4143 28 : get_object_attnum_owner(classid),
4144 : RelationGetDescr(rel),
4145 : &isnull));
4146 : Assert(!isnull);
4147 :
4148 28 : systable_endscan(scan);
4149 28 : table_close(rel, AccessShareLock);
4150 : }
4151 :
4152 10956 : return has_privs_of_role(roleid, ownerId);
4153 : }
4154 :
4155 : /*
4156 : * Check whether specified role has CREATEROLE privilege (or is a superuser)
4157 : *
4158 : * Note: roles do not have owners per se; instead we use this test in
4159 : * places where an ownership-like permissions test is needed for a role.
4160 : * Be sure to apply it to the role trying to do the operation, not the
4161 : * role being operated on! Also note that this generally should not be
4162 : * considered enough privilege if the target role is a superuser.
4163 : * (We don't handle that consideration here because we want to give a
4164 : * separate error message for such cases, so the caller has to deal with it.)
4165 : */
4166 : bool
4167 2466 : has_createrole_privilege(Oid roleid)
4168 : {
4169 2466 : bool result = false;
4170 : HeapTuple utup;
4171 :
4172 : /* Superusers bypass all permission checking. */
4173 2466 : if (superuser_arg(roleid))
4174 1936 : return true;
4175 :
4176 530 : utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4177 530 : if (HeapTupleIsValid(utup))
4178 : {
4179 530 : result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4180 530 : ReleaseSysCache(utup);
4181 : }
4182 530 : return result;
4183 : }
4184 :
4185 : bool
4186 5020 : has_bypassrls_privilege(Oid roleid)
4187 : {
4188 5020 : bool result = false;
4189 : HeapTuple utup;
4190 :
4191 : /* Superusers bypass all permission checking. */
4192 5020 : if (superuser_arg(roleid))
4193 1652 : return true;
4194 :
4195 3368 : utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4196 3368 : if (HeapTupleIsValid(utup))
4197 : {
4198 3368 : result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4199 3368 : ReleaseSysCache(utup);
4200 : }
4201 3368 : return result;
4202 : }
4203 :
4204 : /*
4205 : * Fetch pg_default_acl entry for given role, namespace and object type
4206 : * (object type must be given in pg_default_acl's encoding).
4207 : * Returns NULL if no such entry.
4208 : */
4209 : static Acl *
4210 165644 : get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
4211 : {
4212 165644 : Acl *result = NULL;
4213 : HeapTuple tuple;
4214 :
4215 165644 : tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4216 : ObjectIdGetDatum(roleId),
4217 : ObjectIdGetDatum(nsp_oid),
4218 : CharGetDatum(objtype));
4219 :
4220 165644 : if (HeapTupleIsValid(tuple))
4221 : {
4222 : Datum aclDatum;
4223 : bool isNull;
4224 :
4225 264 : aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4226 : Anum_pg_default_acl_defaclacl,
4227 : &isNull);
4228 264 : if (!isNull)
4229 264 : result = DatumGetAclPCopy(aclDatum);
4230 264 : ReleaseSysCache(tuple);
4231 : }
4232 :
4233 165644 : return result;
4234 : }
4235 :
4236 : /*
4237 : * Get default permissions for newly created object within given schema
4238 : *
4239 : * Returns NULL if built-in system defaults should be used.
4240 : *
4241 : * If the result is not NULL, caller must call recordDependencyOnNewAcl
4242 : * once the OID of the new object is known.
4243 : */
4244 : Acl *
4245 82822 : get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
4246 : {
4247 : Acl *result;
4248 : Acl *glob_acl;
4249 : Acl *schema_acl;
4250 : Acl *def_acl;
4251 : char defaclobjtype;
4252 :
4253 : /*
4254 : * Use NULL during bootstrap, since pg_default_acl probably isn't there
4255 : * yet.
4256 : */
4257 82822 : if (IsBootstrapProcessingMode())
4258 0 : return NULL;
4259 :
4260 : /* Check if object type is supported in pg_default_acl */
4261 82822 : switch (objtype)
4262 : {
4263 55600 : case OBJECT_TABLE:
4264 55600 : defaclobjtype = DEFACLOBJ_RELATION;
4265 55600 : break;
4266 :
4267 1792 : case OBJECT_SEQUENCE:
4268 1792 : defaclobjtype = DEFACLOBJ_SEQUENCE;
4269 1792 : break;
4270 :
4271 17606 : case OBJECT_FUNCTION:
4272 17606 : defaclobjtype = DEFACLOBJ_FUNCTION;
4273 17606 : break;
4274 :
4275 6660 : case OBJECT_TYPE:
4276 6660 : defaclobjtype = DEFACLOBJ_TYPE;
4277 6660 : break;
4278 :
4279 1028 : case OBJECT_SCHEMA:
4280 1028 : defaclobjtype = DEFACLOBJ_NAMESPACE;
4281 1028 : break;
4282 :
4283 136 : case OBJECT_LARGEOBJECT:
4284 136 : defaclobjtype = DEFACLOBJ_LARGEOBJECT;
4285 136 : break;
4286 :
4287 0 : default:
4288 0 : return NULL;
4289 : }
4290 :
4291 : /* Look up the relevant pg_default_acl entries */
4292 82822 : glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4293 82822 : schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4294 :
4295 : /* Quick out if neither entry exists */
4296 82822 : if (glob_acl == NULL && schema_acl == NULL)
4297 82612 : return NULL;
4298 :
4299 : /* We need to know the hard-wired default value, too */
4300 210 : def_acl = acldefault(objtype, ownerId);
4301 :
4302 : /* If there's no global entry, substitute the hard-wired default */
4303 210 : if (glob_acl == NULL)
4304 18 : glob_acl = def_acl;
4305 :
4306 : /* Merge in any per-schema privileges */
4307 210 : result = aclmerge(glob_acl, schema_acl, ownerId);
4308 :
4309 : /*
4310 : * For efficiency, we want to return NULL if the result equals default.
4311 : * This requires sorting both arrays to get an accurate comparison.
4312 : */
4313 210 : aclitemsort(result);
4314 210 : aclitemsort(def_acl);
4315 210 : if (aclequal(result, def_acl))
4316 24 : result = NULL;
4317 :
4318 210 : return result;
4319 : }
4320 :
4321 : /*
4322 : * Record dependencies on roles mentioned in a new object's ACL.
4323 : */
4324 : void
4325 86120 : recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
4326 : Oid ownerId, Acl *acl)
4327 : {
4328 : int nmembers;
4329 : Oid *members;
4330 :
4331 : /* Nothing to do if ACL is defaulted */
4332 86120 : if (acl == NULL)
4333 85934 : return;
4334 :
4335 : /* Extract roles mentioned in ACL */
4336 186 : nmembers = aclmembers(acl, &members);
4337 :
4338 : /* Update the shared dependency ACL info */
4339 186 : updateAclDependencies(classId, objectId, objsubId,
4340 : ownerId,
4341 : 0, NULL,
4342 : nmembers, members);
4343 : }
4344 :
4345 : /*
4346 : * Record initial privileges for the top-level object passed in.
4347 : *
4348 : * For the object passed in, this will record its ACL (if any) and the ACLs of
4349 : * any sub-objects (eg: columns) into pg_init_privs.
4350 : */
4351 : void
4352 96 : recordExtObjInitPriv(Oid objoid, Oid classoid)
4353 : {
4354 : /*
4355 : * pg_class / pg_attribute
4356 : *
4357 : * If this is a relation then we need to see if there are any sub-objects
4358 : * (eg: columns) for it and, if so, be sure to call
4359 : * recordExtensionInitPrivWorker() for each one.
4360 : */
4361 96 : if (classoid == RelationRelationId)
4362 : {
4363 : Form_pg_class pg_class_tuple;
4364 : Datum aclDatum;
4365 : bool isNull;
4366 : HeapTuple tuple;
4367 :
4368 16 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4369 16 : if (!HeapTupleIsValid(tuple))
4370 0 : elog(ERROR, "cache lookup failed for relation %u", objoid);
4371 16 : pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4372 :
4373 : /*
4374 : * Indexes don't have permissions, neither do the pg_class rows for
4375 : * composite types. (These cases are unreachable given the
4376 : * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4377 : */
4378 16 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
4379 16 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4380 16 : pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4381 : {
4382 0 : ReleaseSysCache(tuple);
4383 0 : return;
4384 : }
4385 :
4386 : /*
4387 : * If this isn't a sequence then it's possibly going to have
4388 : * column-level ACLs associated with it.
4389 : */
4390 16 : if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4391 : {
4392 : AttrNumber curr_att;
4393 14 : AttrNumber nattrs = pg_class_tuple->relnatts;
4394 :
4395 38 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
4396 : {
4397 : HeapTuple attTuple;
4398 : Datum attaclDatum;
4399 :
4400 24 : attTuple = SearchSysCache2(ATTNUM,
4401 : ObjectIdGetDatum(objoid),
4402 : Int16GetDatum(curr_att));
4403 :
4404 24 : if (!HeapTupleIsValid(attTuple))
4405 0 : continue;
4406 :
4407 : /* ignore dropped columns */
4408 24 : if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4409 : {
4410 2 : ReleaseSysCache(attTuple);
4411 2 : continue;
4412 : }
4413 :
4414 22 : attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4415 : Anum_pg_attribute_attacl,
4416 : &isNull);
4417 :
4418 : /* no need to do anything for a NULL ACL */
4419 22 : if (isNull)
4420 : {
4421 18 : ReleaseSysCache(attTuple);
4422 18 : continue;
4423 : }
4424 :
4425 4 : recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4426 4 : DatumGetAclP(attaclDatum));
4427 :
4428 4 : ReleaseSysCache(attTuple);
4429 : }
4430 : }
4431 :
4432 16 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4433 : &isNull);
4434 :
4435 : /* Add the record, if any, for the top-level object */
4436 16 : if (!isNull)
4437 8 : recordExtensionInitPrivWorker(objoid, classoid, 0,
4438 8 : DatumGetAclP(aclDatum));
4439 :
4440 16 : ReleaseSysCache(tuple);
4441 : }
4442 80 : else if (classoid == LargeObjectRelationId)
4443 : {
4444 : /* For large objects, we must consult pg_largeobject_metadata */
4445 : Datum aclDatum;
4446 : bool isNull;
4447 : HeapTuple tuple;
4448 : ScanKeyData entry[1];
4449 : SysScanDesc scan;
4450 : Relation relation;
4451 :
4452 : /*
4453 : * Note: this is dead code, given that we don't allow large objects to
4454 : * be made extension members. But it seems worth carrying in case
4455 : * some future caller of this function has need for it.
4456 : */
4457 0 : relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4458 :
4459 : /* There's no syscache for pg_largeobject_metadata */
4460 0 : ScanKeyInit(&entry[0],
4461 : Anum_pg_largeobject_metadata_oid,
4462 : BTEqualStrategyNumber, F_OIDEQ,
4463 : ObjectIdGetDatum(objoid));
4464 :
4465 0 : scan = systable_beginscan(relation,
4466 : LargeObjectMetadataOidIndexId, true,
4467 : NULL, 1, entry);
4468 :
4469 0 : tuple = systable_getnext(scan);
4470 0 : if (!HeapTupleIsValid(tuple))
4471 0 : elog(ERROR, "could not find tuple for large object %u", objoid);
4472 :
4473 0 : aclDatum = heap_getattr(tuple,
4474 : Anum_pg_largeobject_metadata_lomacl,
4475 : RelationGetDescr(relation), &isNull);
4476 :
4477 : /* Add the record, if any, for the top-level object */
4478 0 : if (!isNull)
4479 0 : recordExtensionInitPrivWorker(objoid, classoid, 0,
4480 0 : DatumGetAclP(aclDatum));
4481 :
4482 0 : systable_endscan(scan);
4483 : }
4484 : /* This will error on unsupported classoid. */
4485 80 : else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4486 : {
4487 : int cacheid;
4488 : Datum aclDatum;
4489 : bool isNull;
4490 : HeapTuple tuple;
4491 :
4492 58 : cacheid = get_object_catcache_oid(classoid);
4493 58 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
4494 58 : if (!HeapTupleIsValid(tuple))
4495 0 : elog(ERROR, "cache lookup failed for %s %u",
4496 : get_object_class_descr(classoid), objoid);
4497 :
4498 58 : aclDatum = SysCacheGetAttr(cacheid, tuple,
4499 58 : get_object_attnum_acl(classoid),
4500 : &isNull);
4501 :
4502 : /* Add the record, if any, for the top-level object */
4503 58 : if (!isNull)
4504 10 : recordExtensionInitPrivWorker(objoid, classoid, 0,
4505 10 : DatumGetAclP(aclDatum));
4506 :
4507 58 : ReleaseSysCache(tuple);
4508 : }
4509 : }
4510 :
4511 : /*
4512 : * For the object passed in, remove its ACL and the ACLs of any object subIds
4513 : * from pg_init_privs (via recordExtensionInitPrivWorker()).
4514 : */
4515 : void
4516 352 : removeExtObjInitPriv(Oid objoid, Oid classoid)
4517 : {
4518 : /*
4519 : * If this is a relation then we need to see if there are any sub-objects
4520 : * (eg: columns) for it and, if so, be sure to call
4521 : * recordExtensionInitPrivWorker() for each one.
4522 : */
4523 352 : if (classoid == RelationRelationId)
4524 : {
4525 : Form_pg_class pg_class_tuple;
4526 : HeapTuple tuple;
4527 :
4528 70 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4529 70 : if (!HeapTupleIsValid(tuple))
4530 0 : elog(ERROR, "cache lookup failed for relation %u", objoid);
4531 70 : pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4532 :
4533 : /*
4534 : * Indexes don't have permissions, neither do the pg_class rows for
4535 : * composite types. (These cases are unreachable given the
4536 : * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4537 : */
4538 70 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
4539 70 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4540 70 : pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4541 : {
4542 0 : ReleaseSysCache(tuple);
4543 0 : return;
4544 : }
4545 :
4546 : /*
4547 : * If this isn't a sequence then it's possibly going to have
4548 : * column-level ACLs associated with it.
4549 : */
4550 70 : if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4551 : {
4552 : AttrNumber curr_att;
4553 70 : AttrNumber nattrs = pg_class_tuple->relnatts;
4554 :
4555 2356 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
4556 : {
4557 : HeapTuple attTuple;
4558 :
4559 2286 : attTuple = SearchSysCache2(ATTNUM,
4560 : ObjectIdGetDatum(objoid),
4561 : Int16GetDatum(curr_att));
4562 :
4563 2286 : if (!HeapTupleIsValid(attTuple))
4564 0 : continue;
4565 :
4566 : /* when removing, remove all entries, even dropped columns */
4567 :
4568 2286 : recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4569 :
4570 2286 : ReleaseSysCache(attTuple);
4571 : }
4572 : }
4573 :
4574 70 : ReleaseSysCache(tuple);
4575 : }
4576 :
4577 : /* Remove the record, if any, for the top-level object */
4578 352 : recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
4579 : }
4580 :
4581 : /*
4582 : * Record initial ACL for an extension object
4583 : *
4584 : * Can be called at any time, we check if 'creating_extension' is set and, if
4585 : * not, exit immediately.
4586 : *
4587 : * Pass in the object OID, the OID of the class (the OID of the table which
4588 : * the object is defined in) and the 'sub' id of the object (objsubid), if
4589 : * any. If there is no 'sub' id (they are currently only used for columns of
4590 : * tables) then pass in '0'. Finally, pass in the complete ACL to store.
4591 : *
4592 : * If an ACL already exists for this object/sub-object then we will replace
4593 : * it with what is passed in.
4594 : *
4595 : * Passing in NULL for 'new_acl' will result in the entry for the object being
4596 : * removed, if one is found.
4597 : */
4598 : static void
4599 31628 : recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
4600 : {
4601 : /*
4602 : * Generally, we only record the initial privileges when an extension is
4603 : * being created, but because we don't actually use CREATE EXTENSION
4604 : * during binary upgrades with pg_upgrade, there is a variable to let us
4605 : * know that the GRANT and REVOKE statements being issued, while this
4606 : * variable is true, are for the initial privileges of the extension
4607 : * object and therefore we need to record them.
4608 : */
4609 31628 : if (!creating_extension && !binary_upgrade_record_init_privs)
4610 30826 : return;
4611 :
4612 802 : recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4613 : }
4614 :
4615 : /*
4616 : * Record initial ACL for an extension object, worker.
4617 : *
4618 : * This will perform a wholesale replacement of the entire ACL for the object
4619 : * passed in, therefore be sure to pass in the complete new ACL to use.
4620 : *
4621 : * Generally speaking, do *not* use this function directly but instead use
4622 : * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
4623 : * This function does *not* check if 'creating_extension' is set as it is also
4624 : * used when an object is added to or removed from an extension via ALTER
4625 : * EXTENSION ... ADD/DROP.
4626 : */
4627 : static void
4628 3462 : recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
4629 : Acl *new_acl)
4630 : {
4631 : Relation relation;
4632 : ScanKeyData key[3];
4633 : SysScanDesc scan;
4634 : HeapTuple tuple;
4635 : HeapTuple oldtuple;
4636 : int noldmembers;
4637 : int nnewmembers;
4638 : Oid *oldmembers;
4639 : Oid *newmembers;
4640 :
4641 : /* We'll need the role membership of the new ACL. */
4642 3462 : nnewmembers = aclmembers(new_acl, &newmembers);
4643 :
4644 : /* Search pg_init_privs for an existing entry. */
4645 3462 : relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4646 :
4647 3462 : ScanKeyInit(&key[0],
4648 : Anum_pg_init_privs_objoid,
4649 : BTEqualStrategyNumber, F_OIDEQ,
4650 : ObjectIdGetDatum(objoid));
4651 3462 : ScanKeyInit(&key[1],
4652 : Anum_pg_init_privs_classoid,
4653 : BTEqualStrategyNumber, F_OIDEQ,
4654 : ObjectIdGetDatum(classoid));
4655 3462 : ScanKeyInit(&key[2],
4656 : Anum_pg_init_privs_objsubid,
4657 : BTEqualStrategyNumber, F_INT4EQ,
4658 : Int32GetDatum(objsubid));
4659 :
4660 3462 : scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4661 : NULL, 3, key);
4662 :
4663 : /* There should exist only one entry or none. */
4664 3462 : oldtuple = systable_getnext(scan);
4665 :
4666 : /* If we find an entry, update it with the latest ACL. */
4667 3462 : if (HeapTupleIsValid(oldtuple))
4668 : {
4669 274 : Datum values[Natts_pg_init_privs] = {0};
4670 274 : bool nulls[Natts_pg_init_privs] = {0};
4671 274 : bool replace[Natts_pg_init_privs] = {0};
4672 : Datum oldAclDatum;
4673 : bool isNull;
4674 : Acl *old_acl;
4675 :
4676 : /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
4677 274 : oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4678 : RelationGetDescr(relation), &isNull);
4679 : Assert(!isNull);
4680 274 : old_acl = DatumGetAclP(oldAclDatum);
4681 274 : noldmembers = aclmembers(old_acl, &oldmembers);
4682 :
4683 274 : updateInitAclDependencies(classoid, objoid, objsubid,
4684 : noldmembers, oldmembers,
4685 : nnewmembers, newmembers);
4686 :
4687 : /* If we have a new ACL to set, then update the row with it. */
4688 274 : if (new_acl && ACL_NUM(new_acl) != 0)
4689 : {
4690 176 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4691 176 : replace[Anum_pg_init_privs_initprivs - 1] = true;
4692 :
4693 176 : oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4694 : values, nulls, replace);
4695 :
4696 176 : CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4697 : }
4698 : else
4699 : {
4700 : /* new_acl is NULL/empty, so delete the entry we found. */
4701 98 : CatalogTupleDelete(relation, &oldtuple->t_self);
4702 : }
4703 : }
4704 : else
4705 : {
4706 3188 : Datum values[Natts_pg_init_privs] = {0};
4707 3188 : bool nulls[Natts_pg_init_privs] = {0};
4708 :
4709 : /*
4710 : * Only add a new entry if the new ACL is non-NULL.
4711 : *
4712 : * If we are passed in a NULL ACL and no entry exists, we can just
4713 : * fall through and do nothing.
4714 : */
4715 3188 : if (new_acl && ACL_NUM(new_acl) != 0)
4716 : {
4717 : /* No entry found, so add it. */
4718 642 : values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4719 642 : values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4720 642 : values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4721 :
4722 : /* This function only handles initial privileges of extensions */
4723 642 : values[Anum_pg_init_privs_privtype - 1] =
4724 642 : CharGetDatum(INITPRIVS_EXTENSION);
4725 :
4726 642 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4727 :
4728 642 : tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4729 :
4730 642 : CatalogTupleInsert(relation, tuple);
4731 :
4732 : /* Update pg_shdepend, too. */
4733 642 : noldmembers = 0;
4734 642 : oldmembers = NULL;
4735 :
4736 642 : updateInitAclDependencies(classoid, objoid, objsubid,
4737 : noldmembers, oldmembers,
4738 : nnewmembers, newmembers);
4739 : }
4740 : }
4741 :
4742 3462 : systable_endscan(scan);
4743 :
4744 : /* prevent error when processing objects multiple times */
4745 3462 : CommandCounterIncrement();
4746 :
4747 3462 : table_close(relation, RowExclusiveLock);
4748 3462 : }
4749 :
4750 : /*
4751 : * ReplaceRoleInInitPriv
4752 : *
4753 : * Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
4754 : */
4755 : void
4756 24 : ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
4757 : Oid classid, Oid objid, int32 objsubid)
4758 : {
4759 : Relation rel;
4760 : ScanKeyData key[3];
4761 : SysScanDesc scan;
4762 : HeapTuple oldtuple;
4763 : Datum oldAclDatum;
4764 : bool isNull;
4765 : Acl *old_acl;
4766 : Acl *new_acl;
4767 : HeapTuple newtuple;
4768 : int noldmembers;
4769 : int nnewmembers;
4770 : Oid *oldmembers;
4771 : Oid *newmembers;
4772 :
4773 : /* Search for existing pg_init_privs entry for the target object. */
4774 24 : rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4775 :
4776 24 : ScanKeyInit(&key[0],
4777 : Anum_pg_init_privs_objoid,
4778 : BTEqualStrategyNumber, F_OIDEQ,
4779 : ObjectIdGetDatum(objid));
4780 24 : ScanKeyInit(&key[1],
4781 : Anum_pg_init_privs_classoid,
4782 : BTEqualStrategyNumber, F_OIDEQ,
4783 : ObjectIdGetDatum(classid));
4784 24 : ScanKeyInit(&key[2],
4785 : Anum_pg_init_privs_objsubid,
4786 : BTEqualStrategyNumber, F_INT4EQ,
4787 : Int32GetDatum(objsubid));
4788 :
4789 24 : scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4790 : NULL, 3, key);
4791 :
4792 : /* There should exist only one entry or none. */
4793 24 : oldtuple = systable_getnext(scan);
4794 :
4795 24 : if (!HeapTupleIsValid(oldtuple))
4796 : {
4797 : /*
4798 : * Hmm, why are we here if there's no entry? But pack up and go away
4799 : * quietly.
4800 : */
4801 0 : systable_endscan(scan);
4802 0 : table_close(rel, RowExclusiveLock);
4803 0 : return;
4804 : }
4805 :
4806 : /* Get a writable copy of the existing ACL. */
4807 24 : oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4808 : RelationGetDescr(rel), &isNull);
4809 : Assert(!isNull);
4810 24 : old_acl = DatumGetAclPCopy(oldAclDatum);
4811 :
4812 : /*
4813 : * Generate new ACL. This usage of aclnewowner is a bit off-label when
4814 : * oldroleid isn't the owner; but it does the job fine.
4815 : */
4816 24 : new_acl = aclnewowner(old_acl, oldroleid, newroleid);
4817 :
4818 : /*
4819 : * If we end with an empty ACL, delete the pg_init_privs entry. (That
4820 : * probably can't happen here, but we may as well cover the case.)
4821 : */
4822 24 : if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4823 : {
4824 0 : CatalogTupleDelete(rel, &oldtuple->t_self);
4825 : }
4826 : else
4827 : {
4828 24 : Datum values[Natts_pg_init_privs] = {0};
4829 24 : bool nulls[Natts_pg_init_privs] = {0};
4830 24 : bool replaces[Natts_pg_init_privs] = {0};
4831 :
4832 : /* Update existing entry. */
4833 24 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4834 24 : replaces[Anum_pg_init_privs_initprivs - 1] = true;
4835 :
4836 24 : newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4837 : values, nulls, replaces);
4838 24 : CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4839 : }
4840 :
4841 : /*
4842 : * Update the shared dependency ACL info.
4843 : */
4844 24 : noldmembers = aclmembers(old_acl, &oldmembers);
4845 24 : nnewmembers = aclmembers(new_acl, &newmembers);
4846 :
4847 24 : updateInitAclDependencies(classid, objid, objsubid,
4848 : noldmembers, oldmembers,
4849 : nnewmembers, newmembers);
4850 :
4851 24 : systable_endscan(scan);
4852 :
4853 : /* prevent error when processing objects multiple times */
4854 24 : CommandCounterIncrement();
4855 :
4856 24 : table_close(rel, RowExclusiveLock);
4857 : }
4858 :
4859 : /*
4860 : * RemoveRoleFromInitPriv
4861 : *
4862 : * Used by shdepDropOwned to remove mentions of a role in pg_init_privs.
4863 : */
4864 : void
4865 28 : RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
4866 : {
4867 : Relation rel;
4868 : ScanKeyData key[3];
4869 : SysScanDesc scan;
4870 : HeapTuple oldtuple;
4871 : int cacheid;
4872 : HeapTuple objtuple;
4873 : Oid ownerId;
4874 : Datum oldAclDatum;
4875 : bool isNull;
4876 : Acl *old_acl;
4877 : Acl *new_acl;
4878 : HeapTuple newtuple;
4879 : int noldmembers;
4880 : int nnewmembers;
4881 : Oid *oldmembers;
4882 : Oid *newmembers;
4883 :
4884 : /* Search for existing pg_init_privs entry for the target object. */
4885 28 : rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4886 :
4887 28 : ScanKeyInit(&key[0],
4888 : Anum_pg_init_privs_objoid,
4889 : BTEqualStrategyNumber, F_OIDEQ,
4890 : ObjectIdGetDatum(objid));
4891 28 : ScanKeyInit(&key[1],
4892 : Anum_pg_init_privs_classoid,
4893 : BTEqualStrategyNumber, F_OIDEQ,
4894 : ObjectIdGetDatum(classid));
4895 28 : ScanKeyInit(&key[2],
4896 : Anum_pg_init_privs_objsubid,
4897 : BTEqualStrategyNumber, F_INT4EQ,
4898 : Int32GetDatum(objsubid));
4899 :
4900 28 : scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4901 : NULL, 3, key);
4902 :
4903 : /* There should exist only one entry or none. */
4904 28 : oldtuple = systable_getnext(scan);
4905 :
4906 28 : if (!HeapTupleIsValid(oldtuple))
4907 : {
4908 : /*
4909 : * Hmm, why are we here if there's no entry? But pack up and go away
4910 : * quietly.
4911 : */
4912 0 : systable_endscan(scan);
4913 0 : table_close(rel, RowExclusiveLock);
4914 0 : return;
4915 : }
4916 :
4917 : /* Get a writable copy of the existing ACL. */
4918 28 : oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4919 : RelationGetDescr(rel), &isNull);
4920 : Assert(!isNull);
4921 28 : old_acl = DatumGetAclPCopy(oldAclDatum);
4922 :
4923 : /*
4924 : * We need the members of both old and new ACLs so we can correct the
4925 : * shared dependency information. Collect data before
4926 : * merge_acl_with_grant throws away old_acl.
4927 : */
4928 28 : noldmembers = aclmembers(old_acl, &oldmembers);
4929 :
4930 : /* Must find out the owner's OID the hard way. */
4931 28 : cacheid = get_object_catcache_oid(classid);
4932 28 : objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
4933 28 : if (!HeapTupleIsValid(objtuple))
4934 0 : elog(ERROR, "cache lookup failed for %s %u",
4935 : get_object_class_descr(classid), objid);
4936 :
4937 28 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4938 : objtuple,
4939 28 : get_object_attnum_owner(classid)));
4940 28 : ReleaseSysCache(objtuple);
4941 :
4942 : /*
4943 : * Generate new ACL. Grantor of rights is always the same as the owner.
4944 : */
4945 28 : if (old_acl != NULL)
4946 28 : new_acl = merge_acl_with_grant(old_acl,
4947 : false, /* is_grant */
4948 : false, /* grant_option */
4949 : DROP_RESTRICT,
4950 28 : list_make1_oid(roleid),
4951 : ACLITEM_ALL_PRIV_BITS,
4952 : ownerId,
4953 : ownerId);
4954 : else
4955 0 : new_acl = NULL; /* this case shouldn't happen, probably */
4956 :
4957 : /* If we end with an empty ACL, delete the pg_init_privs entry. */
4958 28 : if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4959 : {
4960 0 : CatalogTupleDelete(rel, &oldtuple->t_self);
4961 : }
4962 : else
4963 : {
4964 28 : Datum values[Natts_pg_init_privs] = {0};
4965 28 : bool nulls[Natts_pg_init_privs] = {0};
4966 28 : bool replaces[Natts_pg_init_privs] = {0};
4967 :
4968 : /* Update existing entry. */
4969 28 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4970 28 : replaces[Anum_pg_init_privs_initprivs - 1] = true;
4971 :
4972 28 : newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4973 : values, nulls, replaces);
4974 28 : CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4975 : }
4976 :
4977 : /*
4978 : * Update the shared dependency ACL info.
4979 : */
4980 28 : nnewmembers = aclmembers(new_acl, &newmembers);
4981 :
4982 28 : updateInitAclDependencies(classid, objid, objsubid,
4983 : noldmembers, oldmembers,
4984 : nnewmembers, newmembers);
4985 :
4986 28 : systable_endscan(scan);
4987 :
4988 : /* prevent error when processing objects multiple times */
4989 28 : CommandCounterIncrement();
4990 :
4991 28 : table_close(rel, RowExclusiveLock);
4992 : }
|