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