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 82246 : 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 82246 : modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
191 :
192 82246 : new_acl = old_acl;
193 :
194 164612 : foreach(j, grantees)
195 : {
196 : AclItem aclitem;
197 : Acl *newer_acl;
198 :
199 82378 : 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 82378 : 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 82378 : 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 82378 : 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 82378 : newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
226 :
227 : /* avoid memory leak when there are many grantees */
228 82366 : pfree(new_acl);
229 82366 : new_acl = newer_acl;
230 : }
231 :
232 82234 : 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 82018 : 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 82018 : switch (objtype)
249 : {
250 52082 : case OBJECT_COLUMN:
251 52082 : whole_mask = ACL_ALL_RIGHTS_COLUMN;
252 52082 : break;
253 19062 : case OBJECT_TABLE:
254 19062 : whole_mask = ACL_ALL_RIGHTS_RELATION;
255 19062 : break;
256 174 : case OBJECT_SEQUENCE:
257 174 : whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
258 174 : break;
259 364 : case OBJECT_DATABASE:
260 364 : whole_mask = ACL_ALL_RIGHTS_DATABASE;
261 364 : break;
262 9208 : case OBJECT_FUNCTION:
263 9208 : whole_mask = ACL_ALL_RIGHTS_FUNCTION;
264 9208 : break;
265 36 : case OBJECT_LANGUAGE:
266 36 : whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
267 36 : break;
268 90 : case OBJECT_LARGEOBJECT:
269 90 : whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
270 90 : break;
271 538 : case OBJECT_SCHEMA:
272 538 : whole_mask = ACL_ALL_RIGHTS_SCHEMA;
273 538 : 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 136 : case OBJECT_PARAMETER_ACL:
291 136 : whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
292 136 : 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 82018 : 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 81982 : this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
325 81982 : if (is_grant)
326 : {
327 17932 : 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 17902 : 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 64050 : 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 64044 : 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 81982 : return this_privileges;
385 : }
386 :
387 : /*
388 : * Called to execute the utility commands GRANT and REVOKE
389 : */
390 : void
391 29950 : ExecuteGrantStmt(GrantStmt *stmt)
392 : {
393 : InternalGrant istmt;
394 : ListCell *cell;
395 : const char *errormsg;
396 : AclMode all_privileges;
397 :
398 29950 : 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 29944 : istmt.is_grant = stmt->is_grant;
418 29944 : istmt.objtype = stmt->objtype;
419 :
420 : /* Collect the OIDs of the target objects */
421 29944 : switch (stmt->targtype)
422 : {
423 29914 : case ACL_TARGET_OBJECT:
424 59796 : istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
425 29914 : stmt->is_grant);
426 29882 : 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 29912 : istmt.col_privs = NIL; /* may get filled below */
439 29912 : istmt.grantees = NIL; /* filled below */
440 29912 : istmt.grant_option = stmt->grant_option;
441 29912 : 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 59920 : foreach(cell, stmt->grantees)
449 : {
450 30014 : RoleSpec *grantee = (RoleSpec *) lfirst(cell);
451 : Oid grantee_uid;
452 :
453 30014 : switch (grantee->roletype)
454 : {
455 25210 : case ROLESPEC_PUBLIC:
456 25210 : grantee_uid = ACL_ID_PUBLIC;
457 25210 : break;
458 4804 : default:
459 4804 : grantee_uid = get_rolespec_oid(grantee, false);
460 4798 : break;
461 : }
462 30008 : 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 29906 : switch (stmt->objtype)
470 : {
471 19476 : 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 19476 : all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
479 19476 : errormsg = gettext_noop("invalid privilege type %s for relation");
480 19476 : 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 354 : case OBJECT_DATABASE:
486 354 : all_privileges = ACL_ALL_RIGHTS_DATABASE;
487 354 : errormsg = gettext_noop("invalid privilege type %s for database");
488 354 : 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 9092 : case OBJECT_FUNCTION:
494 9092 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
495 9092 : errormsg = gettext_noop("invalid privilege type %s for function");
496 9092 : 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 72 : case OBJECT_LARGEOBJECT:
502 72 : all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
503 72 : errormsg = gettext_noop("invalid privilege type %s for large object");
504 72 : break;
505 402 : case OBJECT_SCHEMA:
506 402 : all_privileges = ACL_ALL_RIGHTS_SCHEMA;
507 402 : errormsg = gettext_noop("invalid privilege type %s for schema");
508 402 : 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 74 : case OBJECT_PARAMETER_ACL:
534 74 : all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
535 74 : errormsg = gettext_noop("invalid privilege type %s for parameter");
536 74 : 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 29906 : if (stmt->privileges == NIL)
546 : {
547 2750 : 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 2750 : istmt.privileges = ACL_NO_RIGHTS;
554 : }
555 : else
556 : {
557 27156 : istmt.all_privs = false;
558 27156 : istmt.privileges = ACL_NO_RIGHTS;
559 :
560 54862 : foreach(cell, stmt->privileges)
561 : {
562 27730 : 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 27730 : if (privnode->cols)
570 : {
571 444 : 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 444 : istmt.col_privs = lappend(istmt.col_privs, privnode);
576 444 : continue;
577 : }
578 :
579 27286 : if (privnode->priv_name == NULL) /* parser mistake? */
580 0 : elog(ERROR, "AccessPriv node must specify privilege or columns");
581 27286 : priv = string_to_privilege(privnode->priv_name);
582 :
583 27286 : if (priv & ~all_privileges)
584 24 : ereport(ERROR,
585 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
586 : errmsg(errormsg, privilege_to_string(priv))));
587 :
588 27262 : istmt.privileges |= priv;
589 : }
590 : }
591 :
592 29882 : ExecGrantStmt_oids(&istmt);
593 29810 : }
594 :
595 : /*
596 : * ExecGrantStmt_oids
597 : *
598 : * Internal entry point for granting and revoking privileges.
599 : */
600 : static void
601 30108 : ExecGrantStmt_oids(InternalGrant *istmt)
602 : {
603 30108 : switch (istmt->objtype)
604 : {
605 19598 : case OBJECT_TABLE:
606 : case OBJECT_SEQUENCE:
607 19598 : ExecGrant_Relation(istmt);
608 19580 : break;
609 364 : case OBJECT_DATABASE:
610 364 : ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
611 364 : 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 9166 : case OBJECT_FUNCTION:
623 : case OBJECT_PROCEDURE:
624 : case OBJECT_ROUTINE:
625 9166 : ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
626 9166 : break;
627 42 : case OBJECT_LANGUAGE:
628 42 : ExecGrant_common(istmt, LanguageRelationId, ACL_ALL_RIGHTS_LANGUAGE, ExecGrant_Language_check);
629 36 : break;
630 84 : case OBJECT_LARGEOBJECT:
631 84 : ExecGrant_Largeobject(istmt);
632 84 : break;
633 416 : case OBJECT_SCHEMA:
634 416 : ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
635 416 : break;
636 6 : case OBJECT_TABLESPACE:
637 6 : ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
638 6 : break;
639 98 : case OBJECT_PARAMETER_ACL:
640 98 : ExecGrant_Parameter(istmt);
641 98 : 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 30036 : if (EventTriggerSupportsObjectType(istmt->objtype))
654 29568 : EventTriggerCollectGrant(istmt);
655 30036 : }
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 29914 : objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
678 : {
679 29914 : List *objects = NIL;
680 : ListCell *cell;
681 29914 : const LOCKMODE lockmode = AccessShareLock;
682 :
683 : Assert(objnames != NIL);
684 :
685 29914 : switch (objtype)
686 : {
687 10214 : default:
688 :
689 : /*
690 : * For most object types, we use get_object_address() directly.
691 : */
692 20556 : foreach(cell, objnames)
693 : {
694 : ObjectAddress address;
695 :
696 10366 : address = get_object_address(objtype, lfirst(cell), NULL, lockmode, false);
697 10342 : objects = lappend_oid(objects, address.objectId);
698 : }
699 10190 : break;
700 :
701 19486 : 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 39026 : foreach(cell, objnames)
710 : {
711 19540 : RangeVar *relvar = (RangeVar *) lfirst(cell);
712 : Oid relOid;
713 :
714 19540 : relOid = RangeVarGetRelid(relvar, lockmode, false);
715 19540 : objects = lappend_oid(objects, relOid);
716 : }
717 19486 : 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 76 : case OBJECT_PARAMETER_ACL:
742 :
743 : /*
744 : * Parameters are handled completely differently.
745 : */
746 200 : 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 126 : char *parameter = strVal(lfirst(cell));
759 126 : Oid parameterId = ParameterAclLookup(parameter, true);
760 :
761 126 : 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 124 : if (OidIsValid(parameterId))
773 112 : objects = lappend_oid(objects, parameterId);
774 : }
775 74 : break;
776 : }
777 :
778 29882 : 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 & ~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 %s",
1211 : "GRANT/REVOKE ON SCHEMAS")));
1212 36 : objtype = DEFACLOBJ_NAMESPACE;
1213 36 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1214 24 : this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1215 36 : break;
1216 :
1217 36 : case OBJECT_LARGEOBJECT:
1218 36 : if (OidIsValid(iacls->nspid))
1219 6 : ereport(ERROR,
1220 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1221 : errmsg("cannot use IN SCHEMA clause when using %s",
1222 : "GRANT/REVOKE ON LARGE OBJECTS")));
1223 30 : objtype = DEFACLOBJ_LARGEOBJECT;
1224 30 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1225 18 : this_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
1226 30 : break;
1227 :
1228 0 : default:
1229 0 : elog(ERROR, "unrecognized object type: %d",
1230 : (int) iacls->objtype);
1231 : objtype = 0; /* keep compiler quiet */
1232 : break;
1233 : }
1234 :
1235 : /* Search for existing row for this object type in catalog */
1236 236 : tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1237 : ObjectIdGetDatum(iacls->roleid),
1238 : ObjectIdGetDatum(iacls->nspid),
1239 : CharGetDatum(objtype));
1240 :
1241 236 : if (HeapTupleIsValid(tuple))
1242 : {
1243 : Datum aclDatum;
1244 : bool isNull;
1245 :
1246 90 : aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1247 : Anum_pg_default_acl_defaclacl,
1248 : &isNull);
1249 90 : if (!isNull)
1250 90 : old_acl = DatumGetAclPCopy(aclDatum);
1251 : else
1252 0 : old_acl = NULL; /* this case shouldn't happen, probably */
1253 90 : isNew = false;
1254 : }
1255 : else
1256 : {
1257 146 : old_acl = NULL;
1258 146 : isNew = true;
1259 : }
1260 :
1261 236 : if (old_acl != NULL)
1262 : {
1263 : /*
1264 : * We need the members of both old and new ACLs so we can correct the
1265 : * shared dependency information. Collect data before
1266 : * merge_acl_with_grant throws away old_acl.
1267 : */
1268 90 : noldmembers = aclmembers(old_acl, &oldmembers);
1269 : }
1270 : else
1271 : {
1272 : /* If no or null entry, start with the default ACL value */
1273 146 : old_acl = aclcopy(def_acl);
1274 : /* There are no old member roles according to the catalogs */
1275 146 : noldmembers = 0;
1276 146 : oldmembers = NULL;
1277 : }
1278 :
1279 : /*
1280 : * Generate new ACL. Grantor of rights is always the same as the target
1281 : * role.
1282 : */
1283 236 : new_acl = merge_acl_with_grant(old_acl,
1284 236 : iacls->is_grant,
1285 236 : iacls->grant_option,
1286 : iacls->behavior,
1287 : iacls->grantees,
1288 : this_privileges,
1289 : iacls->roleid,
1290 : iacls->roleid);
1291 :
1292 : /*
1293 : * If the result is the same as the default value, we do not need an
1294 : * explicit pg_default_acl entry, and should in fact remove the entry if
1295 : * it exists. Must sort both arrays to compare properly.
1296 : */
1297 236 : aclitemsort(new_acl);
1298 236 : aclitemsort(def_acl);
1299 236 : if (aclequal(new_acl, def_acl))
1300 : {
1301 : /* delete old entry, if indeed there is one */
1302 62 : if (!isNew)
1303 : {
1304 : ObjectAddress myself;
1305 :
1306 : /*
1307 : * The dependency machinery will take care of removing all
1308 : * associated dependency entries. We use DROP_RESTRICT since
1309 : * there shouldn't be anything depending on this entry.
1310 : */
1311 60 : myself.classId = DefaultAclRelationId;
1312 60 : myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1313 60 : myself.objectSubId = 0;
1314 :
1315 60 : performDeletion(&myself, DROP_RESTRICT, 0);
1316 : }
1317 : }
1318 : else
1319 : {
1320 174 : Datum values[Natts_pg_default_acl] = {0};
1321 174 : bool nulls[Natts_pg_default_acl] = {0};
1322 174 : bool replaces[Natts_pg_default_acl] = {0};
1323 : Oid defAclOid;
1324 :
1325 174 : if (isNew)
1326 : {
1327 : /* insert new entry */
1328 144 : defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1329 : Anum_pg_default_acl_oid);
1330 144 : values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1331 144 : values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1332 144 : values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1333 144 : values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1334 144 : values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1335 :
1336 144 : newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1337 144 : CatalogTupleInsert(rel, newtuple);
1338 : }
1339 : else
1340 : {
1341 30 : defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1342 :
1343 : /* update existing entry */
1344 30 : values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1345 30 : replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1346 :
1347 30 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1348 : values, nulls, replaces);
1349 30 : CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1350 : }
1351 :
1352 : /* these dependencies don't change in an update */
1353 174 : if (isNew)
1354 : {
1355 : /* dependency on role */
1356 144 : recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1357 : iacls->roleid);
1358 :
1359 : /* dependency on namespace */
1360 144 : if (OidIsValid(iacls->nspid))
1361 : {
1362 : ObjectAddress myself,
1363 : referenced;
1364 :
1365 34 : myself.classId = DefaultAclRelationId;
1366 34 : myself.objectId = defAclOid;
1367 34 : myself.objectSubId = 0;
1368 :
1369 34 : referenced.classId = NamespaceRelationId;
1370 34 : referenced.objectId = iacls->nspid;
1371 34 : referenced.objectSubId = 0;
1372 :
1373 34 : recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1374 : }
1375 : }
1376 :
1377 : /*
1378 : * Update the shared dependency ACL info
1379 : */
1380 174 : nnewmembers = aclmembers(new_acl, &newmembers);
1381 :
1382 174 : updateAclDependencies(DefaultAclRelationId,
1383 : defAclOid, 0,
1384 : iacls->roleid,
1385 : noldmembers, oldmembers,
1386 : nnewmembers, newmembers);
1387 :
1388 174 : if (isNew)
1389 144 : InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1390 : else
1391 30 : InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1392 : }
1393 :
1394 236 : if (HeapTupleIsValid(tuple))
1395 90 : ReleaseSysCache(tuple);
1396 :
1397 236 : table_close(rel, RowExclusiveLock);
1398 :
1399 : /* prevent error when processing duplicate objects */
1400 236 : CommandCounterIncrement();
1401 236 : }
1402 :
1403 :
1404 : /*
1405 : * RemoveRoleFromObjectACL
1406 : *
1407 : * Used by shdepDropOwned to remove mentions of a role in ACLs.
1408 : *
1409 : * Notice that this doesn't accept an objsubid parameter, which is a bit bogus
1410 : * since the pg_shdepend record that caused us to call it certainly had one.
1411 : * If, for example, pg_shdepend records the existence of a permission on
1412 : * mytable.mycol, this function will effectively issue a REVOKE ALL ON TABLE
1413 : * mytable. That gets the job done because (per SQL spec) such a REVOKE also
1414 : * revokes per-column permissions. We could not recreate a situation where
1415 : * the role has table-level but not column-level permissions; but it's okay
1416 : * (for now anyway) because this is only used when we're dropping the role
1417 : * and so all its permissions everywhere must go away. At worst it's a bit
1418 : * inefficient if the role has column permissions on several columns of the
1419 : * same table.
1420 : */
1421 : void
1422 262 : RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1423 : {
1424 262 : if (classid == DefaultAclRelationId)
1425 : {
1426 : InternalDefaultACL iacls;
1427 : Form_pg_default_acl pg_default_acl_tuple;
1428 : Relation rel;
1429 : ScanKeyData skey[1];
1430 : SysScanDesc scan;
1431 : HeapTuple tuple;
1432 :
1433 : /* first fetch info needed by SetDefaultACL */
1434 36 : rel = table_open(DefaultAclRelationId, AccessShareLock);
1435 :
1436 36 : ScanKeyInit(&skey[0],
1437 : Anum_pg_default_acl_oid,
1438 : BTEqualStrategyNumber, F_OIDEQ,
1439 : ObjectIdGetDatum(objid));
1440 :
1441 36 : scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1442 : NULL, 1, skey);
1443 :
1444 36 : tuple = systable_getnext(scan);
1445 :
1446 36 : if (!HeapTupleIsValid(tuple))
1447 0 : elog(ERROR, "could not find tuple for default ACL %u", objid);
1448 :
1449 36 : pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1450 :
1451 36 : iacls.roleid = pg_default_acl_tuple->defaclrole;
1452 36 : iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1453 :
1454 36 : switch (pg_default_acl_tuple->defaclobjtype)
1455 : {
1456 6 : case DEFACLOBJ_RELATION:
1457 6 : iacls.objtype = OBJECT_TABLE;
1458 6 : break;
1459 6 : case DEFACLOBJ_SEQUENCE:
1460 6 : iacls.objtype = OBJECT_SEQUENCE;
1461 6 : break;
1462 6 : case DEFACLOBJ_FUNCTION:
1463 6 : iacls.objtype = OBJECT_FUNCTION;
1464 6 : break;
1465 6 : case DEFACLOBJ_TYPE:
1466 6 : iacls.objtype = OBJECT_TYPE;
1467 6 : break;
1468 6 : case DEFACLOBJ_NAMESPACE:
1469 6 : iacls.objtype = OBJECT_SCHEMA;
1470 6 : break;
1471 6 : case DEFACLOBJ_LARGEOBJECT:
1472 6 : iacls.objtype = OBJECT_LARGEOBJECT;
1473 6 : break;
1474 0 : default:
1475 : /* Shouldn't get here */
1476 0 : elog(ERROR, "unexpected default ACL type: %d",
1477 : (int) pg_default_acl_tuple->defaclobjtype);
1478 : break;
1479 : }
1480 :
1481 36 : systable_endscan(scan);
1482 36 : table_close(rel, AccessShareLock);
1483 :
1484 36 : iacls.is_grant = false;
1485 36 : iacls.all_privs = true;
1486 36 : iacls.privileges = ACL_NO_RIGHTS;
1487 36 : iacls.grantees = list_make1_oid(roleid);
1488 36 : iacls.grant_option = false;
1489 36 : iacls.behavior = DROP_CASCADE;
1490 :
1491 : /* Do it */
1492 36 : SetDefaultACL(&iacls);
1493 : }
1494 : else
1495 : {
1496 : InternalGrant istmt;
1497 :
1498 226 : switch (classid)
1499 : {
1500 100 : case RelationRelationId:
1501 : /* it's OK to use TABLE for a sequence */
1502 100 : istmt.objtype = OBJECT_TABLE;
1503 100 : break;
1504 10 : case DatabaseRelationId:
1505 10 : istmt.objtype = OBJECT_DATABASE;
1506 10 : break;
1507 6 : case TypeRelationId:
1508 6 : istmt.objtype = OBJECT_TYPE;
1509 6 : break;
1510 38 : case ProcedureRelationId:
1511 38 : istmt.objtype = OBJECT_ROUTINE;
1512 38 : break;
1513 0 : case LanguageRelationId:
1514 0 : istmt.objtype = OBJECT_LANGUAGE;
1515 0 : break;
1516 18 : case LargeObjectRelationId:
1517 18 : istmt.objtype = OBJECT_LARGEOBJECT;
1518 18 : break;
1519 14 : case NamespaceRelationId:
1520 14 : istmt.objtype = OBJECT_SCHEMA;
1521 14 : break;
1522 0 : case TableSpaceRelationId:
1523 0 : istmt.objtype = OBJECT_TABLESPACE;
1524 0 : break;
1525 14 : case ForeignServerRelationId:
1526 14 : istmt.objtype = OBJECT_FOREIGN_SERVER;
1527 14 : break;
1528 2 : case ForeignDataWrapperRelationId:
1529 2 : istmt.objtype = OBJECT_FDW;
1530 2 : break;
1531 24 : case ParameterAclRelationId:
1532 24 : istmt.objtype = OBJECT_PARAMETER_ACL;
1533 24 : break;
1534 0 : default:
1535 0 : elog(ERROR, "unexpected object class %u", classid);
1536 : break;
1537 : }
1538 226 : istmt.is_grant = false;
1539 226 : istmt.objects = list_make1_oid(objid);
1540 226 : istmt.all_privs = true;
1541 226 : istmt.privileges = ACL_NO_RIGHTS;
1542 226 : istmt.col_privs = NIL;
1543 226 : istmt.grantees = list_make1_oid(roleid);
1544 226 : istmt.grant_option = false;
1545 226 : istmt.behavior = DROP_CASCADE;
1546 :
1547 226 : ExecGrantStmt_oids(&istmt);
1548 : }
1549 262 : }
1550 :
1551 :
1552 : /*
1553 : * expand_col_privileges
1554 : *
1555 : * OR the specified privilege(s) into per-column array entries for each
1556 : * specified attribute. The per-column array is indexed starting at
1557 : * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1558 : */
1559 : static void
1560 444 : expand_col_privileges(List *colnames, Oid table_oid,
1561 : AclMode this_privileges,
1562 : AclMode *col_privileges,
1563 : int num_col_privileges)
1564 : {
1565 : ListCell *cell;
1566 :
1567 3030 : foreach(cell, colnames)
1568 : {
1569 2586 : char *colname = strVal(lfirst(cell));
1570 : AttrNumber attnum;
1571 :
1572 2586 : attnum = get_attnum(table_oid, colname);
1573 2586 : if (attnum == InvalidAttrNumber)
1574 0 : ereport(ERROR,
1575 : (errcode(ERRCODE_UNDEFINED_COLUMN),
1576 : errmsg("column \"%s\" of relation \"%s\" does not exist",
1577 : colname, get_rel_name(table_oid))));
1578 2586 : attnum -= FirstLowInvalidHeapAttributeNumber;
1579 2586 : if (attnum <= 0 || attnum >= num_col_privileges)
1580 0 : elog(ERROR, "column number out of range"); /* safety check */
1581 2586 : col_privileges[attnum] |= this_privileges;
1582 : }
1583 444 : }
1584 :
1585 : /*
1586 : * expand_all_col_privileges
1587 : *
1588 : * OR the specified privilege(s) into per-column array entries for each valid
1589 : * attribute of a relation. The per-column array is indexed starting at
1590 : * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1591 : */
1592 : static void
1593 6710 : expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
1594 : AclMode this_privileges,
1595 : AclMode *col_privileges,
1596 : int num_col_privileges)
1597 : {
1598 : AttrNumber curr_att;
1599 :
1600 : Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1601 6710 : for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1602 69636 : curr_att <= classForm->relnatts;
1603 62926 : curr_att++)
1604 : {
1605 : HeapTuple attTuple;
1606 : bool isdropped;
1607 :
1608 62926 : if (curr_att == InvalidAttrNumber)
1609 6710 : continue;
1610 :
1611 : /* Views don't have any system columns at all */
1612 56216 : if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1613 6672 : continue;
1614 :
1615 49544 : attTuple = SearchSysCache2(ATTNUM,
1616 : ObjectIdGetDatum(table_oid),
1617 : Int16GetDatum(curr_att));
1618 49544 : if (!HeapTupleIsValid(attTuple))
1619 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1620 : curr_att, table_oid);
1621 :
1622 49544 : isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1623 :
1624 49544 : ReleaseSysCache(attTuple);
1625 :
1626 : /* ignore dropped columns */
1627 49544 : if (isdropped)
1628 6 : continue;
1629 :
1630 49538 : col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1631 : }
1632 6710 : }
1633 :
1634 : /*
1635 : * This processes attributes, but expects to be called from
1636 : * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1637 : */
1638 : static void
1639 52082 : ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
1640 : AttrNumber attnum, Oid ownerId, AclMode col_privileges,
1641 : Relation attRelation, const Acl *old_rel_acl)
1642 : {
1643 : HeapTuple attr_tuple;
1644 : Form_pg_attribute pg_attribute_tuple;
1645 : Acl *old_acl;
1646 : Acl *new_acl;
1647 : Acl *merged_acl;
1648 : Datum aclDatum;
1649 : bool isNull;
1650 : Oid grantorId;
1651 : AclMode avail_goptions;
1652 : bool need_update;
1653 : HeapTuple newtuple;
1654 52082 : Datum values[Natts_pg_attribute] = {0};
1655 52082 : bool nulls[Natts_pg_attribute] = {0};
1656 52082 : bool replaces[Natts_pg_attribute] = {0};
1657 : int noldmembers;
1658 : int nnewmembers;
1659 : Oid *oldmembers;
1660 : Oid *newmembers;
1661 :
1662 52082 : attr_tuple = SearchSysCache2(ATTNUM,
1663 : ObjectIdGetDatum(relOid),
1664 : Int16GetDatum(attnum));
1665 52082 : if (!HeapTupleIsValid(attr_tuple))
1666 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1667 : attnum, relOid);
1668 52082 : pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1669 :
1670 : /*
1671 : * Get working copy of existing ACL. If there's no ACL, substitute the
1672 : * proper default.
1673 : */
1674 52082 : aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1675 : &isNull);
1676 52082 : if (isNull)
1677 : {
1678 51772 : old_acl = acldefault(OBJECT_COLUMN, ownerId);
1679 : /* There are no old member roles according to the catalogs */
1680 51772 : noldmembers = 0;
1681 51772 : oldmembers = NULL;
1682 : }
1683 : else
1684 : {
1685 310 : old_acl = DatumGetAclPCopy(aclDatum);
1686 : /* Get the roles mentioned in the existing ACL */
1687 310 : noldmembers = aclmembers(old_acl, &oldmembers);
1688 : }
1689 :
1690 : /*
1691 : * In select_best_grantor we should consider existing table-level ACL bits
1692 : * as well as the per-column ACL. Build a new ACL that is their
1693 : * concatenation. (This is a bit cheap and dirty compared to merging them
1694 : * properly with no duplications, but it's all we need here.)
1695 : */
1696 52082 : merged_acl = aclconcat(old_rel_acl, old_acl);
1697 :
1698 : /* Determine ID to do the grant as, and available grant options */
1699 52082 : select_best_grantor(GetUserId(), col_privileges,
1700 : merged_acl, ownerId,
1701 : &grantorId, &avail_goptions);
1702 :
1703 52082 : pfree(merged_acl);
1704 :
1705 : /*
1706 : * Restrict the privileges to what we can actually grant, and emit the
1707 : * standards-mandated warning and error messages. Note: we don't track
1708 : * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1709 : * each column; we just approximate it by whether all the possible
1710 : * privileges are specified now. Since the all_privs flag only determines
1711 : * whether a warning is issued, this seems close enough.
1712 : */
1713 : col_privileges =
1714 52082 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
1715 : (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1716 : col_privileges,
1717 : relOid, grantorId, OBJECT_COLUMN,
1718 : relname, attnum,
1719 52082 : NameStr(pg_attribute_tuple->attname));
1720 :
1721 : /*
1722 : * Generate new ACL.
1723 : */
1724 52082 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1725 52082 : istmt->grant_option,
1726 : istmt->behavior, istmt->grantees,
1727 : col_privileges, grantorId,
1728 : ownerId);
1729 :
1730 : /*
1731 : * We need the members of both old and new ACLs so we can correct the
1732 : * shared dependency information.
1733 : */
1734 52082 : nnewmembers = aclmembers(new_acl, &newmembers);
1735 :
1736 : /* finished building new ACL value, now insert it */
1737 :
1738 : /*
1739 : * If the updated ACL is empty, we can set attacl to null, and maybe even
1740 : * avoid an update of the pg_attribute row. This is worth testing because
1741 : * we'll come through here multiple times for any relation-level REVOKE,
1742 : * even if there were never any column GRANTs. Note we are assuming that
1743 : * the "default" ACL state for columns is empty.
1744 : */
1745 52082 : if (ACL_NUM(new_acl) > 0)
1746 : {
1747 2610 : values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1748 2610 : need_update = true;
1749 : }
1750 : else
1751 : {
1752 49472 : nulls[Anum_pg_attribute_attacl - 1] = true;
1753 49472 : need_update = !isNull;
1754 : }
1755 52082 : replaces[Anum_pg_attribute_attacl - 1] = true;
1756 :
1757 52082 : if (need_update)
1758 : {
1759 2706 : newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1760 : values, nulls, replaces);
1761 :
1762 2706 : CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1763 :
1764 : /* Update initial privileges for extensions */
1765 2706 : recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1766 2706 : ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1767 :
1768 : /* Update the shared dependency ACL info */
1769 2706 : updateAclDependencies(RelationRelationId, relOid, attnum,
1770 : ownerId,
1771 : noldmembers, oldmembers,
1772 : nnewmembers, newmembers);
1773 : }
1774 :
1775 52082 : pfree(new_acl);
1776 :
1777 52082 : ReleaseSysCache(attr_tuple);
1778 52082 : }
1779 :
1780 : /*
1781 : * This processes both sequences and non-sequences.
1782 : */
1783 : static void
1784 19598 : ExecGrant_Relation(InternalGrant *istmt)
1785 : {
1786 : Relation relation;
1787 : Relation attRelation;
1788 : ListCell *cell;
1789 :
1790 19598 : relation = table_open(RelationRelationId, RowExclusiveLock);
1791 19598 : attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1792 :
1793 39244 : foreach(cell, istmt->objects)
1794 : {
1795 19664 : Oid relOid = lfirst_oid(cell);
1796 : Datum aclDatum;
1797 : Form_pg_class pg_class_tuple;
1798 : bool isNull;
1799 : AclMode this_privileges;
1800 : AclMode *col_privileges;
1801 : int num_col_privileges;
1802 : bool have_col_privileges;
1803 : Acl *old_acl;
1804 : Acl *old_rel_acl;
1805 : int noldmembers;
1806 : Oid *oldmembers;
1807 : Oid ownerId;
1808 : HeapTuple tuple;
1809 : ListCell *cell_colprivs;
1810 :
1811 19664 : tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relOid));
1812 19664 : if (!HeapTupleIsValid(tuple))
1813 2 : elog(ERROR, "cache lookup failed for relation %u", relOid);
1814 19662 : pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1815 :
1816 : /* Not sensible to grant on an index */
1817 19662 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
1818 19662 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1819 0 : ereport(ERROR,
1820 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1821 : errmsg("\"%s\" is an index",
1822 : NameStr(pg_class_tuple->relname))));
1823 :
1824 : /* Composite types aren't tables either */
1825 19662 : if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1826 0 : ereport(ERROR,
1827 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1828 : errmsg("\"%s\" is a composite type",
1829 : NameStr(pg_class_tuple->relname))));
1830 :
1831 : /* Used GRANT SEQUENCE on a non-sequence? */
1832 19662 : if (istmt->objtype == OBJECT_SEQUENCE &&
1833 22 : pg_class_tuple->relkind != RELKIND_SEQUENCE)
1834 0 : ereport(ERROR,
1835 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1836 : errmsg("\"%s\" is not a sequence",
1837 : NameStr(pg_class_tuple->relname))));
1838 :
1839 : /* Adjust the default permissions based on object type */
1840 19662 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1841 : {
1842 2188 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1843 80 : this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1844 : else
1845 2108 : this_privileges = ACL_ALL_RIGHTS_RELATION;
1846 : }
1847 : else
1848 17474 : this_privileges = istmt->privileges;
1849 :
1850 : /*
1851 : * The GRANT TABLE syntax can be used for sequences and non-sequences,
1852 : * so we have to look at the relkind to determine the supported
1853 : * permissions. The OR of table and sequence permissions were already
1854 : * checked.
1855 : */
1856 19662 : if (istmt->objtype == OBJECT_TABLE)
1857 : {
1858 19640 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1859 : {
1860 : /*
1861 : * For backward compatibility, just throw a warning for
1862 : * invalid sequence permissions when using the non-sequence
1863 : * GRANT syntax.
1864 : */
1865 152 : if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1866 : {
1867 : /*
1868 : * Mention the object name because the user needs to know
1869 : * which operations succeeded. This is required because
1870 : * WARNING allows the command to continue.
1871 : */
1872 0 : ereport(WARNING,
1873 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1874 : errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1875 : NameStr(pg_class_tuple->relname))));
1876 0 : this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1877 : }
1878 : }
1879 : else
1880 : {
1881 19488 : if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1882 : {
1883 : /*
1884 : * USAGE is the only permission supported by sequences but
1885 : * not by non-sequences. Don't mention the object name
1886 : * because we didn't in the combined TABLE | SEQUENCE
1887 : * check.
1888 : */
1889 0 : ereport(ERROR,
1890 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1891 : errmsg("invalid privilege type %s for table",
1892 : "USAGE")));
1893 : }
1894 : }
1895 : }
1896 :
1897 : /*
1898 : * Set up array in which we'll accumulate any column privilege bits
1899 : * that need modification. The array is indexed such that entry [0]
1900 : * corresponds to FirstLowInvalidHeapAttributeNumber.
1901 : */
1902 19662 : num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1903 19662 : col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1904 19662 : have_col_privileges = false;
1905 :
1906 : /*
1907 : * If we are revoking relation privileges that are also column
1908 : * privileges, we must implicitly revoke them from each column too,
1909 : * per SQL spec. (We don't need to implicitly add column privileges
1910 : * during GRANT because the permissions-checking code always checks
1911 : * both relation and per-column privileges.)
1912 : */
1913 19662 : if (!istmt->is_grant &&
1914 6768 : (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1915 : {
1916 6710 : expand_all_col_privileges(relOid, pg_class_tuple,
1917 : this_privileges & ACL_ALL_RIGHTS_COLUMN,
1918 : col_privileges,
1919 : num_col_privileges);
1920 6710 : have_col_privileges = true;
1921 : }
1922 :
1923 : /*
1924 : * Get owner ID and working copy of existing ACL. If there's no ACL,
1925 : * substitute the proper default.
1926 : */
1927 19662 : ownerId = pg_class_tuple->relowner;
1928 19662 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1929 : &isNull);
1930 19662 : if (isNull)
1931 : {
1932 9022 : switch (pg_class_tuple->relkind)
1933 : {
1934 92 : case RELKIND_SEQUENCE:
1935 92 : old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1936 92 : break;
1937 8930 : default:
1938 8930 : old_acl = acldefault(OBJECT_TABLE, ownerId);
1939 8930 : break;
1940 : }
1941 : /* There are no old member roles according to the catalogs */
1942 9022 : noldmembers = 0;
1943 9022 : oldmembers = NULL;
1944 : }
1945 : else
1946 : {
1947 10640 : old_acl = DatumGetAclPCopy(aclDatum);
1948 : /* Get the roles mentioned in the existing ACL */
1949 10640 : noldmembers = aclmembers(old_acl, &oldmembers);
1950 : }
1951 :
1952 : /* Need an extra copy of original rel ACL for column handling */
1953 19662 : old_rel_acl = aclcopy(old_acl);
1954 :
1955 : /*
1956 : * Handle relation-level privileges, if any were specified
1957 : */
1958 19662 : if (this_privileges != ACL_NO_RIGHTS)
1959 : {
1960 : AclMode avail_goptions;
1961 : Acl *new_acl;
1962 : Oid grantorId;
1963 : HeapTuple newtuple;
1964 19236 : Datum values[Natts_pg_class] = {0};
1965 19236 : bool nulls[Natts_pg_class] = {0};
1966 19236 : bool replaces[Natts_pg_class] = {0};
1967 : int nnewmembers;
1968 : Oid *newmembers;
1969 : ObjectType objtype;
1970 :
1971 : /* Determine ID to do the grant as, and available grant options */
1972 19236 : select_best_grantor(GetUserId(), this_privileges,
1973 : old_acl, ownerId,
1974 : &grantorId, &avail_goptions);
1975 :
1976 19236 : switch (pg_class_tuple->relkind)
1977 : {
1978 174 : case RELKIND_SEQUENCE:
1979 174 : objtype = OBJECT_SEQUENCE;
1980 174 : break;
1981 19062 : default:
1982 19062 : objtype = OBJECT_TABLE;
1983 19062 : break;
1984 : }
1985 :
1986 : /*
1987 : * Restrict the privileges to what we can actually grant, and emit
1988 : * the standards-mandated warning and error messages.
1989 : */
1990 : this_privileges =
1991 19236 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
1992 19236 : istmt->all_privs, this_privileges,
1993 : relOid, grantorId, objtype,
1994 19236 : NameStr(pg_class_tuple->relname),
1995 : 0, NULL);
1996 :
1997 : /*
1998 : * Generate new ACL.
1999 : */
2000 19230 : new_acl = merge_acl_with_grant(old_acl,
2001 19230 : istmt->is_grant,
2002 19230 : istmt->grant_option,
2003 : istmt->behavior,
2004 : istmt->grantees,
2005 : this_privileges,
2006 : grantorId,
2007 : ownerId);
2008 :
2009 : /*
2010 : * We need the members of both old and new ACLs so we can correct
2011 : * the shared dependency information.
2012 : */
2013 19224 : nnewmembers = aclmembers(new_acl, &newmembers);
2014 :
2015 : /* finished building new ACL value, now insert it */
2016 19224 : replaces[Anum_pg_class_relacl - 1] = true;
2017 19224 : values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
2018 :
2019 19224 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2020 : values, nulls, replaces);
2021 :
2022 19224 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2023 19220 : UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2024 :
2025 : /* Update initial privileges for extensions */
2026 19220 : recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2027 :
2028 : /* Update the shared dependency ACL info */
2029 19220 : updateAclDependencies(RelationRelationId, relOid, 0,
2030 : ownerId,
2031 : noldmembers, oldmembers,
2032 : nnewmembers, newmembers);
2033 :
2034 19220 : pfree(new_acl);
2035 : }
2036 : else
2037 426 : UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2038 :
2039 : /*
2040 : * Handle column-level privileges, if any were specified or implied.
2041 : * We first expand the user-specified column privileges into the
2042 : * array, and then iterate over all nonempty array entries.
2043 : */
2044 20090 : foreach(cell_colprivs, istmt->col_privs)
2045 : {
2046 444 : AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2047 :
2048 444 : if (col_privs->priv_name == NULL)
2049 18 : this_privileges = ACL_ALL_RIGHTS_COLUMN;
2050 : else
2051 426 : this_privileges = string_to_privilege(col_privs->priv_name);
2052 :
2053 444 : if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2054 0 : ereport(ERROR,
2055 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2056 : errmsg("invalid privilege type %s for column",
2057 : privilege_to_string(this_privileges))));
2058 :
2059 444 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2060 0 : this_privileges & ~((AclMode) ACL_SELECT))
2061 : {
2062 : /*
2063 : * The only column privilege allowed on sequences is SELECT.
2064 : * This is a warning not error because we do it that way for
2065 : * relation-level privileges.
2066 : */
2067 0 : ereport(WARNING,
2068 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2069 : errmsg("sequence \"%s\" only supports SELECT column privileges",
2070 : NameStr(pg_class_tuple->relname))));
2071 :
2072 0 : this_privileges &= (AclMode) ACL_SELECT;
2073 : }
2074 :
2075 444 : expand_col_privileges(col_privs->cols, relOid,
2076 : this_privileges,
2077 : col_privileges,
2078 : num_col_privileges);
2079 444 : have_col_privileges = true;
2080 : }
2081 :
2082 19646 : if (have_col_privileges)
2083 : {
2084 : AttrNumber i;
2085 :
2086 83634 : for (i = 0; i < num_col_privileges; i++)
2087 : {
2088 76498 : if (col_privileges[i] == ACL_NO_RIGHTS)
2089 24416 : continue;
2090 52082 : ExecGrant_Attribute(istmt,
2091 : relOid,
2092 52082 : NameStr(pg_class_tuple->relname),
2093 52082 : i + FirstLowInvalidHeapAttributeNumber,
2094 : ownerId,
2095 52082 : col_privileges[i],
2096 : attRelation,
2097 : old_rel_acl);
2098 : }
2099 : }
2100 :
2101 19646 : pfree(old_rel_acl);
2102 19646 : pfree(col_privileges);
2103 :
2104 19646 : ReleaseSysCache(tuple);
2105 :
2106 : /* prevent error when processing duplicate objects */
2107 19646 : CommandCounterIncrement();
2108 : }
2109 :
2110 19580 : table_close(attRelation, RowExclusiveLock);
2111 19580 : table_close(relation, RowExclusiveLock);
2112 19580 : }
2113 :
2114 : static void
2115 10328 : ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
2116 : void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
2117 : {
2118 : int cacheid;
2119 : Relation relation;
2120 : ListCell *cell;
2121 :
2122 10328 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2123 744 : istmt->privileges = default_privs;
2124 :
2125 10328 : cacheid = get_object_catcache_oid(classid);
2126 :
2127 10328 : relation = table_open(classid, RowExclusiveLock);
2128 :
2129 20766 : foreach(cell, istmt->objects)
2130 : {
2131 10492 : Oid objectid = lfirst_oid(cell);
2132 : Datum aclDatum;
2133 : Datum nameDatum;
2134 : bool isNull;
2135 : AclMode avail_goptions;
2136 : AclMode this_privileges;
2137 : Acl *old_acl;
2138 : Acl *new_acl;
2139 : Oid grantorId;
2140 : Oid ownerId;
2141 : HeapTuple tuple;
2142 : HeapTuple newtuple;
2143 10492 : Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2144 10492 : bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2145 10492 : bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2146 : int noldmembers;
2147 : int nnewmembers;
2148 : Oid *oldmembers;
2149 : Oid *newmembers;
2150 :
2151 10492 : tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid));
2152 10492 : if (!HeapTupleIsValid(tuple))
2153 0 : elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2154 :
2155 : /*
2156 : * Additional object-type-specific checks
2157 : */
2158 10492 : if (object_check)
2159 180 : object_check(istmt, tuple);
2160 :
2161 : /*
2162 : * Get owner ID and working copy of existing ACL. If there's no ACL,
2163 : * substitute the proper default.
2164 : */
2165 10474 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2166 : tuple,
2167 10474 : get_object_attnum_owner(classid)));
2168 10474 : aclDatum = SysCacheGetAttr(cacheid,
2169 : tuple,
2170 10474 : get_object_attnum_acl(classid),
2171 : &isNull);
2172 10474 : if (isNull)
2173 : {
2174 7992 : old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2175 : /* There are no old member roles according to the catalogs */
2176 7992 : noldmembers = 0;
2177 7992 : oldmembers = NULL;
2178 : }
2179 : else
2180 : {
2181 2482 : old_acl = DatumGetAclPCopy(aclDatum);
2182 : /* Get the roles mentioned in the existing ACL */
2183 2482 : noldmembers = aclmembers(old_acl, &oldmembers);
2184 : }
2185 :
2186 : /* Determine ID to do the grant as, and available grant options */
2187 10474 : select_best_grantor(GetUserId(), istmt->privileges,
2188 : old_acl, ownerId,
2189 : &grantorId, &avail_goptions);
2190 :
2191 10474 : nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2192 10474 : get_object_attnum_name(classid));
2193 :
2194 : /*
2195 : * Restrict the privileges to what we can actually grant, and emit the
2196 : * standards-mandated warning and error messages.
2197 : */
2198 : this_privileges =
2199 20948 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
2200 10474 : istmt->all_privs, istmt->privileges,
2201 : objectid, grantorId, get_object_type(classid, objectid),
2202 10474 : NameStr(*DatumGetName(nameDatum)),
2203 : 0, NULL);
2204 :
2205 : /*
2206 : * Generate new ACL.
2207 : */
2208 10444 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2209 10444 : istmt->grant_option, istmt->behavior,
2210 : istmt->grantees, this_privileges,
2211 : grantorId, ownerId);
2212 :
2213 : /*
2214 : * We need the members of both old and new ACLs so we can correct the
2215 : * shared dependency information.
2216 : */
2217 10438 : nnewmembers = aclmembers(new_acl, &newmembers);
2218 :
2219 : /* finished building new ACL value, now insert it */
2220 10438 : replaces[get_object_attnum_acl(classid) - 1] = true;
2221 10438 : values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2222 :
2223 10438 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2224 : nulls, replaces);
2225 :
2226 10438 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2227 10438 : UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2228 :
2229 : /* Update initial privileges for extensions */
2230 10438 : recordExtensionInitPriv(objectid, classid, 0, new_acl);
2231 :
2232 : /* Update the shared dependency ACL info */
2233 10438 : updateAclDependencies(classid,
2234 : objectid, 0,
2235 : ownerId,
2236 : noldmembers, oldmembers,
2237 : nnewmembers, newmembers);
2238 :
2239 10438 : ReleaseSysCache(tuple);
2240 :
2241 10438 : pfree(new_acl);
2242 :
2243 : /* prevent error when processing duplicate objects */
2244 10438 : CommandCounterIncrement();
2245 : }
2246 :
2247 10274 : table_close(relation, RowExclusiveLock);
2248 10274 : }
2249 :
2250 : static void
2251 42 : ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
2252 : {
2253 : Form_pg_language pg_language_tuple;
2254 :
2255 42 : pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2256 :
2257 42 : if (!pg_language_tuple->lanpltrusted)
2258 6 : ereport(ERROR,
2259 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2260 : errmsg("language \"%s\" is not trusted",
2261 : NameStr(pg_language_tuple->lanname)),
2262 : errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2263 : "because only superusers can use untrusted languages.")));
2264 36 : }
2265 :
2266 : static void
2267 84 : ExecGrant_Largeobject(InternalGrant *istmt)
2268 : {
2269 : Relation relation;
2270 : ListCell *cell;
2271 :
2272 84 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2273 44 : istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
2274 :
2275 84 : relation = table_open(LargeObjectMetadataRelationId,
2276 : RowExclusiveLock);
2277 :
2278 174 : foreach(cell, istmt->objects)
2279 : {
2280 90 : Oid loid = lfirst_oid(cell);
2281 : Form_pg_largeobject_metadata form_lo_meta;
2282 : char loname[NAMEDATALEN];
2283 : Datum aclDatum;
2284 : bool isNull;
2285 : AclMode avail_goptions;
2286 : AclMode this_privileges;
2287 : Acl *old_acl;
2288 : Acl *new_acl;
2289 : Oid grantorId;
2290 : Oid ownerId;
2291 : HeapTuple newtuple;
2292 90 : Datum values[Natts_pg_largeobject_metadata] = {0};
2293 90 : bool nulls[Natts_pg_largeobject_metadata] = {0};
2294 90 : bool replaces[Natts_pg_largeobject_metadata] = {0};
2295 : int noldmembers;
2296 : int nnewmembers;
2297 : Oid *oldmembers;
2298 : Oid *newmembers;
2299 : ScanKeyData entry[1];
2300 : SysScanDesc scan;
2301 : HeapTuple tuple;
2302 :
2303 : /* There's no syscache for pg_largeobject_metadata */
2304 90 : ScanKeyInit(&entry[0],
2305 : Anum_pg_largeobject_metadata_oid,
2306 : BTEqualStrategyNumber, F_OIDEQ,
2307 : ObjectIdGetDatum(loid));
2308 :
2309 90 : scan = systable_beginscan(relation,
2310 : LargeObjectMetadataOidIndexId, true,
2311 : NULL, 1, entry);
2312 :
2313 90 : tuple = systable_getnext(scan);
2314 90 : if (!HeapTupleIsValid(tuple))
2315 0 : elog(ERROR, "could not find tuple for large object %u", loid);
2316 :
2317 90 : form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2318 :
2319 : /*
2320 : * Get owner ID and working copy of existing ACL. If there's no ACL,
2321 : * substitute the proper default.
2322 : */
2323 90 : ownerId = form_lo_meta->lomowner;
2324 90 : aclDatum = heap_getattr(tuple,
2325 : Anum_pg_largeobject_metadata_lomacl,
2326 : RelationGetDescr(relation), &isNull);
2327 90 : if (isNull)
2328 : {
2329 54 : old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2330 : /* There are no old member roles according to the catalogs */
2331 54 : noldmembers = 0;
2332 54 : oldmembers = NULL;
2333 : }
2334 : else
2335 : {
2336 36 : old_acl = DatumGetAclPCopy(aclDatum);
2337 : /* Get the roles mentioned in the existing ACL */
2338 36 : noldmembers = aclmembers(old_acl, &oldmembers);
2339 : }
2340 :
2341 : /* Determine ID to do the grant as, and available grant options */
2342 90 : select_best_grantor(GetUserId(), istmt->privileges,
2343 : old_acl, ownerId,
2344 : &grantorId, &avail_goptions);
2345 :
2346 : /*
2347 : * Restrict the privileges to what we can actually grant, and emit the
2348 : * standards-mandated warning and error messages.
2349 : */
2350 90 : snprintf(loname, sizeof(loname), "large object %u", loid);
2351 : this_privileges =
2352 90 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
2353 90 : istmt->all_privs, istmt->privileges,
2354 : loid, grantorId, OBJECT_LARGEOBJECT,
2355 : loname, 0, NULL);
2356 :
2357 : /*
2358 : * Generate new ACL.
2359 : */
2360 90 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2361 90 : istmt->grant_option, istmt->behavior,
2362 : istmt->grantees, this_privileges,
2363 : grantorId, ownerId);
2364 :
2365 : /*
2366 : * We need the members of both old and new ACLs so we can correct the
2367 : * shared dependency information.
2368 : */
2369 90 : nnewmembers = aclmembers(new_acl, &newmembers);
2370 :
2371 : /* finished building new ACL value, now insert it */
2372 90 : replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2373 : values[Anum_pg_largeobject_metadata_lomacl - 1]
2374 90 : = PointerGetDatum(new_acl);
2375 :
2376 90 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2377 : values, nulls, replaces);
2378 :
2379 90 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2380 :
2381 : /* Update initial privileges for extensions */
2382 90 : recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2383 :
2384 : /* Update the shared dependency ACL info */
2385 90 : updateAclDependencies(LargeObjectRelationId,
2386 : form_lo_meta->oid, 0,
2387 : ownerId,
2388 : noldmembers, oldmembers,
2389 : nnewmembers, newmembers);
2390 :
2391 90 : systable_endscan(scan);
2392 :
2393 90 : pfree(new_acl);
2394 :
2395 : /* prevent error when processing duplicate objects */
2396 90 : CommandCounterIncrement();
2397 : }
2398 :
2399 84 : table_close(relation, RowExclusiveLock);
2400 84 : }
2401 :
2402 : static void
2403 138 : ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
2404 : {
2405 : Form_pg_type pg_type_tuple;
2406 :
2407 138 : pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2408 :
2409 : /* Disallow GRANT on dependent types */
2410 138 : if (IsTrueArrayType(pg_type_tuple))
2411 6 : ereport(ERROR,
2412 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2413 : errmsg("cannot set privileges of array types"),
2414 : errhint("Set the privileges of the element type instead.")));
2415 132 : if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2416 6 : ereport(ERROR,
2417 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2418 : errmsg("cannot set privileges of multirange types"),
2419 : errhint("Set the privileges of the range type instead.")));
2420 126 : }
2421 :
2422 : static void
2423 98 : ExecGrant_Parameter(InternalGrant *istmt)
2424 : {
2425 : Relation relation;
2426 : ListCell *cell;
2427 :
2428 98 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2429 42 : istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
2430 :
2431 98 : relation = table_open(ParameterAclRelationId, RowExclusiveLock);
2432 :
2433 234 : foreach(cell, istmt->objects)
2434 : {
2435 136 : Oid parameterId = lfirst_oid(cell);
2436 : Datum nameDatum;
2437 : const char *parname;
2438 : Datum aclDatum;
2439 : bool isNull;
2440 : AclMode avail_goptions;
2441 : AclMode this_privileges;
2442 : Acl *old_acl;
2443 : Acl *new_acl;
2444 : Oid grantorId;
2445 : Oid ownerId;
2446 : HeapTuple tuple;
2447 : int noldmembers;
2448 : int nnewmembers;
2449 : Oid *oldmembers;
2450 : Oid *newmembers;
2451 :
2452 136 : tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
2453 136 : if (!HeapTupleIsValid(tuple))
2454 0 : elog(ERROR, "cache lookup failed for parameter ACL %u",
2455 : parameterId);
2456 :
2457 : /* We'll need the GUC's name */
2458 136 : nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
2459 : Anum_pg_parameter_acl_parname);
2460 136 : parname = TextDatumGetCString(nameDatum);
2461 :
2462 : /* Treat all parameters as belonging to the bootstrap superuser. */
2463 136 : ownerId = BOOTSTRAP_SUPERUSERID;
2464 :
2465 : /*
2466 : * Get working copy of existing ACL. If there's no ACL, substitute the
2467 : * proper default.
2468 : */
2469 136 : aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
2470 : Anum_pg_parameter_acl_paracl,
2471 : &isNull);
2472 :
2473 136 : if (isNull)
2474 : {
2475 66 : old_acl = acldefault(istmt->objtype, ownerId);
2476 : /* There are no old member roles according to the catalogs */
2477 66 : noldmembers = 0;
2478 66 : oldmembers = NULL;
2479 : }
2480 : else
2481 : {
2482 70 : old_acl = DatumGetAclPCopy(aclDatum);
2483 : /* Get the roles mentioned in the existing ACL */
2484 70 : noldmembers = aclmembers(old_acl, &oldmembers);
2485 : }
2486 :
2487 : /* Determine ID to do the grant as, and available grant options */
2488 136 : select_best_grantor(GetUserId(), istmt->privileges,
2489 : old_acl, ownerId,
2490 : &grantorId, &avail_goptions);
2491 :
2492 : /*
2493 : * Restrict the privileges to what we can actually grant, and emit the
2494 : * standards-mandated warning and error messages.
2495 : */
2496 : this_privileges =
2497 136 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
2498 136 : istmt->all_privs, istmt->privileges,
2499 : parameterId, grantorId,
2500 : OBJECT_PARAMETER_ACL,
2501 : parname,
2502 : 0, NULL);
2503 :
2504 : /*
2505 : * Generate new ACL.
2506 : */
2507 136 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2508 136 : istmt->grant_option, istmt->behavior,
2509 : istmt->grantees, this_privileges,
2510 : grantorId, ownerId);
2511 :
2512 : /*
2513 : * We need the members of both old and new ACLs so we can correct the
2514 : * shared dependency information.
2515 : */
2516 136 : nnewmembers = aclmembers(new_acl, &newmembers);
2517 :
2518 : /*
2519 : * If the new ACL is equal to the default, we don't need the catalog
2520 : * entry any longer. Delete it rather than updating it, to avoid
2521 : * leaving a degenerate entry.
2522 : */
2523 136 : if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
2524 : {
2525 60 : CatalogTupleDelete(relation, &tuple->t_self);
2526 : }
2527 : else
2528 : {
2529 : /* finished building new ACL value, now insert it */
2530 : HeapTuple newtuple;
2531 76 : Datum values[Natts_pg_parameter_acl] = {0};
2532 76 : bool nulls[Natts_pg_parameter_acl] = {0};
2533 76 : bool replaces[Natts_pg_parameter_acl] = {0};
2534 :
2535 76 : replaces[Anum_pg_parameter_acl_paracl - 1] = true;
2536 76 : values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
2537 :
2538 76 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2539 : values, nulls, replaces);
2540 :
2541 76 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2542 : }
2543 :
2544 : /* Update initial privileges for extensions */
2545 136 : recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
2546 : new_acl);
2547 :
2548 : /* Update the shared dependency ACL info */
2549 136 : updateAclDependencies(ParameterAclRelationId, parameterId, 0,
2550 : ownerId,
2551 : noldmembers, oldmembers,
2552 : nnewmembers, newmembers);
2553 :
2554 136 : ReleaseSysCache(tuple);
2555 136 : pfree(new_acl);
2556 :
2557 : /* prevent error when processing duplicate objects */
2558 136 : CommandCounterIncrement();
2559 : }
2560 :
2561 98 : table_close(relation, RowExclusiveLock);
2562 98 : }
2563 :
2564 :
2565 : static AclMode
2566 27840 : string_to_privilege(const char *privname)
2567 : {
2568 27840 : if (strcmp(privname, "insert") == 0)
2569 240 : return ACL_INSERT;
2570 27600 : if (strcmp(privname, "select") == 0)
2571 17002 : return ACL_SELECT;
2572 10598 : if (strcmp(privname, "update") == 0)
2573 386 : return ACL_UPDATE;
2574 10212 : if (strcmp(privname, "delete") == 0)
2575 126 : return ACL_DELETE;
2576 10086 : if (strcmp(privname, "truncate") == 0)
2577 40 : return ACL_TRUNCATE;
2578 10046 : if (strcmp(privname, "references") == 0)
2579 14 : return ACL_REFERENCES;
2580 10032 : if (strcmp(privname, "trigger") == 0)
2581 8 : return ACL_TRIGGER;
2582 10024 : if (strcmp(privname, "execute") == 0)
2583 8640 : return ACL_EXECUTE;
2584 1384 : if (strcmp(privname, "usage") == 0)
2585 700 : return ACL_USAGE;
2586 684 : if (strcmp(privname, "create") == 0)
2587 324 : return ACL_CREATE;
2588 360 : if (strcmp(privname, "temporary") == 0)
2589 214 : return ACL_CREATE_TEMP;
2590 146 : if (strcmp(privname, "temp") == 0)
2591 2 : return ACL_CREATE_TEMP;
2592 144 : if (strcmp(privname, "connect") == 0)
2593 38 : return ACL_CONNECT;
2594 106 : if (strcmp(privname, "set") == 0)
2595 50 : return ACL_SET;
2596 56 : if (strcmp(privname, "alter system") == 0)
2597 24 : return ACL_ALTER_SYSTEM;
2598 32 : if (strcmp(privname, "maintain") == 0)
2599 32 : return ACL_MAINTAIN;
2600 0 : ereport(ERROR,
2601 : (errcode(ERRCODE_SYNTAX_ERROR),
2602 : errmsg("unrecognized privilege type \"%s\"", privname)));
2603 : return 0; /* appease compiler */
2604 : }
2605 :
2606 : static const char *
2607 24 : privilege_to_string(AclMode privilege)
2608 : {
2609 24 : switch (privilege)
2610 : {
2611 6 : case ACL_INSERT:
2612 6 : return "INSERT";
2613 0 : case ACL_SELECT:
2614 0 : return "SELECT";
2615 0 : case ACL_UPDATE:
2616 0 : return "UPDATE";
2617 0 : case ACL_DELETE:
2618 0 : return "DELETE";
2619 0 : case ACL_TRUNCATE:
2620 0 : return "TRUNCATE";
2621 0 : case ACL_REFERENCES:
2622 0 : return "REFERENCES";
2623 0 : case ACL_TRIGGER:
2624 0 : return "TRIGGER";
2625 0 : case ACL_EXECUTE:
2626 0 : return "EXECUTE";
2627 18 : case ACL_USAGE:
2628 18 : return "USAGE";
2629 0 : case ACL_CREATE:
2630 0 : return "CREATE";
2631 0 : case ACL_CREATE_TEMP:
2632 0 : return "TEMP";
2633 0 : case ACL_CONNECT:
2634 0 : return "CONNECT";
2635 0 : case ACL_SET:
2636 0 : return "SET";
2637 0 : case ACL_ALTER_SYSTEM:
2638 0 : return "ALTER SYSTEM";
2639 0 : case ACL_MAINTAIN:
2640 0 : return "MAINTAIN";
2641 0 : default:
2642 0 : elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2643 : }
2644 : return NULL; /* appease compiler */
2645 : }
2646 :
2647 : /*
2648 : * Standardized reporting of aclcheck permissions failures.
2649 : *
2650 : * Note: we do not double-quote the %s's below, because many callers
2651 : * supply strings that might be already quoted.
2652 : */
2653 : void
2654 2740 : aclcheck_error(AclResult aclerr, ObjectType objtype,
2655 : const char *objectname)
2656 : {
2657 2740 : switch (aclerr)
2658 : {
2659 0 : case ACLCHECK_OK:
2660 : /* no error, so return to caller */
2661 0 : break;
2662 2226 : case ACLCHECK_NO_PRIV:
2663 : {
2664 2226 : const char *msg = "???";
2665 :
2666 : switch (objtype)
2667 : {
2668 6 : case OBJECT_AGGREGATE:
2669 6 : msg = gettext_noop("permission denied for aggregate %s");
2670 6 : break;
2671 0 : case OBJECT_COLLATION:
2672 0 : msg = gettext_noop("permission denied for collation %s");
2673 0 : break;
2674 0 : case OBJECT_COLUMN:
2675 0 : msg = gettext_noop("permission denied for column %s");
2676 0 : break;
2677 0 : case OBJECT_CONVERSION:
2678 0 : msg = gettext_noop("permission denied for conversion %s");
2679 0 : break;
2680 18 : case OBJECT_DATABASE:
2681 18 : msg = gettext_noop("permission denied for database %s");
2682 18 : break;
2683 0 : case OBJECT_DOMAIN:
2684 0 : msg = gettext_noop("permission denied for domain %s");
2685 0 : break;
2686 0 : case OBJECT_EVENT_TRIGGER:
2687 0 : msg = gettext_noop("permission denied for event trigger %s");
2688 0 : break;
2689 0 : case OBJECT_EXTENSION:
2690 0 : msg = gettext_noop("permission denied for extension %s");
2691 0 : break;
2692 44 : case OBJECT_FDW:
2693 44 : msg = gettext_noop("permission denied for foreign-data wrapper %s");
2694 44 : break;
2695 20 : case OBJECT_FOREIGN_SERVER:
2696 20 : msg = gettext_noop("permission denied for foreign server %s");
2697 20 : break;
2698 2 : case OBJECT_FOREIGN_TABLE:
2699 2 : msg = gettext_noop("permission denied for foreign table %s");
2700 2 : break;
2701 102 : case OBJECT_FUNCTION:
2702 102 : msg = gettext_noop("permission denied for function %s");
2703 102 : break;
2704 14 : case OBJECT_INDEX:
2705 14 : msg = gettext_noop("permission denied for index %s");
2706 14 : break;
2707 8 : case OBJECT_LANGUAGE:
2708 8 : msg = gettext_noop("permission denied for language %s");
2709 8 : break;
2710 0 : case OBJECT_LARGEOBJECT:
2711 0 : msg = gettext_noop("permission denied for large object %s");
2712 0 : break;
2713 6 : case OBJECT_MATVIEW:
2714 6 : msg = gettext_noop("permission denied for materialized view %s");
2715 6 : break;
2716 0 : case OBJECT_OPCLASS:
2717 0 : msg = gettext_noop("permission denied for operator class %s");
2718 0 : break;
2719 0 : case OBJECT_OPERATOR:
2720 0 : msg = gettext_noop("permission denied for operator %s");
2721 0 : break;
2722 0 : case OBJECT_OPFAMILY:
2723 0 : msg = gettext_noop("permission denied for operator family %s");
2724 0 : break;
2725 0 : case OBJECT_PARAMETER_ACL:
2726 0 : msg = gettext_noop("permission denied for parameter %s");
2727 0 : break;
2728 0 : case OBJECT_POLICY:
2729 0 : msg = gettext_noop("permission denied for policy %s");
2730 0 : break;
2731 12 : case OBJECT_PROCEDURE:
2732 12 : msg = gettext_noop("permission denied for procedure %s");
2733 12 : break;
2734 0 : case OBJECT_PUBLICATION:
2735 0 : msg = gettext_noop("permission denied for publication %s");
2736 0 : break;
2737 0 : case OBJECT_ROUTINE:
2738 0 : msg = gettext_noop("permission denied for routine %s");
2739 0 : break;
2740 38 : case OBJECT_SCHEMA:
2741 38 : msg = gettext_noop("permission denied for schema %s");
2742 38 : break;
2743 0 : case OBJECT_SEQUENCE:
2744 0 : msg = gettext_noop("permission denied for sequence %s");
2745 0 : break;
2746 0 : case OBJECT_STATISTIC_EXT:
2747 0 : msg = gettext_noop("permission denied for statistics object %s");
2748 0 : break;
2749 0 : case OBJECT_SUBSCRIPTION:
2750 0 : msg = gettext_noop("permission denied for subscription %s");
2751 0 : break;
2752 1412 : case OBJECT_TABLE:
2753 1412 : msg = gettext_noop("permission denied for table %s");
2754 1412 : break;
2755 18 : case OBJECT_TABLESPACE:
2756 18 : msg = gettext_noop("permission denied for tablespace %s");
2757 18 : break;
2758 0 : case OBJECT_TSCONFIGURATION:
2759 0 : msg = gettext_noop("permission denied for text search configuration %s");
2760 0 : break;
2761 0 : case OBJECT_TSDICTIONARY:
2762 0 : msg = gettext_noop("permission denied for text search dictionary %s");
2763 0 : break;
2764 120 : case OBJECT_TYPE:
2765 120 : msg = gettext_noop("permission denied for type %s");
2766 120 : break;
2767 406 : case OBJECT_VIEW:
2768 406 : msg = gettext_noop("permission denied for view %s");
2769 406 : break;
2770 : /* these currently aren't used */
2771 0 : case OBJECT_ACCESS_METHOD:
2772 : case OBJECT_AMOP:
2773 : case OBJECT_AMPROC:
2774 : case OBJECT_ATTRIBUTE:
2775 : case OBJECT_CAST:
2776 : case OBJECT_DEFAULT:
2777 : case OBJECT_DEFACL:
2778 : case OBJECT_DOMCONSTRAINT:
2779 : case OBJECT_PUBLICATION_NAMESPACE:
2780 : case OBJECT_PUBLICATION_REL:
2781 : case OBJECT_ROLE:
2782 : case OBJECT_RULE:
2783 : case OBJECT_TABCONSTRAINT:
2784 : case OBJECT_TRANSFORM:
2785 : case OBJECT_TRIGGER:
2786 : case OBJECT_TSPARSER:
2787 : case OBJECT_TSTEMPLATE:
2788 : case OBJECT_USER_MAPPING:
2789 0 : elog(ERROR, "unsupported object type: %d", objtype);
2790 : }
2791 :
2792 2226 : ereport(ERROR,
2793 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2794 : errmsg(msg, objectname)));
2795 : break;
2796 : }
2797 514 : case ACLCHECK_NOT_OWNER:
2798 : {
2799 514 : const char *msg = "???";
2800 :
2801 : switch (objtype)
2802 : {
2803 6 : case OBJECT_AGGREGATE:
2804 6 : msg = gettext_noop("must be owner of aggregate %s");
2805 6 : break;
2806 0 : case OBJECT_COLLATION:
2807 0 : msg = gettext_noop("must be owner of collation %s");
2808 0 : break;
2809 18 : case OBJECT_CONVERSION:
2810 18 : msg = gettext_noop("must be owner of conversion %s");
2811 18 : break;
2812 0 : case OBJECT_DATABASE:
2813 0 : msg = gettext_noop("must be owner of database %s");
2814 0 : break;
2815 0 : case OBJECT_DOMAIN:
2816 0 : msg = gettext_noop("must be owner of domain %s");
2817 0 : break;
2818 0 : case OBJECT_EVENT_TRIGGER:
2819 0 : msg = gettext_noop("must be owner of event trigger %s");
2820 0 : break;
2821 0 : case OBJECT_EXTENSION:
2822 0 : msg = gettext_noop("must be owner of extension %s");
2823 0 : break;
2824 18 : case OBJECT_FDW:
2825 18 : msg = gettext_noop("must be owner of foreign-data wrapper %s");
2826 18 : break;
2827 114 : case OBJECT_FOREIGN_SERVER:
2828 114 : msg = gettext_noop("must be owner of foreign server %s");
2829 114 : break;
2830 0 : case OBJECT_FOREIGN_TABLE:
2831 0 : msg = gettext_noop("must be owner of foreign table %s");
2832 0 : break;
2833 42 : case OBJECT_FUNCTION:
2834 42 : msg = gettext_noop("must be owner of function %s");
2835 42 : break;
2836 24 : case OBJECT_INDEX:
2837 24 : msg = gettext_noop("must be owner of index %s");
2838 24 : break;
2839 12 : case OBJECT_LANGUAGE:
2840 12 : msg = gettext_noop("must be owner of language %s");
2841 12 : break;
2842 0 : case OBJECT_LARGEOBJECT:
2843 0 : msg = gettext_noop("must be owner of large object %s");
2844 0 : break;
2845 0 : case OBJECT_MATVIEW:
2846 0 : msg = gettext_noop("must be owner of materialized view %s");
2847 0 : break;
2848 18 : case OBJECT_OPCLASS:
2849 18 : msg = gettext_noop("must be owner of operator class %s");
2850 18 : break;
2851 18 : case OBJECT_OPERATOR:
2852 18 : msg = gettext_noop("must be owner of operator %s");
2853 18 : break;
2854 18 : case OBJECT_OPFAMILY:
2855 18 : msg = gettext_noop("must be owner of operator family %s");
2856 18 : break;
2857 6 : case OBJECT_PROCEDURE:
2858 6 : msg = gettext_noop("must be owner of procedure %s");
2859 6 : break;
2860 6 : case OBJECT_PUBLICATION:
2861 6 : msg = gettext_noop("must be owner of publication %s");
2862 6 : break;
2863 0 : case OBJECT_ROUTINE:
2864 0 : msg = gettext_noop("must be owner of routine %s");
2865 0 : break;
2866 6 : case OBJECT_SEQUENCE:
2867 6 : msg = gettext_noop("must be owner of sequence %s");
2868 6 : break;
2869 6 : case OBJECT_SUBSCRIPTION:
2870 6 : msg = gettext_noop("must be owner of subscription %s");
2871 6 : break;
2872 70 : case OBJECT_TABLE:
2873 70 : msg = gettext_noop("must be owner of table %s");
2874 70 : break;
2875 6 : case OBJECT_TYPE:
2876 6 : msg = gettext_noop("must be owner of type %s");
2877 6 : break;
2878 18 : case OBJECT_VIEW:
2879 18 : msg = gettext_noop("must be owner of view %s");
2880 18 : break;
2881 18 : case OBJECT_SCHEMA:
2882 18 : msg = gettext_noop("must be owner of schema %s");
2883 18 : break;
2884 36 : case OBJECT_STATISTIC_EXT:
2885 36 : msg = gettext_noop("must be owner of statistics object %s");
2886 36 : break;
2887 0 : case OBJECT_TABLESPACE:
2888 0 : msg = gettext_noop("must be owner of tablespace %s");
2889 0 : break;
2890 18 : case OBJECT_TSCONFIGURATION:
2891 18 : msg = gettext_noop("must be owner of text search configuration %s");
2892 18 : break;
2893 18 : case OBJECT_TSDICTIONARY:
2894 18 : msg = gettext_noop("must be owner of text search dictionary %s");
2895 18 : break;
2896 :
2897 : /*
2898 : * Special cases: For these, the error message talks
2899 : * about "relation", because that's where the
2900 : * ownership is attached. See also
2901 : * check_object_ownership().
2902 : */
2903 18 : case OBJECT_COLUMN:
2904 : case OBJECT_POLICY:
2905 : case OBJECT_RULE:
2906 : case OBJECT_TABCONSTRAINT:
2907 : case OBJECT_TRIGGER:
2908 18 : msg = gettext_noop("must be owner of relation %s");
2909 18 : break;
2910 : /* these currently aren't used */
2911 0 : case OBJECT_ACCESS_METHOD:
2912 : case OBJECT_AMOP:
2913 : case OBJECT_AMPROC:
2914 : case OBJECT_ATTRIBUTE:
2915 : case OBJECT_CAST:
2916 : case OBJECT_DEFAULT:
2917 : case OBJECT_DEFACL:
2918 : case OBJECT_DOMCONSTRAINT:
2919 : case OBJECT_PARAMETER_ACL:
2920 : case OBJECT_PUBLICATION_NAMESPACE:
2921 : case OBJECT_PUBLICATION_REL:
2922 : case OBJECT_ROLE:
2923 : case OBJECT_TRANSFORM:
2924 : case OBJECT_TSPARSER:
2925 : case OBJECT_TSTEMPLATE:
2926 : case OBJECT_USER_MAPPING:
2927 0 : elog(ERROR, "unsupported object type: %d", objtype);
2928 : }
2929 :
2930 514 : ereport(ERROR,
2931 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2932 : errmsg(msg, objectname)));
2933 : break;
2934 : }
2935 0 : default:
2936 0 : elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2937 : break;
2938 : }
2939 0 : }
2940 :
2941 :
2942 : void
2943 0 : aclcheck_error_col(AclResult aclerr, ObjectType objtype,
2944 : const char *objectname, const char *colname)
2945 : {
2946 0 : switch (aclerr)
2947 : {
2948 0 : case ACLCHECK_OK:
2949 : /* no error, so return to caller */
2950 0 : break;
2951 0 : case ACLCHECK_NO_PRIV:
2952 0 : ereport(ERROR,
2953 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2954 : errmsg("permission denied for column \"%s\" of relation \"%s\"",
2955 : colname, objectname)));
2956 : break;
2957 0 : case ACLCHECK_NOT_OWNER:
2958 : /* relation msg is OK since columns don't have separate owners */
2959 0 : aclcheck_error(aclerr, objtype, objectname);
2960 0 : break;
2961 0 : default:
2962 0 : elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2963 : break;
2964 : }
2965 0 : }
2966 :
2967 :
2968 : /*
2969 : * Special common handling for types: use element type instead of array type,
2970 : * and format nicely
2971 : */
2972 : void
2973 120 : aclcheck_error_type(AclResult aclerr, Oid typeOid)
2974 : {
2975 120 : Oid element_type = get_element_type(typeOid);
2976 :
2977 120 : aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
2978 0 : }
2979 :
2980 :
2981 : /*
2982 : * Relay for the various pg_*_mask routines depending on object kind
2983 : */
2984 : static AclMode
2985 72 : pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
2986 : AclMode mask, AclMaskHow how)
2987 : {
2988 72 : switch (objtype)
2989 : {
2990 0 : case OBJECT_COLUMN:
2991 : return
2992 0 : pg_class_aclmask(object_oid, roleid, mask, how) |
2993 0 : pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
2994 18 : case OBJECT_TABLE:
2995 : case OBJECT_SEQUENCE:
2996 18 : return pg_class_aclmask(object_oid, roleid, mask, how);
2997 0 : case OBJECT_DATABASE:
2998 0 : return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
2999 0 : case OBJECT_FUNCTION:
3000 0 : return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
3001 6 : case OBJECT_LANGUAGE:
3002 6 : return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
3003 0 : case OBJECT_LARGEOBJECT:
3004 0 : return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3005 : mask, how, NULL);
3006 0 : case OBJECT_PARAMETER_ACL:
3007 0 : return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
3008 0 : case OBJECT_SCHEMA:
3009 0 : return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
3010 0 : case OBJECT_STATISTIC_EXT:
3011 0 : elog(ERROR, "grantable rights not supported for statistics objects");
3012 : /* not reached, but keep compiler quiet */
3013 : return ACL_NO_RIGHTS;
3014 0 : case OBJECT_TABLESPACE:
3015 0 : return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3016 18 : case OBJECT_FDW:
3017 18 : return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3018 18 : case OBJECT_FOREIGN_SERVER:
3019 18 : return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3020 0 : case OBJECT_EVENT_TRIGGER:
3021 0 : elog(ERROR, "grantable rights not supported for event triggers");
3022 : /* not reached, but keep compiler quiet */
3023 : return ACL_NO_RIGHTS;
3024 12 : case OBJECT_TYPE:
3025 12 : return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3026 0 : default:
3027 0 : elog(ERROR, "unrecognized object type: %d",
3028 : (int) objtype);
3029 : /* not reached, but keep compiler quiet */
3030 : return ACL_NO_RIGHTS;
3031 : }
3032 : }
3033 :
3034 :
3035 : /* ****************************************************************
3036 : * Exported routines for examining a user's privileges for various objects
3037 : *
3038 : * See aclmask() for a description of the common API for these functions.
3039 : * ****************************************************************
3040 : */
3041 :
3042 : /*
3043 : * Generic routine for examining a user's privileges for an object
3044 : */
3045 : static AclMode
3046 54 : object_aclmask(Oid classid, Oid objectid, Oid roleid,
3047 : AclMode mask, AclMaskHow how)
3048 : {
3049 54 : return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3050 : }
3051 :
3052 : /*
3053 : * Generic routine for examining a user's privileges for an object,
3054 : * with is_missing
3055 : */
3056 : static AclMode
3057 3267224 : object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
3058 : AclMode mask, AclMaskHow how,
3059 : bool *is_missing)
3060 : {
3061 : int cacheid;
3062 : AclMode result;
3063 : HeapTuple tuple;
3064 : Datum aclDatum;
3065 : bool isNull;
3066 : Acl *acl;
3067 : Oid ownerId;
3068 :
3069 : /* Special cases */
3070 3267224 : switch (classid)
3071 : {
3072 974084 : case NamespaceRelationId:
3073 974084 : return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
3074 : is_missing);
3075 357940 : case TypeRelationId:
3076 357940 : return pg_type_aclmask_ext(objectid, roleid, mask, how,
3077 : is_missing);
3078 : }
3079 :
3080 : /* Even more special cases */
3081 : Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3082 : Assert(classid != LargeObjectMetadataRelationId); /* should use
3083 : * pg_largeobject_acl* */
3084 :
3085 : /* Superusers bypass all permission checking. */
3086 1935200 : if (superuser_arg(roleid))
3087 1892114 : return mask;
3088 :
3089 : /*
3090 : * Get the object's ACL from its catalog
3091 : */
3092 :
3093 43086 : cacheid = get_object_catcache_oid(classid);
3094 :
3095 43086 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3096 43086 : if (!HeapTupleIsValid(tuple))
3097 : {
3098 0 : if (is_missing != NULL)
3099 : {
3100 : /* return "no privileges" instead of throwing an error */
3101 0 : *is_missing = true;
3102 0 : return 0;
3103 : }
3104 : else
3105 0 : elog(ERROR, "cache lookup failed for %s %u",
3106 : get_object_class_descr(classid), objectid);
3107 : }
3108 :
3109 43086 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3110 : tuple,
3111 43086 : get_object_attnum_owner(classid)));
3112 :
3113 43086 : aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3114 : &isNull);
3115 43086 : if (isNull)
3116 : {
3117 : /* No ACL, so build default ACL */
3118 40444 : acl = acldefault(get_object_type(classid, objectid), ownerId);
3119 40444 : aclDatum = (Datum) 0;
3120 : }
3121 : else
3122 : {
3123 : /* detoast ACL if necessary */
3124 2642 : acl = DatumGetAclP(aclDatum);
3125 : }
3126 :
3127 43086 : result = aclmask(acl, roleid, ownerId, mask, how);
3128 :
3129 : /* if we have a detoasted copy, free it */
3130 43086 : if (acl && acl != DatumGetPointer(aclDatum))
3131 43086 : pfree(acl);
3132 :
3133 43086 : ReleaseSysCache(tuple);
3134 :
3135 43086 : return result;
3136 : }
3137 :
3138 : /*
3139 : * Routine for examining a user's privileges for a column
3140 : *
3141 : * Note: this considers only privileges granted specifically on the column.
3142 : * It is caller's responsibility to take relation-level privileges into account
3143 : * as appropriate. (For the same reason, we have no special case for
3144 : * superuser-ness here.)
3145 : */
3146 : static AclMode
3147 0 : pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
3148 : AclMode mask, AclMaskHow how)
3149 : {
3150 0 : return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3151 : mask, how, NULL);
3152 : }
3153 :
3154 : /*
3155 : * Routine for examining a user's privileges for a column, with is_missing
3156 : */
3157 : static AclMode
3158 7770 : pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid,
3159 : AclMode mask, AclMaskHow how, bool *is_missing)
3160 : {
3161 : AclMode result;
3162 : HeapTuple classTuple;
3163 : HeapTuple attTuple;
3164 : Form_pg_class classForm;
3165 : Form_pg_attribute attributeForm;
3166 : Datum aclDatum;
3167 : bool isNull;
3168 : Acl *acl;
3169 : Oid ownerId;
3170 :
3171 : /*
3172 : * First, get the column's ACL from its pg_attribute entry
3173 : */
3174 7770 : attTuple = SearchSysCache2(ATTNUM,
3175 : ObjectIdGetDatum(table_oid),
3176 : Int16GetDatum(attnum));
3177 7770 : if (!HeapTupleIsValid(attTuple))
3178 : {
3179 30 : if (is_missing != NULL)
3180 : {
3181 : /* return "no privileges" instead of throwing an error */
3182 30 : *is_missing = true;
3183 30 : return 0;
3184 : }
3185 : else
3186 0 : ereport(ERROR,
3187 : (errcode(ERRCODE_UNDEFINED_COLUMN),
3188 : errmsg("attribute %d of relation with OID %u does not exist",
3189 : attnum, table_oid)));
3190 : }
3191 :
3192 7740 : attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3193 :
3194 : /* Check dropped columns, too */
3195 7740 : if (attributeForm->attisdropped)
3196 : {
3197 12 : if (is_missing != NULL)
3198 : {
3199 : /* return "no privileges" instead of throwing an error */
3200 12 : *is_missing = true;
3201 12 : ReleaseSysCache(attTuple);
3202 12 : return 0;
3203 : }
3204 : else
3205 0 : ereport(ERROR,
3206 : (errcode(ERRCODE_UNDEFINED_COLUMN),
3207 : errmsg("attribute %d of relation with OID %u does not exist",
3208 : attnum, table_oid)));
3209 : }
3210 :
3211 7728 : aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3212 : &isNull);
3213 :
3214 : /*
3215 : * Here we hard-wire knowledge that the default ACL for a column grants no
3216 : * privileges, so that we can fall out quickly in the very common case
3217 : * where attacl is null.
3218 : */
3219 7728 : if (isNull)
3220 : {
3221 4898 : ReleaseSysCache(attTuple);
3222 4898 : return 0;
3223 : }
3224 :
3225 : /*
3226 : * Must get the relation's ownerId from pg_class. Since we already found
3227 : * a pg_attribute entry, the only likely reason for this to fail is that a
3228 : * concurrent DROP of the relation committed since then (which could only
3229 : * happen if we don't have lock on the relation). Treat that similarly to
3230 : * not finding the attribute entry.
3231 : */
3232 2830 : classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3233 2830 : if (!HeapTupleIsValid(classTuple))
3234 : {
3235 0 : ReleaseSysCache(attTuple);
3236 0 : if (is_missing != NULL)
3237 : {
3238 : /* return "no privileges" instead of throwing an error */
3239 0 : *is_missing = true;
3240 0 : return 0;
3241 : }
3242 : else
3243 0 : ereport(ERROR,
3244 : (errcode(ERRCODE_UNDEFINED_TABLE),
3245 : errmsg("relation with OID %u does not exist",
3246 : table_oid)));
3247 : }
3248 2830 : classForm = (Form_pg_class) GETSTRUCT(classTuple);
3249 :
3250 2830 : ownerId = classForm->relowner;
3251 :
3252 2830 : ReleaseSysCache(classTuple);
3253 :
3254 : /* detoast column's ACL if necessary */
3255 2830 : acl = DatumGetAclP(aclDatum);
3256 :
3257 2830 : result = aclmask(acl, roleid, ownerId, mask, how);
3258 :
3259 : /* if we have a detoasted copy, free it */
3260 2830 : if (acl && acl != DatumGetPointer(aclDatum))
3261 2830 : pfree(acl);
3262 :
3263 2830 : ReleaseSysCache(attTuple);
3264 :
3265 2830 : return result;
3266 : }
3267 :
3268 : /*
3269 : * Exported routine for examining a user's privileges for a table
3270 : */
3271 : AclMode
3272 599752 : pg_class_aclmask(Oid table_oid, Oid roleid,
3273 : AclMode mask, AclMaskHow how)
3274 : {
3275 599752 : return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3276 : }
3277 :
3278 : /*
3279 : * Routine for examining a user's privileges for a table, with is_missing
3280 : */
3281 : static AclMode
3282 3154544 : pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
3283 : AclMaskHow how, bool *is_missing)
3284 : {
3285 : AclMode result;
3286 : HeapTuple tuple;
3287 : Form_pg_class classForm;
3288 : Datum aclDatum;
3289 : bool isNull;
3290 : Acl *acl;
3291 : Oid ownerId;
3292 :
3293 : /*
3294 : * Must get the relation's tuple from pg_class
3295 : */
3296 3154544 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3297 3154544 : if (!HeapTupleIsValid(tuple))
3298 : {
3299 10 : if (is_missing != NULL)
3300 : {
3301 : /* return "no privileges" instead of throwing an error */
3302 10 : *is_missing = true;
3303 10 : return 0;
3304 : }
3305 : else
3306 0 : ereport(ERROR,
3307 : (errcode(ERRCODE_UNDEFINED_TABLE),
3308 : errmsg("relation with OID %u does not exist",
3309 : table_oid)));
3310 : }
3311 :
3312 3154534 : classForm = (Form_pg_class) GETSTRUCT(tuple);
3313 :
3314 : /*
3315 : * Deny anyone permission to update a system catalog unless
3316 : * pg_authid.rolsuper is set.
3317 : *
3318 : * As of 7.4 we have some updatable system views; those shouldn't be
3319 : * protected in this way. Assume the view rules can take care of
3320 : * themselves. ACL_USAGE is if we ever have system sequences.
3321 : */
3322 3991330 : if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3323 836796 : IsSystemClass(table_oid, classForm) &&
3324 5374 : classForm->relkind != RELKIND_VIEW &&
3325 5374 : !superuser_arg(roleid))
3326 70 : mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
3327 :
3328 : /*
3329 : * Otherwise, superusers bypass all permission-checking.
3330 : */
3331 3154534 : if (superuser_arg(roleid))
3332 : {
3333 3113558 : ReleaseSysCache(tuple);
3334 3113558 : return mask;
3335 : }
3336 :
3337 : /*
3338 : * Normal case: get the relation's ACL from pg_class
3339 : */
3340 40976 : ownerId = classForm->relowner;
3341 :
3342 40976 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3343 : &isNull);
3344 40976 : if (isNull)
3345 : {
3346 : /* No ACL, so build default ACL */
3347 9108 : switch (classForm->relkind)
3348 : {
3349 48 : case RELKIND_SEQUENCE:
3350 48 : acl = acldefault(OBJECT_SEQUENCE, ownerId);
3351 48 : break;
3352 9060 : default:
3353 9060 : acl = acldefault(OBJECT_TABLE, ownerId);
3354 9060 : break;
3355 : }
3356 9108 : aclDatum = (Datum) 0;
3357 : }
3358 : else
3359 : {
3360 : /* detoast rel's ACL if necessary */
3361 31868 : acl = DatumGetAclP(aclDatum);
3362 : }
3363 :
3364 40976 : result = aclmask(acl, roleid, ownerId, mask, how);
3365 :
3366 : /* if we have a detoasted copy, free it */
3367 40976 : if (acl && acl != DatumGetPointer(aclDatum))
3368 40976 : pfree(acl);
3369 :
3370 40976 : ReleaseSysCache(tuple);
3371 :
3372 : /*
3373 : * Check if ACL_SELECT is being checked and, if so, and not set already as
3374 : * part of the result, then check if the user is a member of the
3375 : * pg_read_all_data role, which allows read access to all relations.
3376 : */
3377 43224 : if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
3378 2248 : has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
3379 12 : result |= ACL_SELECT;
3380 :
3381 : /*
3382 : * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3383 : * so, and not set already as part of the result, then check if the user
3384 : * is a member of the pg_write_all_data role, which allows
3385 : * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3386 : * which requires superuser, see above).
3387 : */
3388 40976 : if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
3389 8720 : !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
3390 1926 : has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
3391 18 : result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
3392 :
3393 : /*
3394 : * Check if ACL_MAINTAIN is being checked and, if so, and not already set
3395 : * as part of the result, then check if the user is a member of the
3396 : * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
3397 : * MATERIALIZED VIEW, REINDEX, and LOCK TABLE on all relations.
3398 : */
3399 40976 : if (mask & ACL_MAINTAIN &&
3400 7464 : !(result & ACL_MAINTAIN) &&
3401 3440 : has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
3402 66 : result |= ACL_MAINTAIN;
3403 :
3404 40976 : return result;
3405 : }
3406 :
3407 : /*
3408 : * Routine for examining a user's privileges for a configuration
3409 : * parameter (GUC), identified by GUC name.
3410 : */
3411 : static AclMode
3412 160 : pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
3413 : {
3414 : AclMode result;
3415 : char *parname;
3416 : text *partext;
3417 : HeapTuple tuple;
3418 :
3419 : /* Superusers bypass all permission checking. */
3420 160 : if (superuser_arg(roleid))
3421 2 : return mask;
3422 :
3423 : /* Convert name to the form it should have in pg_parameter_acl... */
3424 158 : parname = convert_GUC_name_for_parameter_acl(name);
3425 158 : partext = cstring_to_text(parname);
3426 :
3427 : /* ... and look it up */
3428 158 : tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3429 :
3430 158 : if (!HeapTupleIsValid(tuple))
3431 : {
3432 : /* If no entry, GUC has no permissions for non-superusers */
3433 70 : result = ACL_NO_RIGHTS;
3434 : }
3435 : else
3436 : {
3437 : Datum aclDatum;
3438 : bool isNull;
3439 : Acl *acl;
3440 :
3441 88 : aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3442 : Anum_pg_parameter_acl_paracl,
3443 : &isNull);
3444 88 : if (isNull)
3445 : {
3446 : /* No ACL, so build default ACL */
3447 0 : acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3448 0 : aclDatum = (Datum) 0;
3449 : }
3450 : else
3451 : {
3452 : /* detoast ACL if necessary */
3453 88 : acl = DatumGetAclP(aclDatum);
3454 : }
3455 :
3456 88 : result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3457 :
3458 : /* if we have a detoasted copy, free it */
3459 88 : if (acl && acl != DatumGetPointer(aclDatum))
3460 88 : pfree(acl);
3461 :
3462 88 : ReleaseSysCache(tuple);
3463 : }
3464 :
3465 158 : pfree(parname);
3466 158 : pfree(partext);
3467 :
3468 158 : return result;
3469 : }
3470 :
3471 : /*
3472 : * Routine for examining a user's privileges for a configuration
3473 : * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
3474 : */
3475 : static AclMode
3476 0 : pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
3477 : {
3478 : AclMode result;
3479 : HeapTuple tuple;
3480 : Datum aclDatum;
3481 : bool isNull;
3482 : Acl *acl;
3483 :
3484 : /* Superusers bypass all permission checking. */
3485 0 : if (superuser_arg(roleid))
3486 0 : return mask;
3487 :
3488 : /* Get the ACL from pg_parameter_acl */
3489 0 : tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3490 0 : if (!HeapTupleIsValid(tuple))
3491 0 : ereport(ERROR,
3492 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3493 : errmsg("parameter ACL with OID %u does not exist",
3494 : acl_oid)));
3495 :
3496 0 : aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3497 : Anum_pg_parameter_acl_paracl,
3498 : &isNull);
3499 0 : if (isNull)
3500 : {
3501 : /* No ACL, so build default ACL */
3502 0 : acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3503 0 : aclDatum = (Datum) 0;
3504 : }
3505 : else
3506 : {
3507 : /* detoast ACL if necessary */
3508 0 : acl = DatumGetAclP(aclDatum);
3509 : }
3510 :
3511 0 : result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3512 :
3513 : /* if we have a detoasted copy, free it */
3514 0 : if (acl && acl != DatumGetPointer(aclDatum))
3515 0 : pfree(acl);
3516 :
3517 0 : ReleaseSysCache(tuple);
3518 :
3519 0 : return result;
3520 : }
3521 :
3522 : /*
3523 : * Routine for examining a user's privileges for a largeobject
3524 : *
3525 : * When a large object is opened for reading, it is opened relative to the
3526 : * caller's snapshot, but when it is opened for writing, a current
3527 : * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
3528 : * takes a snapshot argument so that the permissions check can be made
3529 : * relative to the same snapshot that will be used to read the underlying
3530 : * data. The caller will actually pass NULL for an instantaneous MVCC
3531 : * snapshot, since all we do with the snapshot argument is pass it through
3532 : * to systable_beginscan().
3533 : */
3534 : static AclMode
3535 864 : pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
3536 : AclMode mask, AclMaskHow how,
3537 : Snapshot snapshot)
3538 : {
3539 : AclMode result;
3540 : Relation pg_lo_meta;
3541 : ScanKeyData entry[1];
3542 : SysScanDesc scan;
3543 : HeapTuple tuple;
3544 : Datum aclDatum;
3545 : bool isNull;
3546 : Acl *acl;
3547 : Oid ownerId;
3548 :
3549 : /* Superusers bypass all permission checking. */
3550 864 : if (superuser_arg(roleid))
3551 570 : return mask;
3552 :
3553 : /*
3554 : * Get the largeobject's ACL from pg_largeobject_metadata
3555 : */
3556 294 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
3557 : AccessShareLock);
3558 :
3559 294 : ScanKeyInit(&entry[0],
3560 : Anum_pg_largeobject_metadata_oid,
3561 : BTEqualStrategyNumber, F_OIDEQ,
3562 : ObjectIdGetDatum(lobj_oid));
3563 :
3564 294 : scan = systable_beginscan(pg_lo_meta,
3565 : LargeObjectMetadataOidIndexId, true,
3566 : snapshot, 1, entry);
3567 :
3568 294 : tuple = systable_getnext(scan);
3569 294 : if (!HeapTupleIsValid(tuple))
3570 0 : ereport(ERROR,
3571 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3572 : errmsg("large object %u does not exist", lobj_oid)));
3573 :
3574 294 : ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
3575 :
3576 294 : aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
3577 : RelationGetDescr(pg_lo_meta), &isNull);
3578 :
3579 294 : if (isNull)
3580 : {
3581 : /* No ACL, so build default ACL */
3582 72 : acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
3583 72 : aclDatum = (Datum) 0;
3584 : }
3585 : else
3586 : {
3587 : /* detoast ACL if necessary */
3588 222 : acl = DatumGetAclP(aclDatum);
3589 : }
3590 :
3591 294 : result = aclmask(acl, roleid, ownerId, mask, how);
3592 :
3593 : /* if we have a detoasted copy, free it */
3594 294 : if (acl && acl != DatumGetPointer(aclDatum))
3595 294 : pfree(acl);
3596 :
3597 294 : systable_endscan(scan);
3598 :
3599 294 : table_close(pg_lo_meta, AccessShareLock);
3600 :
3601 294 : return result;
3602 : }
3603 :
3604 : /*
3605 : * Routine for examining a user's privileges for a namespace, with is_missing
3606 : */
3607 : static AclMode
3608 974086 : pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
3609 : AclMode mask, AclMaskHow how,
3610 : bool *is_missing)
3611 : {
3612 : AclMode result;
3613 : HeapTuple tuple;
3614 : Datum aclDatum;
3615 : bool isNull;
3616 : Acl *acl;
3617 : Oid ownerId;
3618 :
3619 : /* Superusers bypass all permission checking. */
3620 974086 : if (superuser_arg(roleid))
3621 956556 : return mask;
3622 :
3623 : /*
3624 : * If we have been assigned this namespace as a temp namespace, check to
3625 : * make sure we have CREATE TEMP permission on the database, and if so act
3626 : * as though we have all standard (but not GRANT OPTION) permissions on
3627 : * the namespace. If we don't have CREATE TEMP, act as though we have
3628 : * only USAGE (and not CREATE) rights.
3629 : *
3630 : * This may seem redundant given the check in InitTempTableNamespace, but
3631 : * it really isn't since current user ID may have changed since then. The
3632 : * upshot of this behavior is that a SECURITY DEFINER function can create
3633 : * temp tables that can then be accessed (if permission is granted) by
3634 : * code in the same session that doesn't have permissions to create temp
3635 : * tables.
3636 : *
3637 : * XXX Would it be safe to ereport a special error message as
3638 : * InitTempTableNamespace does? Returning zero here means we'll get a
3639 : * generic "permission denied for schema pg_temp_N" message, which is not
3640 : * remarkably user-friendly.
3641 : */
3642 17530 : if (isTempNamespace(nsp_oid))
3643 : {
3644 314 : if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
3645 : ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
3646 314 : return mask & ACL_ALL_RIGHTS_SCHEMA;
3647 : else
3648 0 : return mask & ACL_USAGE;
3649 : }
3650 :
3651 : /*
3652 : * Get the schema's ACL from pg_namespace
3653 : */
3654 17216 : tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
3655 17216 : if (!HeapTupleIsValid(tuple))
3656 : {
3657 0 : if (is_missing != NULL)
3658 : {
3659 : /* return "no privileges" instead of throwing an error */
3660 0 : *is_missing = true;
3661 0 : return 0;
3662 : }
3663 : else
3664 0 : ereport(ERROR,
3665 : (errcode(ERRCODE_UNDEFINED_SCHEMA),
3666 : errmsg("schema with OID %u does not exist", nsp_oid)));
3667 : }
3668 :
3669 17216 : ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3670 :
3671 17216 : aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
3672 : &isNull);
3673 17216 : if (isNull)
3674 : {
3675 : /* No ACL, so build default ACL */
3676 304 : acl = acldefault(OBJECT_SCHEMA, ownerId);
3677 304 : aclDatum = (Datum) 0;
3678 : }
3679 : else
3680 : {
3681 : /* detoast ACL if necessary */
3682 16912 : acl = DatumGetAclP(aclDatum);
3683 : }
3684 :
3685 17216 : result = aclmask(acl, roleid, ownerId, mask, how);
3686 :
3687 : /* if we have a detoasted copy, free it */
3688 17216 : if (acl && acl != DatumGetPointer(aclDatum))
3689 17216 : pfree(acl);
3690 :
3691 17216 : ReleaseSysCache(tuple);
3692 :
3693 : /*
3694 : * Check if ACL_USAGE is being checked and, if so, and not set already as
3695 : * part of the result, then check if the user is a member of the
3696 : * pg_read_all_data or pg_write_all_data roles, which allow usage access
3697 : * to all schemas.
3698 : */
3699 17278 : if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
3700 118 : (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
3701 56 : has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
3702 12 : result |= ACL_USAGE;
3703 17216 : return result;
3704 : }
3705 :
3706 : /*
3707 : * Routine for examining a user's privileges for a type, with is_missing
3708 : */
3709 : static AclMode
3710 357940 : pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
3711 : bool *is_missing)
3712 : {
3713 : AclMode result;
3714 : HeapTuple tuple;
3715 : Form_pg_type typeForm;
3716 : Datum aclDatum;
3717 : bool isNull;
3718 : Acl *acl;
3719 : Oid ownerId;
3720 :
3721 : /* Bypass permission checks for superusers */
3722 357940 : if (superuser_arg(roleid))
3723 353486 : return mask;
3724 :
3725 : /*
3726 : * Must get the type's tuple from pg_type
3727 : */
3728 4454 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3729 4454 : if (!HeapTupleIsValid(tuple))
3730 : {
3731 0 : if (is_missing != NULL)
3732 : {
3733 : /* return "no privileges" instead of throwing an error */
3734 0 : *is_missing = true;
3735 0 : return 0;
3736 : }
3737 : else
3738 0 : ereport(ERROR,
3739 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3740 : errmsg("type with OID %u does not exist",
3741 : type_oid)));
3742 : }
3743 4454 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
3744 :
3745 : /*
3746 : * "True" array types don't manage permissions of their own; consult the
3747 : * element type instead.
3748 : */
3749 4454 : if (IsTrueArrayType(typeForm))
3750 : {
3751 48 : Oid elttype_oid = typeForm->typelem;
3752 :
3753 48 : ReleaseSysCache(tuple);
3754 :
3755 48 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3756 48 : if (!HeapTupleIsValid(tuple))
3757 : {
3758 0 : if (is_missing != NULL)
3759 : {
3760 : /* return "no privileges" instead of throwing an error */
3761 0 : *is_missing = true;
3762 0 : return 0;
3763 : }
3764 : else
3765 0 : ereport(ERROR,
3766 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3767 : errmsg("type with OID %u does not exist",
3768 : elttype_oid)));
3769 : }
3770 48 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
3771 : }
3772 :
3773 : /*
3774 : * Likewise, multirange types don't manage their own permissions; consult
3775 : * the associated range type. (Note we must do this after the array step
3776 : * to get the right answer for arrays of multiranges.)
3777 : */
3778 4454 : if (typeForm->typtype == TYPTYPE_MULTIRANGE)
3779 : {
3780 12 : Oid rangetype = get_multirange_range(typeForm->oid);
3781 :
3782 12 : ReleaseSysCache(tuple);
3783 :
3784 12 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
3785 12 : if (!HeapTupleIsValid(tuple))
3786 : {
3787 0 : if (is_missing != NULL)
3788 : {
3789 : /* return "no privileges" instead of throwing an error */
3790 0 : *is_missing = true;
3791 0 : return 0;
3792 : }
3793 : else
3794 0 : ereport(ERROR,
3795 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3796 : errmsg("type with OID %u does not exist",
3797 : rangetype)));
3798 : }
3799 12 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
3800 : }
3801 :
3802 : /*
3803 : * Now get the type's owner and ACL from the tuple
3804 : */
3805 4454 : ownerId = typeForm->typowner;
3806 :
3807 4454 : aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3808 : Anum_pg_type_typacl, &isNull);
3809 4454 : if (isNull)
3810 : {
3811 : /* No ACL, so build default ACL */
3812 4220 : acl = acldefault(OBJECT_TYPE, ownerId);
3813 4220 : aclDatum = (Datum) 0;
3814 : }
3815 : else
3816 : {
3817 : /* detoast rel's ACL if necessary */
3818 234 : acl = DatumGetAclP(aclDatum);
3819 : }
3820 :
3821 4454 : result = aclmask(acl, roleid, ownerId, mask, how);
3822 :
3823 : /* if we have a detoasted copy, free it */
3824 4454 : if (acl && acl != DatumGetPointer(aclDatum))
3825 4454 : pfree(acl);
3826 :
3827 4454 : ReleaseSysCache(tuple);
3828 :
3829 4454 : return result;
3830 : }
3831 :
3832 : /*
3833 : * Exported generic routine for checking a user's access privileges to an object
3834 : */
3835 : AclResult
3836 3266752 : object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
3837 : {
3838 3266752 : return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3839 : }
3840 :
3841 : /*
3842 : * Exported generic routine for checking a user's access privileges to an
3843 : * object, with is_missing
3844 : */
3845 : AclResult
3846 3267174 : object_aclcheck_ext(Oid classid, Oid objectid,
3847 : Oid roleid, AclMode mode,
3848 : bool *is_missing)
3849 : {
3850 3267174 : if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
3851 : is_missing) != 0)
3852 3266556 : return ACLCHECK_OK;
3853 : else
3854 618 : return ACLCHECK_NO_PRIV;
3855 : }
3856 :
3857 : /*
3858 : * Exported routine for checking a user's access privileges to a column
3859 : *
3860 : * Returns ACLCHECK_OK if the user has any of the privileges identified by
3861 : * 'mode'; otherwise returns a suitable error code (in practice, always
3862 : * ACLCHECK_NO_PRIV).
3863 : *
3864 : * As with pg_attribute_aclmask, only privileges granted directly on the
3865 : * column are considered here.
3866 : */
3867 : AclResult
3868 4092 : pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
3869 : Oid roleid, AclMode mode)
3870 : {
3871 4092 : return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3872 : }
3873 :
3874 :
3875 : /*
3876 : * Exported routine for checking a user's access privileges to a column,
3877 : * with is_missing
3878 : */
3879 : AclResult
3880 7770 : pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
3881 : Oid roleid, AclMode mode, bool *is_missing)
3882 : {
3883 7770 : if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3884 : ACLMASK_ANY, is_missing) != 0)
3885 2296 : return ACLCHECK_OK;
3886 : else
3887 5474 : return ACLCHECK_NO_PRIV;
3888 : }
3889 :
3890 : /*
3891 : * Exported routine for checking a user's access privileges to any/all columns
3892 : *
3893 : * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
3894 : * privileges identified by 'mode' on any non-dropped column in the relation;
3895 : * otherwise returns a suitable error code (in practice, always
3896 : * ACLCHECK_NO_PRIV).
3897 : *
3898 : * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
3899 : * privileges identified by 'mode' on each non-dropped column in the relation
3900 : * (and there must be at least one such column); otherwise returns a suitable
3901 : * error code (in practice, always ACLCHECK_NO_PRIV).
3902 : *
3903 : * As with pg_attribute_aclmask, only privileges granted directly on the
3904 : * column(s) are considered here.
3905 : *
3906 : * Note: system columns are not considered here; there are cases where that
3907 : * might be appropriate but there are also cases where it wouldn't.
3908 : */
3909 : AclResult
3910 174 : pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
3911 : AclMaskHow how)
3912 : {
3913 174 : return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3914 : }
3915 :
3916 : /*
3917 : * Exported routine for checking a user's access privileges to any/all columns,
3918 : * with is_missing
3919 : */
3920 : AclResult
3921 174 : pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid,
3922 : AclMode mode, AclMaskHow how,
3923 : bool *is_missing)
3924 : {
3925 : AclResult result;
3926 : HeapTuple classTuple;
3927 : Form_pg_class classForm;
3928 : Oid ownerId;
3929 : AttrNumber nattrs;
3930 : AttrNumber curr_att;
3931 :
3932 : /*
3933 : * Must fetch pg_class row to get owner ID and number of attributes.
3934 : */
3935 174 : classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3936 174 : if (!HeapTupleIsValid(classTuple))
3937 : {
3938 0 : if (is_missing != NULL)
3939 : {
3940 : /* return "no privileges" instead of throwing an error */
3941 0 : *is_missing = true;
3942 0 : return ACLCHECK_NO_PRIV;
3943 : }
3944 : else
3945 0 : ereport(ERROR,
3946 : (errcode(ERRCODE_UNDEFINED_TABLE),
3947 : errmsg("relation with OID %u does not exist",
3948 : table_oid)));
3949 : }
3950 174 : classForm = (Form_pg_class) GETSTRUCT(classTuple);
3951 :
3952 174 : ownerId = classForm->relowner;
3953 174 : nattrs = classForm->relnatts;
3954 :
3955 174 : ReleaseSysCache(classTuple);
3956 :
3957 : /*
3958 : * Initialize result in case there are no non-dropped columns. We want to
3959 : * report failure in such cases for either value of 'how'.
3960 : */
3961 174 : result = ACLCHECK_NO_PRIV;
3962 :
3963 426 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
3964 : {
3965 : HeapTuple attTuple;
3966 : Datum aclDatum;
3967 : bool isNull;
3968 : Acl *acl;
3969 : AclMode attmask;
3970 :
3971 342 : attTuple = SearchSysCache2(ATTNUM,
3972 : ObjectIdGetDatum(table_oid),
3973 : Int16GetDatum(curr_att));
3974 :
3975 : /*
3976 : * Lookup failure probably indicates that the table was just dropped,
3977 : * but we'll treat it the same as a dropped column rather than
3978 : * throwing error.
3979 : */
3980 342 : if (!HeapTupleIsValid(attTuple))
3981 18 : continue;
3982 :
3983 : /* ignore dropped columns */
3984 342 : if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
3985 : {
3986 18 : ReleaseSysCache(attTuple);
3987 18 : continue;
3988 : }
3989 :
3990 324 : aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3991 : &isNull);
3992 :
3993 : /*
3994 : * Here we hard-wire knowledge that the default ACL for a column
3995 : * grants no privileges, so that we can fall out quickly in the very
3996 : * common case where attacl is null.
3997 : */
3998 324 : if (isNull)
3999 168 : attmask = 0;
4000 : else
4001 : {
4002 : /* detoast column's ACL if necessary */
4003 156 : acl = DatumGetAclP(aclDatum);
4004 :
4005 156 : attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
4006 :
4007 : /* if we have a detoasted copy, free it */
4008 156 : if (acl != DatumGetPointer(aclDatum))
4009 156 : pfree(acl);
4010 : }
4011 :
4012 324 : ReleaseSysCache(attTuple);
4013 :
4014 324 : if (attmask != 0)
4015 : {
4016 138 : result = ACLCHECK_OK;
4017 138 : if (how == ACLMASK_ANY)
4018 90 : break; /* succeed on any success */
4019 : }
4020 : else
4021 : {
4022 186 : result = ACLCHECK_NO_PRIV;
4023 186 : if (how == ACLMASK_ALL)
4024 48 : break; /* fail on any failure */
4025 : }
4026 : }
4027 :
4028 174 : return result;
4029 : }
4030 :
4031 : /*
4032 : * Exported routine for checking a user's access privileges to a table
4033 : *
4034 : * Returns ACLCHECK_OK if the user has any of the privileges identified by
4035 : * 'mode'; otherwise returns a suitable error code (in practice, always
4036 : * ACLCHECK_NO_PRIV).
4037 : */
4038 : AclResult
4039 2534616 : pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
4040 : {
4041 2534616 : return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
4042 : }
4043 :
4044 : /*
4045 : * Exported routine for checking a user's access privileges to a table,
4046 : * with is_missing
4047 : */
4048 : AclResult
4049 2554792 : pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
4050 : AclMode mode, bool *is_missing)
4051 : {
4052 2554792 : if (pg_class_aclmask_ext(table_oid, roleid, mode,
4053 : ACLMASK_ANY, is_missing) != 0)
4054 2550712 : return ACLCHECK_OK;
4055 : else
4056 4080 : return ACLCHECK_NO_PRIV;
4057 : }
4058 :
4059 : /*
4060 : * Exported routine for checking a user's access privileges to a configuration
4061 : * parameter (GUC), identified by GUC name.
4062 : */
4063 : AclResult
4064 160 : pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
4065 : {
4066 160 : if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4067 68 : return ACLCHECK_OK;
4068 : else
4069 92 : return ACLCHECK_NO_PRIV;
4070 : }
4071 :
4072 : /*
4073 : * Exported routine for checking a user's access privileges to a largeobject
4074 : */
4075 : AclResult
4076 864 : pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
4077 : Snapshot snapshot)
4078 : {
4079 864 : if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4080 : ACLMASK_ANY, snapshot) != 0)
4081 738 : return ACLCHECK_OK;
4082 : else
4083 126 : return ACLCHECK_NO_PRIV;
4084 : }
4085 :
4086 : /*
4087 : * Generic ownership check for an object
4088 : */
4089 : bool
4090 486420 : object_ownercheck(Oid classid, Oid objectid, Oid roleid)
4091 : {
4092 : int cacheid;
4093 : Oid ownerId;
4094 :
4095 : /* Superusers bypass all permission checking. */
4096 486420 : if (superuser_arg(roleid))
4097 474968 : return true;
4098 :
4099 : /* For large objects, the catalog to consult is pg_largeobject_metadata */
4100 11452 : if (classid == LargeObjectRelationId)
4101 24 : classid = LargeObjectMetadataRelationId;
4102 :
4103 11452 : cacheid = get_object_catcache_oid(classid);
4104 11452 : if (cacheid != -1)
4105 : {
4106 : /* we can get the object's tuple from the syscache */
4107 : HeapTuple tuple;
4108 :
4109 11424 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4110 11424 : if (!HeapTupleIsValid(tuple))
4111 0 : elog(ERROR, "cache lookup failed for %s %u",
4112 : get_object_class_descr(classid), objectid);
4113 :
4114 11424 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4115 : tuple,
4116 11424 : get_object_attnum_owner(classid)));
4117 11424 : ReleaseSysCache(tuple);
4118 : }
4119 : else
4120 : {
4121 : /* for catalogs without an appropriate syscache */
4122 : Relation rel;
4123 : ScanKeyData entry[1];
4124 : SysScanDesc scan;
4125 : HeapTuple tuple;
4126 : bool isnull;
4127 :
4128 28 : rel = table_open(classid, AccessShareLock);
4129 :
4130 56 : ScanKeyInit(&entry[0],
4131 28 : get_object_attnum_oid(classid),
4132 : BTEqualStrategyNumber, F_OIDEQ,
4133 : ObjectIdGetDatum(objectid));
4134 :
4135 28 : scan = systable_beginscan(rel,
4136 : get_object_oid_index(classid), true,
4137 : NULL, 1, entry);
4138 :
4139 28 : tuple = systable_getnext(scan);
4140 28 : if (!HeapTupleIsValid(tuple))
4141 0 : elog(ERROR, "could not find tuple for %s %u",
4142 : get_object_class_descr(classid), objectid);
4143 :
4144 28 : ownerId = DatumGetObjectId(heap_getattr(tuple,
4145 28 : get_object_attnum_owner(classid),
4146 : RelationGetDescr(rel),
4147 : &isnull));
4148 : Assert(!isnull);
4149 :
4150 28 : systable_endscan(scan);
4151 28 : table_close(rel, AccessShareLock);
4152 : }
4153 :
4154 11452 : return has_privs_of_role(roleid, ownerId);
4155 : }
4156 :
4157 : /*
4158 : * Check whether specified role has CREATEROLE privilege (or is a superuser)
4159 : *
4160 : * Note: roles do not have owners per se; instead we use this test in
4161 : * places where an ownership-like permissions test is needed for a role.
4162 : * Be sure to apply it to the role trying to do the operation, not the
4163 : * role being operated on! Also note that this generally should not be
4164 : * considered enough privilege if the target role is a superuser.
4165 : * (We don't handle that consideration here because we want to give a
4166 : * separate error message for such cases, so the caller has to deal with it.)
4167 : */
4168 : bool
4169 2486 : has_createrole_privilege(Oid roleid)
4170 : {
4171 2486 : bool result = false;
4172 : HeapTuple utup;
4173 :
4174 : /* Superusers bypass all permission checking. */
4175 2486 : if (superuser_arg(roleid))
4176 1956 : return true;
4177 :
4178 530 : utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4179 530 : if (HeapTupleIsValid(utup))
4180 : {
4181 530 : result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4182 530 : ReleaseSysCache(utup);
4183 : }
4184 530 : return result;
4185 : }
4186 :
4187 : bool
4188 5266 : has_bypassrls_privilege(Oid roleid)
4189 : {
4190 5266 : bool result = false;
4191 : HeapTuple utup;
4192 :
4193 : /* Superusers bypass all permission checking. */
4194 5266 : if (superuser_arg(roleid))
4195 1640 : return true;
4196 :
4197 3626 : utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4198 3626 : if (HeapTupleIsValid(utup))
4199 : {
4200 3626 : result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4201 3626 : ReleaseSysCache(utup);
4202 : }
4203 3626 : return result;
4204 : }
4205 :
4206 : /*
4207 : * Fetch pg_default_acl entry for given role, namespace and object type
4208 : * (object type must be given in pg_default_acl's encoding).
4209 : * Returns NULL if no such entry.
4210 : */
4211 : static Acl *
4212 169548 : get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
4213 : {
4214 169548 : Acl *result = NULL;
4215 : HeapTuple tuple;
4216 :
4217 169548 : tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4218 : ObjectIdGetDatum(roleId),
4219 : ObjectIdGetDatum(nsp_oid),
4220 : CharGetDatum(objtype));
4221 :
4222 169548 : if (HeapTupleIsValid(tuple))
4223 : {
4224 : Datum aclDatum;
4225 : bool isNull;
4226 :
4227 264 : aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4228 : Anum_pg_default_acl_defaclacl,
4229 : &isNull);
4230 264 : if (!isNull)
4231 264 : result = DatumGetAclPCopy(aclDatum);
4232 264 : ReleaseSysCache(tuple);
4233 : }
4234 :
4235 169548 : return result;
4236 : }
4237 :
4238 : /*
4239 : * Get default permissions for newly created object within given schema
4240 : *
4241 : * Returns NULL if built-in system defaults should be used.
4242 : *
4243 : * If the result is not NULL, caller must call recordDependencyOnNewAcl
4244 : * once the OID of the new object is known.
4245 : */
4246 : Acl *
4247 84774 : get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
4248 : {
4249 : Acl *result;
4250 : Acl *glob_acl;
4251 : Acl *schema_acl;
4252 : Acl *def_acl;
4253 : char defaclobjtype;
4254 :
4255 : /*
4256 : * Use NULL during bootstrap, since pg_default_acl probably isn't there
4257 : * yet.
4258 : */
4259 84774 : if (IsBootstrapProcessingMode())
4260 0 : return NULL;
4261 :
4262 : /* Check if object type is supported in pg_default_acl */
4263 84774 : switch (objtype)
4264 : {
4265 56950 : case OBJECT_TABLE:
4266 56950 : defaclobjtype = DEFACLOBJ_RELATION;
4267 56950 : break;
4268 :
4269 1892 : case OBJECT_SEQUENCE:
4270 1892 : defaclobjtype = DEFACLOBJ_SEQUENCE;
4271 1892 : break;
4272 :
4273 18006 : case OBJECT_FUNCTION:
4274 18006 : defaclobjtype = DEFACLOBJ_FUNCTION;
4275 18006 : break;
4276 :
4277 6688 : case OBJECT_TYPE:
4278 6688 : defaclobjtype = DEFACLOBJ_TYPE;
4279 6688 : break;
4280 :
4281 1070 : case OBJECT_SCHEMA:
4282 1070 : defaclobjtype = DEFACLOBJ_NAMESPACE;
4283 1070 : break;
4284 :
4285 168 : case OBJECT_LARGEOBJECT:
4286 168 : defaclobjtype = DEFACLOBJ_LARGEOBJECT;
4287 168 : break;
4288 :
4289 0 : default:
4290 0 : return NULL;
4291 : }
4292 :
4293 : /* Look up the relevant pg_default_acl entries */
4294 84774 : glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4295 84774 : schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4296 :
4297 : /* Quick out if neither entry exists */
4298 84774 : if (glob_acl == NULL && schema_acl == NULL)
4299 84564 : return NULL;
4300 :
4301 : /* We need to know the hard-wired default value, too */
4302 210 : def_acl = acldefault(objtype, ownerId);
4303 :
4304 : /* If there's no global entry, substitute the hard-wired default */
4305 210 : if (glob_acl == NULL)
4306 18 : glob_acl = def_acl;
4307 :
4308 : /* Merge in any per-schema privileges */
4309 210 : result = aclmerge(glob_acl, schema_acl, ownerId);
4310 :
4311 : /*
4312 : * For efficiency, we want to return NULL if the result equals default.
4313 : * This requires sorting both arrays to get an accurate comparison.
4314 : */
4315 210 : aclitemsort(result);
4316 210 : aclitemsort(def_acl);
4317 210 : if (aclequal(result, def_acl))
4318 24 : result = NULL;
4319 :
4320 210 : return result;
4321 : }
4322 :
4323 : /*
4324 : * Record dependencies on roles mentioned in a new object's ACL.
4325 : */
4326 : void
4327 88218 : recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
4328 : Oid ownerId, Acl *acl)
4329 : {
4330 : int nmembers;
4331 : Oid *members;
4332 :
4333 : /* Nothing to do if ACL is defaulted */
4334 88218 : if (acl == NULL)
4335 88032 : return;
4336 :
4337 : /* Extract roles mentioned in ACL */
4338 186 : nmembers = aclmembers(acl, &members);
4339 :
4340 : /* Update the shared dependency ACL info */
4341 186 : updateAclDependencies(classId, objectId, objsubId,
4342 : ownerId,
4343 : 0, NULL,
4344 : nmembers, members);
4345 : }
4346 :
4347 : /*
4348 : * Record initial privileges for the top-level object passed in.
4349 : *
4350 : * For the object passed in, this will record its ACL (if any) and the ACLs of
4351 : * any sub-objects (eg: columns) into pg_init_privs.
4352 : */
4353 : void
4354 104 : recordExtObjInitPriv(Oid objoid, Oid classoid)
4355 : {
4356 : /*
4357 : * pg_class / pg_attribute
4358 : *
4359 : * If this is a relation then we need to see if there are any sub-objects
4360 : * (eg: columns) for it and, if so, be sure to call
4361 : * recordExtensionInitPrivWorker() for each one.
4362 : */
4363 104 : if (classoid == RelationRelationId)
4364 : {
4365 : Form_pg_class pg_class_tuple;
4366 : Datum aclDatum;
4367 : bool isNull;
4368 : HeapTuple tuple;
4369 :
4370 16 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4371 16 : if (!HeapTupleIsValid(tuple))
4372 0 : elog(ERROR, "cache lookup failed for relation %u", objoid);
4373 16 : pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4374 :
4375 : /*
4376 : * Indexes don't have permissions, neither do the pg_class rows for
4377 : * composite types. (These cases are unreachable given the
4378 : * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4379 : */
4380 16 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
4381 16 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4382 16 : pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4383 : {
4384 0 : ReleaseSysCache(tuple);
4385 0 : return;
4386 : }
4387 :
4388 : /*
4389 : * If this isn't a sequence then it's possibly going to have
4390 : * column-level ACLs associated with it.
4391 : */
4392 16 : if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4393 : {
4394 : AttrNumber curr_att;
4395 14 : AttrNumber nattrs = pg_class_tuple->relnatts;
4396 :
4397 38 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
4398 : {
4399 : HeapTuple attTuple;
4400 : Datum attaclDatum;
4401 :
4402 24 : attTuple = SearchSysCache2(ATTNUM,
4403 : ObjectIdGetDatum(objoid),
4404 : Int16GetDatum(curr_att));
4405 :
4406 24 : if (!HeapTupleIsValid(attTuple))
4407 0 : continue;
4408 :
4409 : /* ignore dropped columns */
4410 24 : if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4411 : {
4412 2 : ReleaseSysCache(attTuple);
4413 2 : continue;
4414 : }
4415 :
4416 22 : attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4417 : Anum_pg_attribute_attacl,
4418 : &isNull);
4419 :
4420 : /* no need to do anything for a NULL ACL */
4421 22 : if (isNull)
4422 : {
4423 18 : ReleaseSysCache(attTuple);
4424 18 : continue;
4425 : }
4426 :
4427 4 : recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4428 4 : DatumGetAclP(attaclDatum));
4429 :
4430 4 : ReleaseSysCache(attTuple);
4431 : }
4432 : }
4433 :
4434 16 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4435 : &isNull);
4436 :
4437 : /* Add the record, if any, for the top-level object */
4438 16 : if (!isNull)
4439 8 : recordExtensionInitPrivWorker(objoid, classoid, 0,
4440 8 : DatumGetAclP(aclDatum));
4441 :
4442 16 : ReleaseSysCache(tuple);
4443 : }
4444 88 : else if (classoid == LargeObjectRelationId)
4445 : {
4446 : /* For large objects, we must consult pg_largeobject_metadata */
4447 : Datum aclDatum;
4448 : bool isNull;
4449 : HeapTuple tuple;
4450 : ScanKeyData entry[1];
4451 : SysScanDesc scan;
4452 : Relation relation;
4453 :
4454 : /*
4455 : * Note: this is dead code, given that we don't allow large objects to
4456 : * be made extension members. But it seems worth carrying in case
4457 : * some future caller of this function has need for it.
4458 : */
4459 0 : relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4460 :
4461 : /* There's no syscache for pg_largeobject_metadata */
4462 0 : ScanKeyInit(&entry[0],
4463 : Anum_pg_largeobject_metadata_oid,
4464 : BTEqualStrategyNumber, F_OIDEQ,
4465 : ObjectIdGetDatum(objoid));
4466 :
4467 0 : scan = systable_beginscan(relation,
4468 : LargeObjectMetadataOidIndexId, true,
4469 : NULL, 1, entry);
4470 :
4471 0 : tuple = systable_getnext(scan);
4472 0 : if (!HeapTupleIsValid(tuple))
4473 0 : elog(ERROR, "could not find tuple for large object %u", objoid);
4474 :
4475 0 : aclDatum = heap_getattr(tuple,
4476 : Anum_pg_largeobject_metadata_lomacl,
4477 : RelationGetDescr(relation), &isNull);
4478 :
4479 : /* Add the record, if any, for the top-level object */
4480 0 : if (!isNull)
4481 0 : recordExtensionInitPrivWorker(objoid, classoid, 0,
4482 0 : DatumGetAclP(aclDatum));
4483 :
4484 0 : systable_endscan(scan);
4485 : }
4486 : /* This will error on unsupported classoid. */
4487 88 : else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4488 : {
4489 : int cacheid;
4490 : Datum aclDatum;
4491 : bool isNull;
4492 : HeapTuple tuple;
4493 :
4494 66 : cacheid = get_object_catcache_oid(classoid);
4495 66 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
4496 66 : if (!HeapTupleIsValid(tuple))
4497 0 : elog(ERROR, "cache lookup failed for %s %u",
4498 : get_object_class_descr(classoid), objoid);
4499 :
4500 66 : aclDatum = SysCacheGetAttr(cacheid, tuple,
4501 66 : get_object_attnum_acl(classoid),
4502 : &isNull);
4503 :
4504 : /* Add the record, if any, for the top-level object */
4505 66 : if (!isNull)
4506 10 : recordExtensionInitPrivWorker(objoid, classoid, 0,
4507 10 : DatumGetAclP(aclDatum));
4508 :
4509 66 : ReleaseSysCache(tuple);
4510 : }
4511 : }
4512 :
4513 : /*
4514 : * For the object passed in, remove its ACL and the ACLs of any object subIds
4515 : * from pg_init_privs (via recordExtensionInitPrivWorker()).
4516 : */
4517 : void
4518 354 : removeExtObjInitPriv(Oid objoid, Oid classoid)
4519 : {
4520 : /*
4521 : * If this is a relation then we need to see if there are any sub-objects
4522 : * (eg: columns) for it and, if so, be sure to call
4523 : * recordExtensionInitPrivWorker() for each one.
4524 : */
4525 354 : if (classoid == RelationRelationId)
4526 : {
4527 : Form_pg_class pg_class_tuple;
4528 : HeapTuple tuple;
4529 :
4530 70 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4531 70 : if (!HeapTupleIsValid(tuple))
4532 0 : elog(ERROR, "cache lookup failed for relation %u", objoid);
4533 70 : pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4534 :
4535 : /*
4536 : * Indexes don't have permissions, neither do the pg_class rows for
4537 : * composite types. (These cases are unreachable given the
4538 : * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4539 : */
4540 70 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
4541 70 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4542 70 : pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4543 : {
4544 0 : ReleaseSysCache(tuple);
4545 0 : return;
4546 : }
4547 :
4548 : /*
4549 : * If this isn't a sequence then it's possibly going to have
4550 : * column-level ACLs associated with it.
4551 : */
4552 70 : if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4553 : {
4554 : AttrNumber curr_att;
4555 70 : AttrNumber nattrs = pg_class_tuple->relnatts;
4556 :
4557 2356 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
4558 : {
4559 : HeapTuple attTuple;
4560 :
4561 2286 : attTuple = SearchSysCache2(ATTNUM,
4562 : ObjectIdGetDatum(objoid),
4563 : Int16GetDatum(curr_att));
4564 :
4565 2286 : if (!HeapTupleIsValid(attTuple))
4566 0 : continue;
4567 :
4568 : /* when removing, remove all entries, even dropped columns */
4569 :
4570 2286 : recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4571 :
4572 2286 : ReleaseSysCache(attTuple);
4573 : }
4574 : }
4575 :
4576 70 : ReleaseSysCache(tuple);
4577 : }
4578 :
4579 : /* Remove the record, if any, for the top-level object */
4580 354 : recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
4581 : }
4582 :
4583 : /*
4584 : * Record initial ACL for an extension object
4585 : *
4586 : * Can be called at any time, we check if 'creating_extension' is set and, if
4587 : * not, exit immediately.
4588 : *
4589 : * Pass in the object OID, the OID of the class (the OID of the table which
4590 : * the object is defined in) and the 'sub' id of the object (objsubid), if
4591 : * any. If there is no 'sub' id (they are currently only used for columns of
4592 : * tables) then pass in '0'. Finally, pass in the complete ACL to store.
4593 : *
4594 : * If an ACL already exists for this object/sub-object then we will replace
4595 : * it with what is passed in.
4596 : *
4597 : * Passing in NULL for 'new_acl' will result in the entry for the object being
4598 : * removed, if one is found.
4599 : */
4600 : static void
4601 32590 : recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
4602 : {
4603 : /*
4604 : * Generally, we only record the initial privileges when an extension is
4605 : * being created, but because we don't actually use CREATE EXTENSION
4606 : * during binary upgrades with pg_upgrade, there is a variable to let us
4607 : * know that the GRANT and REVOKE statements being issued, while this
4608 : * variable is true, are for the initial privileges of the extension
4609 : * object and therefore we need to record them.
4610 : */
4611 32590 : if (!creating_extension && !binary_upgrade_record_init_privs)
4612 31776 : return;
4613 :
4614 814 : recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4615 : }
4616 :
4617 : /*
4618 : * Record initial ACL for an extension object, worker.
4619 : *
4620 : * This will perform a wholesale replacement of the entire ACL for the object
4621 : * passed in, therefore be sure to pass in the complete new ACL to use.
4622 : *
4623 : * Generally speaking, do *not* use this function directly but instead use
4624 : * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
4625 : * This function does *not* check if 'creating_extension' is set as it is also
4626 : * used when an object is added to or removed from an extension via ALTER
4627 : * EXTENSION ... ADD/DROP.
4628 : */
4629 : static void
4630 3476 : recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
4631 : Acl *new_acl)
4632 : {
4633 : Relation relation;
4634 : ScanKeyData key[3];
4635 : SysScanDesc scan;
4636 : HeapTuple tuple;
4637 : HeapTuple oldtuple;
4638 : int noldmembers;
4639 : int nnewmembers;
4640 : Oid *oldmembers;
4641 : Oid *newmembers;
4642 :
4643 : /* We'll need the role membership of the new ACL. */
4644 3476 : nnewmembers = aclmembers(new_acl, &newmembers);
4645 :
4646 : /* Search pg_init_privs for an existing entry. */
4647 3476 : relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4648 :
4649 3476 : ScanKeyInit(&key[0],
4650 : Anum_pg_init_privs_objoid,
4651 : BTEqualStrategyNumber, F_OIDEQ,
4652 : ObjectIdGetDatum(objoid));
4653 3476 : ScanKeyInit(&key[1],
4654 : Anum_pg_init_privs_classoid,
4655 : BTEqualStrategyNumber, F_OIDEQ,
4656 : ObjectIdGetDatum(classoid));
4657 3476 : ScanKeyInit(&key[2],
4658 : Anum_pg_init_privs_objsubid,
4659 : BTEqualStrategyNumber, F_INT4EQ,
4660 : Int32GetDatum(objsubid));
4661 :
4662 3476 : scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4663 : NULL, 3, key);
4664 :
4665 : /* There should exist only one entry or none. */
4666 3476 : oldtuple = systable_getnext(scan);
4667 :
4668 : /* If we find an entry, update it with the latest ACL. */
4669 3476 : if (HeapTupleIsValid(oldtuple))
4670 : {
4671 280 : Datum values[Natts_pg_init_privs] = {0};
4672 280 : bool nulls[Natts_pg_init_privs] = {0};
4673 280 : bool replace[Natts_pg_init_privs] = {0};
4674 : Datum oldAclDatum;
4675 : bool isNull;
4676 : Acl *old_acl;
4677 :
4678 : /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
4679 280 : oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4680 : RelationGetDescr(relation), &isNull);
4681 : Assert(!isNull);
4682 280 : old_acl = DatumGetAclP(oldAclDatum);
4683 280 : noldmembers = aclmembers(old_acl, &oldmembers);
4684 :
4685 280 : updateInitAclDependencies(classoid, objoid, objsubid,
4686 : noldmembers, oldmembers,
4687 : nnewmembers, newmembers);
4688 :
4689 : /* If we have a new ACL to set, then update the row with it. */
4690 280 : if (new_acl && ACL_NUM(new_acl) != 0)
4691 : {
4692 182 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4693 182 : replace[Anum_pg_init_privs_initprivs - 1] = true;
4694 :
4695 182 : oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4696 : values, nulls, replace);
4697 :
4698 182 : CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4699 : }
4700 : else
4701 : {
4702 : /* new_acl is NULL/empty, so delete the entry we found. */
4703 98 : CatalogTupleDelete(relation, &oldtuple->t_self);
4704 : }
4705 : }
4706 : else
4707 : {
4708 3196 : Datum values[Natts_pg_init_privs] = {0};
4709 3196 : bool nulls[Natts_pg_init_privs] = {0};
4710 :
4711 : /*
4712 : * Only add a new entry if the new ACL is non-NULL.
4713 : *
4714 : * If we are passed in a NULL ACL and no entry exists, we can just
4715 : * fall through and do nothing.
4716 : */
4717 3196 : if (new_acl && ACL_NUM(new_acl) != 0)
4718 : {
4719 : /* No entry found, so add it. */
4720 648 : values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4721 648 : values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4722 648 : values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4723 :
4724 : /* This function only handles initial privileges of extensions */
4725 648 : values[Anum_pg_init_privs_privtype - 1] =
4726 648 : CharGetDatum(INITPRIVS_EXTENSION);
4727 :
4728 648 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4729 :
4730 648 : tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4731 :
4732 648 : CatalogTupleInsert(relation, tuple);
4733 :
4734 : /* Update pg_shdepend, too. */
4735 648 : noldmembers = 0;
4736 648 : oldmembers = NULL;
4737 :
4738 648 : updateInitAclDependencies(classoid, objoid, objsubid,
4739 : noldmembers, oldmembers,
4740 : nnewmembers, newmembers);
4741 : }
4742 : }
4743 :
4744 3476 : systable_endscan(scan);
4745 :
4746 : /* prevent error when processing objects multiple times */
4747 3476 : CommandCounterIncrement();
4748 :
4749 3476 : table_close(relation, RowExclusiveLock);
4750 3476 : }
4751 :
4752 : /*
4753 : * ReplaceRoleInInitPriv
4754 : *
4755 : * Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
4756 : */
4757 : void
4758 24 : ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
4759 : Oid classid, Oid objid, int32 objsubid)
4760 : {
4761 : Relation rel;
4762 : ScanKeyData key[3];
4763 : SysScanDesc scan;
4764 : HeapTuple oldtuple;
4765 : Datum oldAclDatum;
4766 : bool isNull;
4767 : Acl *old_acl;
4768 : Acl *new_acl;
4769 : HeapTuple newtuple;
4770 : int noldmembers;
4771 : int nnewmembers;
4772 : Oid *oldmembers;
4773 : Oid *newmembers;
4774 :
4775 : /* Search for existing pg_init_privs entry for the target object. */
4776 24 : rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4777 :
4778 24 : ScanKeyInit(&key[0],
4779 : Anum_pg_init_privs_objoid,
4780 : BTEqualStrategyNumber, F_OIDEQ,
4781 : ObjectIdGetDatum(objid));
4782 24 : ScanKeyInit(&key[1],
4783 : Anum_pg_init_privs_classoid,
4784 : BTEqualStrategyNumber, F_OIDEQ,
4785 : ObjectIdGetDatum(classid));
4786 24 : ScanKeyInit(&key[2],
4787 : Anum_pg_init_privs_objsubid,
4788 : BTEqualStrategyNumber, F_INT4EQ,
4789 : Int32GetDatum(objsubid));
4790 :
4791 24 : scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4792 : NULL, 3, key);
4793 :
4794 : /* There should exist only one entry or none. */
4795 24 : oldtuple = systable_getnext(scan);
4796 :
4797 24 : if (!HeapTupleIsValid(oldtuple))
4798 : {
4799 : /*
4800 : * Hmm, why are we here if there's no entry? But pack up and go away
4801 : * quietly.
4802 : */
4803 0 : systable_endscan(scan);
4804 0 : table_close(rel, RowExclusiveLock);
4805 0 : return;
4806 : }
4807 :
4808 : /* Get a writable copy of the existing ACL. */
4809 24 : oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4810 : RelationGetDescr(rel), &isNull);
4811 : Assert(!isNull);
4812 24 : old_acl = DatumGetAclPCopy(oldAclDatum);
4813 :
4814 : /*
4815 : * Generate new ACL. This usage of aclnewowner is a bit off-label when
4816 : * oldroleid isn't the owner; but it does the job fine.
4817 : */
4818 24 : new_acl = aclnewowner(old_acl, oldroleid, newroleid);
4819 :
4820 : /*
4821 : * If we end with an empty ACL, delete the pg_init_privs entry. (That
4822 : * probably can't happen here, but we may as well cover the case.)
4823 : */
4824 24 : if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4825 : {
4826 0 : CatalogTupleDelete(rel, &oldtuple->t_self);
4827 : }
4828 : else
4829 : {
4830 24 : Datum values[Natts_pg_init_privs] = {0};
4831 24 : bool nulls[Natts_pg_init_privs] = {0};
4832 24 : bool replaces[Natts_pg_init_privs] = {0};
4833 :
4834 : /* Update existing entry. */
4835 24 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4836 24 : replaces[Anum_pg_init_privs_initprivs - 1] = true;
4837 :
4838 24 : newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4839 : values, nulls, replaces);
4840 24 : CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4841 : }
4842 :
4843 : /*
4844 : * Update the shared dependency ACL info.
4845 : */
4846 24 : noldmembers = aclmembers(old_acl, &oldmembers);
4847 24 : nnewmembers = aclmembers(new_acl, &newmembers);
4848 :
4849 24 : updateInitAclDependencies(classid, objid, objsubid,
4850 : noldmembers, oldmembers,
4851 : nnewmembers, newmembers);
4852 :
4853 24 : systable_endscan(scan);
4854 :
4855 : /* prevent error when processing objects multiple times */
4856 24 : CommandCounterIncrement();
4857 :
4858 24 : table_close(rel, RowExclusiveLock);
4859 : }
4860 :
4861 : /*
4862 : * RemoveRoleFromInitPriv
4863 : *
4864 : * Used by shdepDropOwned to remove mentions of a role in pg_init_privs.
4865 : */
4866 : void
4867 28 : RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
4868 : {
4869 : Relation rel;
4870 : ScanKeyData key[3];
4871 : SysScanDesc scan;
4872 : HeapTuple oldtuple;
4873 : int cacheid;
4874 : HeapTuple objtuple;
4875 : Oid ownerId;
4876 : Datum oldAclDatum;
4877 : bool isNull;
4878 : Acl *old_acl;
4879 : Acl *new_acl;
4880 : HeapTuple newtuple;
4881 : int noldmembers;
4882 : int nnewmembers;
4883 : Oid *oldmembers;
4884 : Oid *newmembers;
4885 :
4886 : /* Search for existing pg_init_privs entry for the target object. */
4887 28 : rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4888 :
4889 28 : ScanKeyInit(&key[0],
4890 : Anum_pg_init_privs_objoid,
4891 : BTEqualStrategyNumber, F_OIDEQ,
4892 : ObjectIdGetDatum(objid));
4893 28 : ScanKeyInit(&key[1],
4894 : Anum_pg_init_privs_classoid,
4895 : BTEqualStrategyNumber, F_OIDEQ,
4896 : ObjectIdGetDatum(classid));
4897 28 : ScanKeyInit(&key[2],
4898 : Anum_pg_init_privs_objsubid,
4899 : BTEqualStrategyNumber, F_INT4EQ,
4900 : Int32GetDatum(objsubid));
4901 :
4902 28 : scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4903 : NULL, 3, key);
4904 :
4905 : /* There should exist only one entry or none. */
4906 28 : oldtuple = systable_getnext(scan);
4907 :
4908 28 : if (!HeapTupleIsValid(oldtuple))
4909 : {
4910 : /*
4911 : * Hmm, why are we here if there's no entry? But pack up and go away
4912 : * quietly.
4913 : */
4914 0 : systable_endscan(scan);
4915 0 : table_close(rel, RowExclusiveLock);
4916 0 : return;
4917 : }
4918 :
4919 : /* Get a writable copy of the existing ACL. */
4920 28 : oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4921 : RelationGetDescr(rel), &isNull);
4922 : Assert(!isNull);
4923 28 : old_acl = DatumGetAclPCopy(oldAclDatum);
4924 :
4925 : /*
4926 : * We need the members of both old and new ACLs so we can correct the
4927 : * shared dependency information. Collect data before
4928 : * merge_acl_with_grant throws away old_acl.
4929 : */
4930 28 : noldmembers = aclmembers(old_acl, &oldmembers);
4931 :
4932 : /* Must find out the owner's OID the hard way. */
4933 28 : cacheid = get_object_catcache_oid(classid);
4934 28 : objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
4935 28 : if (!HeapTupleIsValid(objtuple))
4936 0 : elog(ERROR, "cache lookup failed for %s %u",
4937 : get_object_class_descr(classid), objid);
4938 :
4939 28 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4940 : objtuple,
4941 28 : get_object_attnum_owner(classid)));
4942 28 : ReleaseSysCache(objtuple);
4943 :
4944 : /*
4945 : * Generate new ACL. Grantor of rights is always the same as the owner.
4946 : */
4947 28 : if (old_acl != NULL)
4948 28 : new_acl = merge_acl_with_grant(old_acl,
4949 : false, /* is_grant */
4950 : false, /* grant_option */
4951 : DROP_RESTRICT,
4952 28 : list_make1_oid(roleid),
4953 : ACLITEM_ALL_PRIV_BITS,
4954 : ownerId,
4955 : ownerId);
4956 : else
4957 0 : new_acl = NULL; /* this case shouldn't happen, probably */
4958 :
4959 : /* If we end with an empty ACL, delete the pg_init_privs entry. */
4960 28 : if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4961 : {
4962 0 : CatalogTupleDelete(rel, &oldtuple->t_self);
4963 : }
4964 : else
4965 : {
4966 28 : Datum values[Natts_pg_init_privs] = {0};
4967 28 : bool nulls[Natts_pg_init_privs] = {0};
4968 28 : bool replaces[Natts_pg_init_privs] = {0};
4969 :
4970 : /* Update existing entry. */
4971 28 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4972 28 : replaces[Anum_pg_init_privs_initprivs - 1] = true;
4973 :
4974 28 : newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4975 : values, nulls, replaces);
4976 28 : CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4977 : }
4978 :
4979 : /*
4980 : * Update the shared dependency ACL info.
4981 : */
4982 28 : nnewmembers = aclmembers(new_acl, &newmembers);
4983 :
4984 28 : updateInitAclDependencies(classid, objid, objsubid,
4985 : noldmembers, oldmembers,
4986 : nnewmembers, newmembers);
4987 :
4988 28 : systable_endscan(scan);
4989 :
4990 : /* prevent error when processing objects multiple times */
4991 28 : CommandCounterIncrement();
4992 :
4993 28 : table_close(rel, RowExclusiveLock);
4994 : }
|