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