Age Owner TLA 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 *
7658 tgl 172 GIC 104765 : 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 104765 : modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
182 :
7720 peter_e 183 104765 : new_acl = old_acl;
184 :
185 209569 : foreach(j, grantees)
186 : {
187 : AclItem aclitem;
7157 tgl 188 ECB : Acl *newer_acl;
189 :
3955 bruce 190 GIC 104810 : 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.
7381 peter_e 197 ECB : */
6494 tgl 198 GIC 104810 : if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
7202 tgl 199 LBC 0 : ereport(ERROR,
200 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
6494 tgl 201 ECB : errmsg("grant options can only be granted to roles")));
202 :
3955 bruce 203 GIC 104810 : aclitem.ai_grantor = grantorId;
204 :
205 : /*
6886 tgl 206 ECB : * 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 : */
6494 tgl 212 GIC 104810 : ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
213 : (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
2118 tgl 214 ECB : (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
7720 peter_e 215 EUB :
6494 tgl 216 GIC 104810 : newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
217 :
218 : /* avoid memory leak when there are many grantees */
7157 tgl 219 CBC 104804 : pfree(new_acl);
7157 tgl 220 GIC 104804 : new_acl = newer_acl;
221 : }
222 :
7720 peter_e 223 104759 : return new_acl;
224 : }
225 :
226 : /*
227 : * Restrict the privileges to what we can actually grant, and emit
6338 alvherre 228 ECB : * the standards-mandated warning and error messages.
229 : */
230 : static AclMode
6338 alvherre 231 GIC 104685 : restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
6338 alvherre 232 ECB : AclMode privileges, Oid objectId, Oid grantorId,
233 : ObjectType objtype, const char *objname,
234 : AttrNumber att_number, const char *colname)
235 : {
6031 bruce 236 : AclMode this_privileges;
237 : AclMode whole_mask;
238 :
1954 peter_e 239 CBC 104685 : switch (objtype)
240 : {
1954 peter_e 241 GIC 55894 : case OBJECT_COLUMN:
5190 tgl 242 55894 : whole_mask = ACL_ALL_RIGHTS_COLUMN;
243 55894 : break;
1954 peter_e 244 24608 : case OBJECT_TABLE:
6338 alvherre 245 24608 : whole_mask = ACL_ALL_RIGHTS_RELATION;
246 24608 : break;
1954 peter_e 247 CBC 76 : case OBJECT_SEQUENCE:
6287 bruce 248 GIC 76 : whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
249 76 : break;
1954 peter_e 250 659 : case OBJECT_DATABASE:
6338 alvherre 251 659 : whole_mask = ACL_ALL_RIGHTS_DATABASE;
252 659 : break;
1954 peter_e 253 22206 : case OBJECT_FUNCTION:
6338 alvherre 254 22206 : whole_mask = ACL_ALL_RIGHTS_FUNCTION;
6338 alvherre 255 CBC 22206 : break;
1954 peter_e 256 GIC 18 : case OBJECT_LANGUAGE:
6338 alvherre 257 CBC 18 : whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
258 18 : break;
1954 peter_e 259 40 : case OBJECT_LARGEOBJECT:
4867 itagaki.takahiro 260 40 : whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
261 40 : break;
1954 peter_e 262 978 : case OBJECT_SCHEMA:
2006 263 978 : whole_mask = ACL_ALL_RIGHTS_SCHEMA;
6338 alvherre 264 978 : break;
1954 peter_e 265 LBC 0 : case OBJECT_TABLESPACE:
6338 alvherre 266 0 : whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
267 0 : break;
1954 peter_e 268 CBC 47 : case OBJECT_FDW:
5224 269 47 : whole_mask = ACL_ALL_RIGHTS_FDW;
270 47 : break;
1954 271 44 : case OBJECT_FOREIGN_SERVER:
5224 272 44 : whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
273 44 : break;
1954 peter_e 274 LBC 0 : case OBJECT_EVENT_TRIGGER:
3917 rhaas 275 0 : elog(ERROR, "grantable rights not supported for event triggers");
3917 rhaas 276 ECB : /* not reached, but keep compiler quiet */
277 : return ACL_NO_RIGHTS;
1954 peter_e 278 CBC 47 : case OBJECT_TYPE:
4128 279 47 : whole_mask = ACL_ALL_RIGHTS_TYPE;
280 47 : break;
368 tgl 281 GBC 68 : case OBJECT_PARAMETER_ACL:
282 68 : whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
283 68 : break;
6338 alvherre 284 LBC 0 : default:
1954 peter_e 285 0 : elog(ERROR, "unrecognized object type: %d", objtype);
6338 alvherre 286 ECB : /* not reached, but keep compiler quiet */
287 : return ACL_NO_RIGHTS;
288 : }
289 :
6338 alvherre 290 EUB : /*
6031 bruce 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.
6338 alvherre 294 ECB : */
6338 alvherre 295 CBC 104685 : if (avail_goptions == ACL_NO_RIGHTS)
6338 alvherre 296 ECB : {
1954 peter_e 297 CBC 33 : if (pg_aclmask(objtype, objectId, att_number, grantorId,
6338 alvherre 298 33 : whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
6338 alvherre 299 ECB : ACLMASK_ANY) == ACL_NO_RIGHTS)
5190 tgl 300 EUB : {
1954 peter_e 301 GBC 15 : if (objtype == OBJECT_COLUMN && colname)
1954 peter_e 302 UIC 0 : aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
303 : else
1954 peter_e 304 GIC 15 : 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
6031 bruce 311 ECB : * 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.)
6338 alvherre 314 : */
6338 alvherre 315 GIC 104670 : this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
316 104670 : if (is_grant)
6338 alvherre 317 ECB : {
6338 alvherre 318 GBC 29688 : if (this_privileges == 0)
319 : {
1954 peter_e 320 CBC 15 : if (objtype == OBJECT_COLUMN && colname)
4782 tgl 321 UIC 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
4782 tgl 326 GIC 15 : ereport(WARNING,
327 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
328 : errmsg("no privileges were granted for \"%s\"",
329 : objname)));
330 : }
6338 alvherre 331 CBC 29673 : else if (!all_privs && this_privileges != privileges)
4782 tgl 332 ECB : {
1954 peter_e 333 UIC 0 : if (objtype == OBJECT_COLUMN && colname)
4782 tgl 334 LBC 0 : ereport(WARNING,
335 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
4782 tgl 336 ECB : errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
4782 tgl 337 EUB : colname, objname)));
338 : else
4782 tgl 339 UIC 0 : ereport(WARNING,
340 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
341 : errmsg("not all privileges were granted for \"%s\"",
4782 tgl 342 ECB : objname)));
343 : }
344 : }
345 : else
346 : {
6338 alvherre 347 CBC 74982 : if (this_privileges == 0)
348 : {
1954 peter_e 349 GBC 3 : if (objtype == OBJECT_COLUMN && colname)
4782 tgl 350 UBC 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
4782 tgl 355 GBC 3 : ereport(WARNING,
356 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
357 : errmsg("no privileges could be revoked for \"%s\"",
358 : objname)));
359 : }
6338 alvherre 360 GIC 74979 : else if (!all_privs && this_privileges != privileges)
361 : {
1954 peter_e 362 UIC 0 : if (objtype == OBJECT_COLUMN && colname)
4782 tgl 363 LBC 0 : ereport(WARNING,
364 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
4782 tgl 365 ECB : errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
4782 tgl 366 EUB : colname, objname)));
367 : else
4782 tgl 368 UIC 0 : ereport(WARNING,
369 : (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
370 : errmsg("not all privileges could be revoked for \"%s\"",
2118 tgl 371 ECB : objname)));
372 : }
373 : }
374 :
6338 alvherre 375 GIC 104670 : return this_privileges;
6338 alvherre 376 ECB : }
377 :
9770 scrappy 378 EUB : /*
7974 peter_e 379 : * Called to execute the utility commands GRANT and REVOKE
380 : */
381 : void
7974 peter_e 382 GIC 48822 : ExecuteGrantStmt(GrantStmt *stmt)
383 : {
6338 alvherre 384 EUB : InternalGrant istmt;
385 : ListCell *cell;
386 : const char *errormsg;
387 : AclMode all_privileges;
388 :
799 peter 389 GIC 48822 : if (stmt->grantor)
390 : {
799 peter 391 ECB : Oid grantor;
392 :
799 peter 393 GIC 9 : grantor = get_rolespec_oid(stmt->grantor, false);
394 :
395 : /*
396 : * Currently, this clause is only for SQL compatibility, not very
397 : * interesting otherwise.
799 peter 398 ECB : */
799 peter 399 GIC 9 : if (grantor != GetUserId())
400 3 : ereport(ERROR,
401 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
402 : errmsg("grantor must be current user")));
403 : }
404 :
6338 alvherre 405 ECB : /*
406 : * Turn the regular GrantStmt into the InternalGrant form.
407 : */
6338 alvherre 408 GIC 48819 : istmt.is_grant = stmt->is_grant;
6338 alvherre 409 CBC 48819 : istmt.objtype = stmt->objtype;
410 :
411 : /* Collect the OIDs of the target objects */
4927 tgl 412 GIC 48819 : switch (stmt->targtype)
413 : {
414 48804 : case ACL_TARGET_OBJECT:
368 tgl 415 CBC 97595 : istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
416 48804 : stmt->is_grant);
4927 tgl 417 GIC 48791 : break;
418 15 : case ACL_TARGET_ALL_IN_SCHEMA:
419 15 : istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
420 15 : break;
421 : /* ACL_TARGET_DEFAULTS should not be seen here */
4927 tgl 422 UIC 0 : default:
423 0 : elog(ERROR, "unrecognized GrantStmt.targtype: %d",
4927 tgl 424 ECB : (int) stmt->targtype);
425 : }
426 :
427 : /* all_privs to be filled below */
6338 alvherre 428 : /* privileges to be filled below */
5190 tgl 429 GIC 48806 : istmt.col_privs = NIL; /* may get filled below */
5190 tgl 430 CBC 48806 : istmt.grantees = NIL; /* filled below */
6338 alvherre 431 48806 : istmt.grant_option = stmt->grant_option;
432 48806 : istmt.behavior = stmt->behavior;
6338 alvherre 433 ECB :
6348 434 : /*
2878 bruce 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.
6348 alvherre 438 EUB : */
6348 alvherre 439 GBC 97639 : foreach(cell, stmt->grantees)
440 : {
2878 bruce 441 GIC 48836 : RoleSpec *grantee = (RoleSpec *) lfirst(cell);
442 : Oid grantee_uid;
443 :
2953 alvherre 444 48836 : switch (grantee->roletype)
2953 alvherre 445 ECB : {
2953 alvherre 446 CBC 44015 : case ROLESPEC_PUBLIC:
447 44015 : grantee_uid = ACL_ID_PUBLIC;
448 44015 : break;
2953 alvherre 449 GIC 4821 : default:
2293 peter_e 450 4821 : grantee_uid = get_rolespec_oid(grantee, false);
2953 alvherre 451 4818 : break;
452 : }
453 48833 : istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
454 : }
6348 alvherre 455 ECB :
456 : /*
5050 bruce 457 : * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
458 : * bitmask. Note: objtype can't be OBJECT_COLUMN.
459 : */
7658 tgl 460 CBC 48803 : switch (stmt->objtype)
461 : {
2006 peter_e 462 25070 : case OBJECT_TABLE:
1809 tgl 463 ECB :
6031 bruce 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 : */
6287 bruce 469 CBC 25070 : all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
5494 tgl 470 GIC 25070 : errormsg = gettext_noop("invalid privilege type %s for relation");
6287 bruce 471 25070 : break;
2006 peter_e 472 6 : case OBJECT_SEQUENCE:
6287 bruce 473 6 : all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
5494 tgl 474 6 : errormsg = gettext_noop("invalid privilege type %s for sequence");
7658 475 6 : break;
2006 peter_e 476 CBC 655 : case OBJECT_DATABASE:
6348 alvherre 477 GIC 655 : all_privileges = ACL_ALL_RIGHTS_DATABASE;
5494 tgl 478 CBC 655 : errormsg = gettext_noop("invalid privilege type %s for database");
7720 peter_e 479 GIC 655 : break;
2006 480 10 : case OBJECT_DOMAIN:
4128 481 10 : all_privileges = ACL_ALL_RIGHTS_TYPE;
482 10 : errormsg = gettext_noop("invalid privilege type %s for domain");
483 10 : break;
2006 484 22156 : case OBJECT_FUNCTION:
6348 alvherre 485 CBC 22156 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
5494 tgl 486 22156 : errormsg = gettext_noop("invalid privilege type %s for function");
7720 peter_e 487 22156 : break;
2006 488 21 : case OBJECT_LANGUAGE:
6348 alvherre 489 21 : all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
5494 tgl 490 21 : errormsg = gettext_noop("invalid privilege type %s for language");
7658 491 21 : break;
2006 peter_e 492 31 : case OBJECT_LARGEOBJECT:
4867 itagaki.takahiro 493 31 : all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
494 31 : errormsg = gettext_noop("invalid privilege type %s for large object");
495 31 : break;
2006 peter_e 496 666 : case OBJECT_SCHEMA:
497 666 : all_privileges = ACL_ALL_RIGHTS_SCHEMA;
5494 tgl 498 666 : errormsg = gettext_noop("invalid privilege type %s for schema");
7720 peter_e 499 666 : break;
2006 500 21 : case OBJECT_PROCEDURE:
1956 501 21 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
502 21 : errormsg = gettext_noop("invalid privilege type %s for procedure");
503 21 : break;
2006 504 3 : case OBJECT_ROUTINE:
1956 505 3 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
506 3 : errormsg = gettext_noop("invalid privilege type %s for routine");
507 3 : break;
2006 peter_e 508 LBC 0 : case OBJECT_TABLESPACE:
6348 alvherre 509 0 : all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
5494 tgl 510 0 : errormsg = gettext_noop("invalid privilege type %s for tablespace");
6869 511 0 : break;
2006 peter_e 512 CBC 43 : case OBJECT_TYPE:
4128 513 43 : all_privileges = ACL_ALL_RIGHTS_TYPE;
514 43 : errormsg = gettext_noop("invalid privilege type %s for type");
515 43 : break;
2006 516 46 : case OBJECT_FDW:
5224 517 46 : all_privileges = ACL_ALL_RIGHTS_FDW;
518 46 : errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
519 46 : break;
2006 520 38 : case OBJECT_FOREIGN_SERVER:
5224 521 38 : all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
522 38 : errormsg = gettext_noop("invalid privilege type %s for foreign server");
523 38 : break;
368 tgl 524 GBC 37 : case OBJECT_PARAMETER_ACL:
525 37 : all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
526 37 : errormsg = gettext_noop("invalid privilege type %s for parameter");
527 37 : break;
7720 peter_e 528 LBC 0 : default:
4934 tgl 529 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
4934 tgl 530 ECB : (int) stmt->objtype);
6338 alvherre 531 : /* keep compiler quiet */
532 : all_privileges = ACL_NO_RIGHTS;
533 : errormsg = NULL;
7720 peter_e 534 : }
535 :
6494 tgl 536 CBC 48803 : if (stmt->privileges == NIL)
6886 tgl 537 ECB : {
6338 alvherre 538 CBC 4646 : istmt.all_privs = true;
6031 bruce 539 ECB :
6338 alvherre 540 : /*
541 : * will be turned into ACL_ALL_RIGHTS_* by the internal routines
542 : * depending on the object type
543 : */
6338 alvherre 544 GBC 4646 : istmt.privileges = ACL_NO_RIGHTS;
6886 tgl 545 EUB : }
546 : else
547 : {
6338 alvherre 548 GIC 44157 : istmt.all_privs = false;
549 44157 : istmt.privileges = ACL_NO_RIGHTS;
550 :
6348 551 89310 : foreach(cell, stmt->privileges)
7720 peter_e 552 ECB : {
5190 tgl 553 GIC 45165 : AccessPriv *privnode = (AccessPriv *) lfirst(cell);
5190 tgl 554 ECB : 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 : */
5190 tgl 560 CBC 45165 : if (privnode->cols)
561 : {
2006 peter_e 562 GIC 469 : if (stmt->objtype != OBJECT_TABLE)
5190 tgl 563 UIC 0 : ereport(ERROR,
5190 tgl 564 ECB : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
565 : errmsg("column privileges are only valid for relations")));
5190 tgl 566 GIC 469 : istmt.col_privs = lappend(istmt.col_privs, privnode);
5190 tgl 567 CBC 469 : continue;
568 : }
5190 tgl 569 ECB :
5050 bruce 570 GIC 44696 : if (privnode->priv_name == NULL) /* parser mistake? */
5190 tgl 571 UIC 0 : elog(ERROR, "AccessPriv node must specify privilege or columns");
5190 tgl 572 GIC 44696 : priv = string_to_privilege(privnode->priv_name);
573 :
6348 alvherre 574 44696 : if (priv & ~((AclMode) all_privileges))
7202 tgl 575 12 : ereport(ERROR,
7202 tgl 576 ECB : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
577 : errmsg(errormsg, privilege_to_string(priv))));
6348 alvherre 578 :
6338 alvherre 579 GBC 44684 : istmt.privileges |= priv;
580 : }
581 : }
7720 peter_e 582 ECB :
6338 alvherre 583 CBC 48791 : ExecGrantStmt_oids(&istmt);
6348 alvherre 584 GIC 48761 : }
585 :
6348 alvherre 586 ECB : /*
6348 alvherre 587 EUB : * ExecGrantStmt_oids
6348 alvherre 588 ECB : *
589 : * Internal entry point for granting and revoking privileges.
590 : */
4934 tgl 591 : static void
6338 alvherre 592 GIC 48881 : ExecGrantStmt_oids(InternalGrant *istmt)
593 : {
594 48881 : switch (istmt->objtype)
8287 tgl 595 ECB : {
2006 peter_e 596 GIC 25114 : case OBJECT_TABLE:
597 : case OBJECT_SEQUENCE:
6338 alvherre 598 25114 : ExecGrant_Relation(istmt);
6348 alvherre 599 CBC 25111 : break;
2006 peter_e 600 659 : case OBJECT_DATABASE:
117 peter 601 GNC 659 : ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
6348 alvherre 602 GIC 659 : break;
2006 peter_e 603 53 : case OBJECT_DOMAIN:
604 : case OBJECT_TYPE:
117 peter 605 GNC 53 : ExecGrant_common(istmt, TypeRelationId, ACL_ALL_RIGHTS_TYPE, ExecGrant_Type_check);
4128 peter_e 606 GIC 44 : break;
2006 607 47 : case OBJECT_FDW:
117 peter 608 GNC 47 : ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
5224 peter_e 609 GIC 38 : break;
2006 peter_e 610 CBC 44 : case OBJECT_FOREIGN_SERVER:
117 peter 611 GNC 44 : ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
5224 peter_e 612 CBC 38 : break;
2006 peter_e 613 GIC 22185 : case OBJECT_FUNCTION:
2006 peter_e 614 ECB : case OBJECT_PROCEDURE:
615 : case OBJECT_ROUTINE:
117 peter 616 GNC 22185 : ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
6348 alvherre 617 CBC 22185 : break;
2006 peter_e 618 21 : case OBJECT_LANGUAGE:
117 peter 619 GNC 21 : ExecGrant_common(istmt, LanguageRelationId, ACL_ALL_RIGHTS_LANGUAGE, ExecGrant_Language_check);
6348 alvherre 620 GIC 18 : break;
2006 peter_e 621 CBC 37 : case OBJECT_LARGEOBJECT:
4867 itagaki.takahiro 622 37 : ExecGrant_Largeobject(istmt);
623 37 : break;
2006 peter_e 624 672 : case OBJECT_SCHEMA:
117 peter 625 GNC 672 : ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
6348 alvherre 626 CBC 672 : break;
2006 peter_e 627 LBC 0 : case OBJECT_TABLESPACE:
117 peter 628 UNC 0 : ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
6348 alvherre 629 LBC 0 : break;
368 tgl 630 GIC 49 : case OBJECT_PARAMETER_ACL:
631 49 : ExecGrant_Parameter(istmt);
368 tgl 632 CBC 49 : break;
6348 alvherre 633 LBC 0 : default:
634 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
6338 alvherre 635 ECB : (int) istmt->objtype);
6348 636 : }
2890 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.
2890 alvherre 643 EUB : */
2006 peter_e 644 GBC 48851 : if (EventTriggerSupportsObjectType(istmt->objtype))
2890 alvherre 645 48143 : EventTriggerCollectGrant(istmt);
6348 alvherre 646 CBC 48851 : }
6348 alvherre 647 ECB :
648 : /*
6348 alvherre 649 EUB : * 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 *
368 tgl 659 GIC 48804 : objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
6348 alvherre 660 ECB : {
6347 bruce 661 CBC 48804 : List *objects = NIL;
6347 bruce 662 ECB : ListCell *cell;
663 :
6348 alvherre 664 GIC 48804 : Assert(objnames != NIL);
665 :
666 48804 : switch (objtype)
667 : {
2006 peter_e 668 25070 : case OBJECT_TABLE:
669 : case OBJECT_SEQUENCE:
6348 alvherre 670 50167 : foreach(cell, objnames)
671 : {
672 25097 : RangeVar *relvar = (RangeVar *) lfirst(cell);
673 : Oid relOid;
674 :
4148 rhaas 675 CBC 25097 : relOid = RangeVarGetRelid(relvar, NoLock, false);
6348 alvherre 676 GIC 25097 : objects = lappend_oid(objects, relOid);
6348 alvherre 677 ECB : }
6348 alvherre 678 GIC 25070 : break;
2006 peter_e 679 655 : case OBJECT_DATABASE:
6348 alvherre 680 CBC 1310 : foreach(cell, objnames)
681 : {
682 655 : char *dbname = strVal(lfirst(cell));
683 : Oid dbid;
6348 alvherre 684 ECB :
4630 rhaas 685 GIC 655 : dbid = get_database_oid(dbname, false);
6185 tgl 686 CBC 655 : objects = lappend_oid(objects, dbid);
687 : }
6348 alvherre 688 655 : break;
2006 peter_e 689 GIC 53 : case OBJECT_DOMAIN:
690 : case OBJECT_TYPE:
4128 peter_e 691 CBC 106 : foreach(cell, objnames)
4128 peter_e 692 ECB : {
4128 peter_e 693 GIC 53 : List *typname = (List *) lfirst(cell);
4128 peter_e 694 ECB : Oid oid;
695 :
4128 peter_e 696 CBC 53 : oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
4128 peter_e 697 GIC 53 : objects = lappend_oid(objects, oid);
4128 peter_e 698 ECB : }
4128 peter_e 699 GIC 53 : break;
2006 700 22159 : case OBJECT_FUNCTION:
6348 alvherre 701 CBC 44324 : foreach(cell, objnames)
6348 alvherre 702 ECB : {
2293 peter_e 703 GIC 22171 : ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
6348 alvherre 704 ECB : Oid funcid;
705 :
1956 peter_e 706 GIC 22171 : funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
6348 alvherre 707 CBC 22165 : objects = lappend_oid(objects, funcid);
708 : }
709 22153 : break;
2006 peter_e 710 GIC 21 : case OBJECT_LANGUAGE:
6348 alvherre 711 42 : foreach(cell, objnames)
6348 alvherre 712 ECB : {
6347 bruce 713 CBC 21 : char *langname = strVal(lfirst(cell));
714 : Oid oid;
6348 alvherre 715 ECB :
4630 rhaas 716 CBC 21 : oid = get_language_oid(langname, false);
717 21 : objects = lappend_oid(objects, oid);
718 : }
6348 alvherre 719 21 : break;
2006 peter_e 720 GIC 40 : case OBJECT_LARGEOBJECT:
4867 itagaki.takahiro 721 77 : foreach(cell, objnames)
4867 itagaki.takahiro 722 ECB : {
4683 rhaas 723 CBC 43 : Oid lobjOid = oidparse(lfirst(cell));
724 :
4867 itagaki.takahiro 725 43 : if (!LargeObjectExists(lobjOid))
726 6 : ereport(ERROR,
4867 itagaki.takahiro 727 ECB : (errcode(ERRCODE_UNDEFINED_OBJECT),
728 : errmsg("large object %u does not exist",
729 : lobjOid)));
730 :
4867 itagaki.takahiro 731 GIC 37 : objects = lappend_oid(objects, lobjOid);
4867 itagaki.takahiro 732 ECB : }
4867 itagaki.takahiro 733 CBC 34 : break;
2006 peter_e 734 GIC 666 : case OBJECT_SCHEMA:
6347 bruce 735 CBC 1638 : foreach(cell, objnames)
6348 alvherre 736 ECB : {
6348 alvherre 737 CBC 972 : char *nspname = strVal(lfirst(cell));
738 : Oid oid;
6348 alvherre 739 ECB :
4630 rhaas 740 GIC 972 : oid = get_namespace_oid(nspname, false);
4630 rhaas 741 CBC 972 : objects = lappend_oid(objects, oid);
6348 alvherre 742 ECB : }
6348 alvherre 743 GIC 666 : break;
2006 peter_e 744 18 : case OBJECT_PROCEDURE:
1956 745 36 : foreach(cell, objnames)
746 : {
1956 peter_e 747 CBC 18 : ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
748 : Oid procid;
1956 peter_e 749 ECB :
1956 peter_e 750 CBC 18 : procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
751 18 : objects = lappend_oid(objects, procid);
752 : }
753 18 : break;
2006 peter_e 754 UIC 0 : case OBJECT_ROUTINE:
1956 755 0 : foreach(cell, objnames)
1956 peter_e 756 ECB : {
1956 peter_e 757 LBC 0 : ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
758 : Oid routid;
1956 peter_e 759 ECB :
1956 peter_e 760 LBC 0 : routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
761 0 : objects = lappend_oid(objects, routid);
762 : }
763 0 : break;
2006 peter_e 764 UIC 0 : case OBJECT_TABLESPACE:
6347 bruce 765 0 : foreach(cell, objnames)
6348 alvherre 766 ECB : {
6347 bruce 767 LBC 0 : char *spcname = strVal(lfirst(cell));
768 : Oid spcoid;
6348 alvherre 769 ECB :
4630 rhaas 770 UBC 0 : spcoid = get_tablespace_oid(spcname, false);
771 0 : objects = lappend_oid(objects, spcoid);
772 : }
6348 alvherre 773 0 : break;
2006 peter_e 774 GIC 46 : case OBJECT_FDW:
5224 775 92 : foreach(cell, objnames)
5224 peter_e 776 EUB : {
5050 bruce 777 GBC 46 : char *fdwname = strVal(lfirst(cell));
4391 rhaas 778 GIC 46 : Oid fdwid = get_foreign_data_wrapper_oid(fdwname, false);
5224 peter_e 779 EUB :
5224 peter_e 780 GBC 46 : objects = lappend_oid(objects, fdwid);
5224 peter_e 781 EUB : }
5224 peter_e 782 GIC 46 : break;
2006 peter_e 783 GBC 38 : case OBJECT_FOREIGN_SERVER:
5224 peter_e 784 GIC 76 : foreach(cell, objnames)
785 : {
5050 bruce 786 GBC 38 : char *srvname = strVal(lfirst(cell));
4391 rhaas 787 38 : Oid srvid = get_foreign_server_oid(srvname, false);
788 :
5224 peter_e 789 38 : objects = lappend_oid(objects, srvid);
5224 peter_e 790 ECB : }
5224 peter_e 791 CBC 38 : break;
368 tgl 792 GIC 38 : case OBJECT_PARAMETER_ACL:
368 tgl 793 CBC 100 : foreach(cell, objnames)
368 tgl 794 ECB : {
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 : */
368 tgl 805 CBC 63 : char *parameter = strVal(lfirst(cell));
368 tgl 806 GIC 63 : Oid parameterId = ParameterAclLookup(parameter, true);
368 tgl 807 ECB :
368 tgl 808 CBC 63 : if (!OidIsValid(parameterId) && is_grant)
368 tgl 809 ECB : {
368 tgl 810 GIC 35 : 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 34 : CommandCounterIncrement();
818 : }
819 62 : if (OidIsValid(parameterId))
820 56 : objects = lappend_oid(objects, parameterId);
368 tgl 821 ECB : }
368 tgl 822 CBC 37 : break;
6348 alvherre 823 UIC 0 : default:
6348 alvherre 824 LBC 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
825 : (int) objtype);
6348 alvherre 826 ECB : }
827 :
6348 alvherre 828 GIC 48791 : return objects;
829 : }
830 :
831 : /*
832 : * objectsInSchemaToOids
4927 tgl 833 ECB : *
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 *
2006 peter_e 839 GBC 15 : objectsInSchemaToOids(ObjectType objtype, List *nspnames)
4927 tgl 840 EUB : {
4927 tgl 841 GIC 15 : List *objects = NIL;
842 : ListCell *cell;
843 :
4927 tgl 844 CBC 30 : foreach(cell, nspnames)
845 : {
4927 tgl 846 GIC 15 : char *nspname = strVal(lfirst(cell));
847 : Oid namespaceId;
848 : List *objs;
849 :
3725 bruce 850 15 : namespaceId = LookupExplicitNamespace(nspname, false);
851 :
4927 tgl 852 15 : switch (objtype)
853 : {
2006 peter_e 854 6 : case OBJECT_TABLE:
4927 tgl 855 CBC 6 : objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
4927 tgl 856 GIC 6 : objects = list_concat(objects, objs);
4927 tgl 857 CBC 6 : objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
4927 tgl 858 GIC 6 : objects = list_concat(objects, objs);
3689 kgrittn 859 6 : objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
3689 kgrittn 860 CBC 6 : objects = list_concat(objects, objs);
4481 rhaas 861 GIC 6 : objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
4481 rhaas 862 CBC 6 : objects = list_concat(objects, objs);
2314 rhaas 863 GIC 6 : objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
864 6 : objects = list_concat(objects, objs);
4927 tgl 865 6 : break;
2006 peter_e 866 LBC 0 : case OBJECT_SEQUENCE:
4927 tgl 867 UIC 0 : objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
4927 tgl 868 LBC 0 : objects = list_concat(objects, objs);
4927 tgl 869 UIC 0 : break;
2006 peter_e 870 CBC 9 : case OBJECT_FUNCTION:
2006 peter_e 871 ECB : case OBJECT_PROCEDURE:
872 : case OBJECT_ROUTINE:
4927 tgl 873 : {
1956 peter_e 874 : ScanKeyData key[2];
875 : int keycount;
4927 tgl 876 : Relation rel;
1490 andres 877 : TableScanDesc scan;
4927 tgl 878 : HeapTuple tuple;
879 :
1956 peter_e 880 CBC 9 : keycount = 0;
881 9 : ScanKeyInit(&key[keycount++],
4927 tgl 882 EUB : Anum_pg_proc_pronamespace,
883 : BTEqualStrategyNumber, F_OIDEQ,
884 : ObjectIdGetDatum(namespaceId));
885 :
2006 peter_e 886 CBC 9 : if (objtype == OBJECT_FUNCTION)
887 : /* includes aggregates and window functions */
1956 peter_e 888 GIC 3 : ScanKeyInit(&key[keycount++],
889 : Anum_pg_proc_prokind,
890 : BTEqualStrategyNumber, F_CHARNE,
891 : CharGetDatum(PROKIND_PROCEDURE));
2006 892 6 : else if (objtype == OBJECT_PROCEDURE)
1956 893 3 : ScanKeyInit(&key[keycount++],
894 : Anum_pg_proc_prokind,
895 : BTEqualStrategyNumber, F_CHAREQ,
1864 peter_e 896 ECB : CharGetDatum(PROKIND_PROCEDURE));
1956 897 :
1539 andres 898 GIC 9 : rel = table_open(ProcedureRelationId, AccessShareLock);
1490 899 9 : scan = table_beginscan_catalog(rel, keycount, key);
900 :
4927 tgl 901 27 : while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
4927 tgl 902 ECB : {
1418 tgl 903 GIC 18 : Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
1601 andres 904 ECB :
1601 andres 905 GIC 18 : objects = lappend_oid(objects, oid);
906 : }
907 :
1490 andres 908 CBC 9 : table_endscan(scan);
1539 909 9 : table_close(rel, AccessShareLock);
910 : }
4927 tgl 911 GIC 9 : break;
4927 tgl 912 UIC 0 : default:
913 : /* should not happen */
4927 tgl 914 LBC 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
4927 tgl 915 ECB : (int) objtype);
916 : }
917 : }
918 :
4927 tgl 919 CBC 15 : return objects;
920 : }
4927 tgl 921 ECB :
922 : /*
923 : * getRelationsInNamespace
924 : *
925 : * Return Oid list of relations in given namespace filtered by relation kind
926 : */
927 : static List *
4927 tgl 928 GBC 30 : getRelationsInNamespace(Oid namespaceId, char relkind)
929 : {
930 30 : List *relations = NIL;
931 : ScanKeyData key[2];
932 : Relation rel;
933 : TableScanDesc scan;
934 : HeapTuple tuple;
4927 tgl 935 ECB :
4927 tgl 936 GIC 30 : ScanKeyInit(&key[0],
937 : Anum_pg_class_relnamespace,
938 : BTEqualStrategyNumber, F_OIDEQ,
939 : ObjectIdGetDatum(namespaceId));
940 30 : ScanKeyInit(&key[1],
941 : Anum_pg_class_relkind,
942 : BTEqualStrategyNumber, F_CHAREQ,
943 : CharGetDatum(relkind));
4927 tgl 944 ECB :
1539 andres 945 GIC 30 : rel = table_open(RelationRelationId, AccessShareLock);
1490 andres 946 CBC 30 : scan = table_beginscan_catalog(rel, 2, key);
947 :
4927 tgl 948 GIC 42 : while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
949 : {
1418 950 12 : Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
951 :
1601 andres 952 CBC 12 : relations = lappend_oid(relations, oid);
953 : }
954 :
1490 andres 955 GIC 30 : table_endscan(scan);
1539 andres 956 CBC 30 : table_close(rel, AccessShareLock);
957 :
4927 tgl 958 GIC 30 : return relations;
959 : }
960 :
4927 tgl 961 ECB :
4934 962 : /*
963 : * ALTER DEFAULT PRIVILEGES statement
964 : */
965 : void
2406 peter_e 966 CBC 80 : ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
967 : {
4934 tgl 968 80 : GrantStmt *action = stmt->action;
969 : InternalDefaultACL iacls;
970 : ListCell *cell;
2953 alvherre 971 80 : List *rolespecs = NIL;
4934 tgl 972 80 : List *nspnames = NIL;
2953 alvherre 973 GIC 80 : DefElem *drolespecs = NULL;
4934 tgl 974 CBC 80 : DefElem *dnspnames = NULL;
975 : AclMode all_privileges;
976 : const char *errormsg;
977 :
978 : /* Deconstruct the "options" part of the statement */
4934 tgl 979 GIC 141 : foreach(cell, stmt->options)
980 : {
981 61 : DefElem *defel = (DefElem *) lfirst(cell);
4934 tgl 982 ECB :
4934 tgl 983 GIC 61 : if (strcmp(defel->defname, "schemas") == 0)
4934 tgl 984 ECB : {
4934 tgl 985 GIC 27 : if (dnspnames)
633 dean.a.rasheed 986 UIC 0 : errorConflictingDefElem(defel, pstate);
4934 tgl 987 CBC 27 : dnspnames = defel;
4934 tgl 988 ECB : }
4934 tgl 989 CBC 34 : else if (strcmp(defel->defname, "roles") == 0)
4934 tgl 990 ECB : {
2953 alvherre 991 GIC 34 : if (drolespecs)
633 dean.a.rasheed 992 UIC 0 : errorConflictingDefElem(defel, pstate);
2953 alvherre 993 GIC 34 : drolespecs = defel;
994 : }
4934 tgl 995 ECB : else
4934 tgl 996 UIC 0 : elog(ERROR, "option \"%s\" not recognized", defel->defname);
4934 tgl 997 ECB : }
998 :
4934 tgl 999 CBC 80 : if (dnspnames)
4934 tgl 1000 GIC 27 : nspnames = (List *) dnspnames->arg;
2953 alvherre 1001 CBC 80 : if (drolespecs)
2953 alvherre 1002 GBC 34 : rolespecs = (List *) drolespecs->arg;
4934 tgl 1003 ECB :
1004 : /* Prepare the InternalDefaultACL representation of the statement */
1005 : /* roleid to be filled below */
1006 : /* nspid to be filled in SetDefaultACLsInSchemas */
4934 tgl 1007 CBC 80 : iacls.is_grant = action->is_grant;
4934 tgl 1008 GBC 80 : iacls.objtype = action->objtype;
4934 tgl 1009 ECB : /* all_privs to be filled below */
1010 : /* privileges to be filled below */
4934 tgl 1011 GIC 80 : iacls.grantees = NIL; /* filled below */
4934 tgl 1012 GBC 80 : iacls.grant_option = action->grant_option;
4934 tgl 1013 GIC 80 : iacls.behavior = action->behavior;
1014 :
4934 tgl 1015 ECB : /*
2878 bruce 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
2953 alvherre 1018 : * there shouldn't be any additional work needed to support this case.
1019 : */
4934 tgl 1020 GIC 163 : foreach(cell, action->grantees)
1021 : {
2878 bruce 1022 83 : RoleSpec *grantee = (RoleSpec *) lfirst(cell);
2878 bruce 1023 ECB : Oid grantee_uid;
4934 tgl 1024 :
2953 alvherre 1025 GIC 83 : switch (grantee->roletype)
1026 : {
2953 alvherre 1027 CBC 20 : case ROLESPEC_PUBLIC:
1028 20 : grantee_uid = ACL_ID_PUBLIC;
1029 20 : break;
2953 alvherre 1030 GIC 63 : default:
2293 peter_e 1031 63 : grantee_uid = get_rolespec_oid(grantee, false);
2953 alvherre 1032 63 : break;
1033 : }
1034 83 : iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
1035 : }
4934 tgl 1036 ECB :
1037 : /*
4790 bruce 1038 : * Convert action->privileges, a list of privilege strings, into an
1039 : * AclMode bitmask.
1040 : */
4934 tgl 1041 CBC 80 : switch (action->objtype)
1042 : {
2006 peter_e 1043 39 : case OBJECT_TABLE:
4934 tgl 1044 39 : all_privileges = ACL_ALL_RIGHTS_RELATION;
1045 39 : errormsg = gettext_noop("invalid privilege type %s for relation");
1046 39 : break;
2006 peter_e 1047 3 : case OBJECT_SEQUENCE:
4934 tgl 1048 3 : all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
4934 tgl 1049 GIC 3 : errormsg = gettext_noop("invalid privilege type %s for sequence");
4934 tgl 1050 CBC 3 : break;
2006 peter_e 1051 GIC 11 : case OBJECT_FUNCTION:
4934 tgl 1052 11 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1053 11 : errormsg = gettext_noop("invalid privilege type %s for function");
1054 11 : break;
2006 peter_e 1055 UIC 0 : case OBJECT_PROCEDURE:
1956 1056 0 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1956 peter_e 1057 LBC 0 : errormsg = gettext_noop("invalid privilege type %s for procedure");
1956 peter_e 1058 UIC 0 : break;
2006 peter_e 1059 LBC 0 : case OBJECT_ROUTINE:
1956 1060 0 : all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1061 0 : errormsg = gettext_noop("invalid privilege type %s for routine");
1062 0 : break;
2006 peter_e 1063 CBC 9 : case OBJECT_TYPE:
4128 1064 9 : all_privileges = ACL_ALL_RIGHTS_TYPE;
1065 9 : errormsg = gettext_noop("invalid privilege type %s for type");
1066 9 : break;
2006 1067 18 : case OBJECT_SCHEMA:
1068 18 : all_privileges = ACL_ALL_RIGHTS_SCHEMA;
2203 teodor 1069 18 : errormsg = gettext_noop("invalid privilege type %s for schema");
1070 18 : break;
4934 tgl 1071 UBC 0 : default:
1072 0 : elog(ERROR, "unrecognized GrantStmt.objtype: %d",
4934 tgl 1073 EUB : (int) action->objtype);
1074 : /* keep compiler quiet */
1075 : all_privileges = ACL_NO_RIGHTS;
1076 : errormsg = NULL;
1077 : }
1078 :
4934 tgl 1079 CBC 80 : if (action->privileges == NIL)
4934 tgl 1080 ECB : {
4934 tgl 1081 CBC 28 : iacls.all_privs = true;
4934 tgl 1082 ECB :
1083 : /*
1084 : * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1085 : * depending on the object type
1086 : */
4934 tgl 1087 GBC 28 : iacls.privileges = ACL_NO_RIGHTS;
4934 tgl 1088 EUB : }
1089 : else
1090 : {
4934 tgl 1091 GIC 52 : iacls.all_privs = false;
1092 52 : iacls.privileges = ACL_NO_RIGHTS;
1093 :
1094 104 : foreach(cell, action->privileges)
4934 tgl 1095 ECB : {
4934 tgl 1096 GIC 52 : AccessPriv *privnode = (AccessPriv *) lfirst(cell);
4934 tgl 1097 ECB : AclMode priv;
1098 :
4934 tgl 1099 GIC 52 : if (privnode->cols)
4934 tgl 1100 UIC 0 : ereport(ERROR,
1101 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1102 : errmsg("default privileges cannot be set for columns")));
4934 tgl 1103 ECB :
4934 tgl 1104 GIC 52 : if (privnode->priv_name == NULL) /* parser mistake? */
4934 tgl 1105 UIC 0 : elog(ERROR, "AccessPriv node must specify privilege");
4934 tgl 1106 GIC 52 : priv = string_to_privilege(privnode->priv_name);
4934 tgl 1107 ECB :
4934 tgl 1108 CBC 52 : if (priv & ~((AclMode) all_privileges))
4934 tgl 1109 UIC 0 : ereport(ERROR,
4934 tgl 1110 ECB : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1111 : errmsg(errormsg, privilege_to_string(priv))));
1112 :
4934 tgl 1113 GIC 52 : iacls.privileges |= priv;
1114 : }
4934 tgl 1115 ECB : }
4934 tgl 1116 EUB :
2953 alvherre 1117 GIC 80 : if (rolespecs == NIL)
1118 : {
1119 : /* Set permissions for myself */
4934 tgl 1120 CBC 46 : iacls.roleid = GetUserId();
4934 tgl 1121 EUB :
4934 tgl 1122 CBC 46 : SetDefaultACLsInSchemas(&iacls, nspnames);
1123 : }
4934 tgl 1124 ECB : else
4934 tgl 1125 EUB : {
1126 : /* Look up the role OIDs and do permissions checks */
1127 : ListCell *rolecell;
1128 :
2953 alvherre 1129 CBC 68 : foreach(rolecell, rolespecs)
1130 : {
2953 alvherre 1131 GIC 34 : RoleSpec *rolespec = lfirst(rolecell);
1132 :
2293 peter_e 1133 CBC 34 : iacls.roleid = get_rolespec_oid(rolespec, false);
1134 :
202 rhaas 1135 GNC 34 : if (!has_privs_of_role(GetUserId(), iacls.roleid))
202 rhaas 1136 UNC 0 : ereport(ERROR,
1137 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1138 : errmsg("permission denied to change default privileges")));
1139 :
4934 tgl 1140 GIC 34 : SetDefaultACLsInSchemas(&iacls, nspnames);
1141 : }
4934 tgl 1142 ECB : }
4934 tgl 1143 GIC 77 : }
4934 tgl 1144 ECB :
1145 : /*
1146 : * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1147 : *
1148 : * All fields of *iacls except nspid were filled already
4934 tgl 1149 EUB : */
1150 : static void
4934 tgl 1151 GIC 80 : SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
1152 : {
4934 tgl 1153 CBC 80 : if (nspnames == NIL)
1154 : {
1155 : /* Set database-wide permissions if no schema was specified */
1156 53 : iacls->nspid = InvalidOid;
1157 :
4934 tgl 1158 GIC 53 : SetDefaultACL(iacls);
1159 : }
1160 : else
1161 : {
1162 : /* Look up the schema OIDs and set permissions for each one */
1163 : ListCell *nspcell;
4934 tgl 1164 ECB :
4934 tgl 1165 GIC 54 : foreach(nspcell, nspnames)
4934 tgl 1166 ECB : {
4934 tgl 1167 GIC 30 : char *nspname = strVal(lfirst(nspcell));
1168 :
4630 rhaas 1169 CBC 30 : iacls->nspid = get_namespace_oid(nspname, false);
1170 :
3591 tgl 1171 ECB : /*
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 : */
4934 1182 :
4934 tgl 1183 GIC 30 : SetDefaultACL(iacls);
1184 : }
1185 : }
1186 77 : }
1187 :
1188 :
1189 : /*
1190 : * Create or update a pg_default_acl entry
1191 : */
1192 : static void
1193 98 : SetDefaultACL(InternalDefaultACL *iacls)
1194 : {
1195 98 : AclMode this_privileges = iacls->privileges;
4934 tgl 1196 ECB : 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 :
1539 andres 1209 GIC 98 : 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 : */
4752 tgl 1217 98 : if (!OidIsValid(iacls->nspid))
1218 68 : def_acl = acldefault(iacls->objtype, iacls->roleid);
4752 tgl 1219 ECB : else
4752 tgl 1220 GIC 30 : 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 : */
4934 1226 98 : switch (iacls->objtype)
4934 tgl 1227 ECB : {
2006 peter_e 1228 CBC 45 : case OBJECT_TABLE:
4934 tgl 1229 GIC 45 : objtype = DEFACLOBJ_RELATION;
4934 tgl 1230 CBC 45 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
4934 tgl 1231 GIC 13 : this_privileges = ACL_ALL_RIGHTS_RELATION;
1232 45 : break;
1233 :
2006 peter_e 1234 6 : case OBJECT_SEQUENCE:
4934 tgl 1235 6 : objtype = DEFACLOBJ_SEQUENCE;
4934 tgl 1236 CBC 6 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
4934 tgl 1237 GIC 6 : this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
4934 tgl 1238 CBC 6 : break;
4934 tgl 1239 ECB :
2006 peter_e 1240 CBC 14 : case OBJECT_FUNCTION:
4934 tgl 1241 14 : objtype = DEFACLOBJ_FUNCTION;
1242 14 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
4934 tgl 1243 GIC 6 : this_privileges = ACL_ALL_RIGHTS_FUNCTION;
4934 tgl 1244 CBC 14 : break;
4934 tgl 1245 ECB :
2006 peter_e 1246 CBC 12 : case OBJECT_TYPE:
4128 1247 12 : objtype = DEFACLOBJ_TYPE;
1248 12 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
4128 peter_e 1249 GIC 6 : this_privileges = ACL_ALL_RIGHTS_TYPE;
4128 peter_e 1250 CBC 12 : break;
4128 peter_e 1251 ECB :
2006 peter_e 1252 CBC 21 : case OBJECT_SCHEMA:
2203 teodor 1253 21 : if (OidIsValid(iacls->nspid))
1254 3 : ereport(ERROR,
1255 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2203 teodor 1256 ECB : errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
2203 teodor 1257 CBC 18 : objtype = DEFACLOBJ_NAMESPACE;
1258 18 : if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
2006 peter_e 1259 12 : this_privileges = ACL_ALL_RIGHTS_SCHEMA;
2203 teodor 1260 18 : break;
1261 :
4934 tgl 1262 LBC 0 : default:
152 peter 1263 UNC 0 : elog(ERROR, "unrecognized object type: %d",
4934 tgl 1264 ECB : (int) iacls->objtype);
1265 : objtype = 0; /* keep compiler quiet */
1266 : break;
1267 : }
1268 :
1269 : /* Search for existing row for this object type in catalog */
4802 rhaas 1270 CBC 95 : tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1271 : ObjectIdGetDatum(iacls->roleid),
4802 rhaas 1272 EUB : ObjectIdGetDatum(iacls->nspid),
4790 bruce 1273 : CharGetDatum(objtype));
1274 :
4934 tgl 1275 GIC 95 : if (HeapTupleIsValid(tuple))
1276 : {
1277 : Datum aclDatum;
1278 : bool isNull;
1279 :
4934 tgl 1280 CBC 36 : aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1281 : Anum_pg_default_acl_defaclacl,
1282 : &isNull);
4934 tgl 1283 GIC 36 : if (!isNull)
1284 36 : old_acl = DatumGetAclPCopy(aclDatum);
4934 tgl 1285 ECB : else
4752 tgl 1286 UIC 0 : old_acl = NULL; /* this case shouldn't happen, probably */
4934 tgl 1287 GIC 36 : isNew = false;
1288 : }
1289 : else
4934 tgl 1290 ECB : {
4934 tgl 1291 GIC 59 : old_acl = NULL;
1292 59 : isNew = true;
4934 tgl 1293 ECB : }
1294 :
4752 tgl 1295 GIC 95 : if (old_acl != NULL)
4752 tgl 1296 EUB : {
4752 tgl 1297 ECB : /*
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 : */
4752 tgl 1302 CBC 36 : noldmembers = aclmembers(old_acl, &oldmembers);
1303 : }
1304 : else
4934 tgl 1305 ECB : {
1306 : /* If no or null entry, start with the default ACL value */
4752 tgl 1307 GIC 59 : old_acl = aclcopy(def_acl);
1308 : /* There are no old member roles according to the catalogs */
1309 59 : noldmembers = 0;
1310 59 : oldmembers = NULL;
1311 : }
4934 tgl 1312 ECB :
1313 : /*
1314 : * Generate new ACL. Grantor of rights is always the same as the target
1315 : * role.
1316 : */
4934 tgl 1317 CBC 95 : new_acl = merge_acl_with_grant(old_acl,
4934 tgl 1318 GIC 95 : iacls->is_grant,
4934 tgl 1319 CBC 95 : iacls->grant_option,
4934 tgl 1320 ECB : iacls->behavior,
1321 : iacls->grantees,
1322 : this_privileges,
1323 : iacls->roleid,
1324 : iacls->roleid);
1325 :
1326 : /*
4752 1327 : * If the result is the same as the default value, we do not need an
4660 bruce 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 : */
4752 tgl 1331 GIC 95 : aclitemsort(new_acl);
1332 95 : aclitemsort(def_acl);
1333 95 : if (aclequal(new_acl, def_acl))
1334 : {
1335 : /* delete old entry, if indeed there is one */
1336 28 : if (!isNew)
1337 : {
1338 : ObjectAddress myself;
1339 :
1340 : /*
4752 tgl 1341 ECB : * 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 : */
4752 tgl 1345 GIC 27 : myself.classId = DefaultAclRelationId;
1601 andres 1346 CBC 27 : myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
4752 tgl 1347 GIC 27 : myself.objectSubId = 0;
1348 :
4091 rhaas 1349 27 : performDeletion(&myself, DROP_RESTRICT, 0);
1350 : }
1351 : }
1352 : else
1353 : {
267 peter 1354 GNC 67 : Datum values[Natts_pg_default_acl] = {0};
1355 67 : bool nulls[Natts_pg_default_acl] = {0};
1356 67 : bool replaces[Natts_pg_default_acl] = {0};
1357 : Oid defAclOid;
1601 andres 1358 ECB :
4752 tgl 1359 GIC 67 : if (isNew)
1360 : {
1361 : /* insert new entry */
1601 andres 1362 CBC 58 : defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1601 andres 1363 ECB : Anum_pg_default_acl_oid);
1601 andres 1364 CBC 58 : values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
4752 tgl 1365 GIC 58 : values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1366 58 : values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
4752 tgl 1367 CBC 58 : values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
4752 tgl 1368 GIC 58 : values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1369 :
4752 tgl 1370 CBC 58 : newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
2259 alvherre 1371 GIC 58 : CatalogTupleInsert(rel, newtuple);
4752 tgl 1372 ECB : }
1373 : else
1374 : {
1601 andres 1375 CBC 9 : defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1601 andres 1376 ECB :
1377 : /* update existing entry */
4752 tgl 1378 CBC 9 : values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1379 9 : replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1380 :
4752 tgl 1381 GIC 9 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1382 : values, nulls, replaces);
2259 alvherre 1383 CBC 9 : CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1384 : }
1385 :
4752 tgl 1386 ECB : /* these dependencies don't change in an update */
4752 tgl 1387 CBC 67 : if (isNew)
1388 : {
4752 tgl 1389 ECB : /* dependency on role */
1601 andres 1390 GIC 58 : recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
4752 tgl 1391 ECB : iacls->roleid);
1392 :
1393 : /* dependency on namespace */
4752 tgl 1394 GIC 58 : if (OidIsValid(iacls->nspid))
4752 tgl 1395 ECB : {
1396 : ObjectAddress myself,
1397 : referenced;
4934 1398 :
4752 tgl 1399 GIC 17 : myself.classId = DefaultAclRelationId;
1601 andres 1400 17 : myself.objectId = defAclOid;
4752 tgl 1401 17 : myself.objectSubId = 0;
4934 tgl 1402 ECB :
4752 tgl 1403 GIC 17 : referenced.classId = NamespaceRelationId;
1404 17 : referenced.objectId = iacls->nspid;
1405 17 : referenced.objectSubId = 0;
1406 :
4752 tgl 1407 CBC 17 : recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
4752 tgl 1408 ECB : }
1409 : }
1410 :
1411 : /*
1412 : * Update the shared dependency ACL info
1413 : */
4752 tgl 1414 GIC 67 : nnewmembers = aclmembers(new_acl, &newmembers);
4934 tgl 1415 ECB :
4752 tgl 1416 GIC 67 : updateAclDependencies(DefaultAclRelationId,
1417 : defAclOid, 0,
1418 : iacls->roleid,
1419 : noldmembers, oldmembers,
1420 : nnewmembers, newmembers);
1421 :
3675 rhaas 1422 CBC 67 : if (isNew)
1601 andres 1423 GIC 58 : InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
3675 rhaas 1424 ECB : else
1418 tgl 1425 GIC 9 : InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1426 : }
1427 :
4934 1428 95 : if (HeapTupleIsValid(tuple))
1429 36 : ReleaseSysCache(tuple);
4934 tgl 1430 ECB :
1539 andres 1431 CBC 95 : table_close(rel, RowExclusiveLock);
1432 :
809 michael 1433 ECB : /* prevent error when processing duplicate objects */
809 michael 1434 GIC 95 : CommandCounterIncrement();
4934 tgl 1435 95 : }
4934 tgl 1436 ECB :
1437 :
1438 : /*
1439 : * RemoveRoleFromObjectACL
1440 : *
1441 : * Used by shdepDropOwned to remove mentions of a role in ACLs
1442 : */
1443 : void
4934 tgl 1444 GIC 105 : RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
1445 : {
1446 105 : if (classid == DefaultAclRelationId)
1447 : {
1448 : InternalDefaultACL iacls;
1449 : Form_pg_default_acl pg_default_acl_tuple;
1450 : Relation rel;
1451 : ScanKeyData skey[1];
4934 tgl 1452 ECB : SysScanDesc scan;
1453 : HeapTuple tuple;
1454 :
1455 : /* first fetch info needed by SetDefaultACL */
1539 andres 1456 GIC 15 : rel = table_open(DefaultAclRelationId, AccessShareLock);
1457 :
4934 tgl 1458 15 : ScanKeyInit(&skey[0],
1459 : Anum_pg_default_acl_oid,
1460 : BTEqualStrategyNumber, F_OIDEQ,
1461 : ObjectIdGetDatum(objid));
1462 :
1463 15 : scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
3568 rhaas 1464 ECB : NULL, 1, skey);
1465 :
4934 tgl 1466 CBC 15 : tuple = systable_getnext(scan);
1467 :
4934 tgl 1468 GIC 15 : if (!HeapTupleIsValid(tuple))
4934 tgl 1469 UIC 0 : elog(ERROR, "could not find tuple for default ACL %u", objid);
1470 :
4934 tgl 1471 CBC 15 : pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1472 :
4934 tgl 1473 GIC 15 : iacls.roleid = pg_default_acl_tuple->defaclrole;
4934 tgl 1474 CBC 15 : iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1475 :
1476 15 : switch (pg_default_acl_tuple->defaclobjtype)
4934 tgl 1477 EUB : {
4934 tgl 1478 GIC 3 : case DEFACLOBJ_RELATION:
2006 peter_e 1479 CBC 3 : iacls.objtype = OBJECT_TABLE;
4934 tgl 1480 GIC 3 : break;
4372 rhaas 1481 CBC 3 : case DEFACLOBJ_SEQUENCE:
2006 peter_e 1482 3 : iacls.objtype = OBJECT_SEQUENCE;
4934 tgl 1483 GIC 3 : break;
4934 tgl 1484 CBC 3 : case DEFACLOBJ_FUNCTION:
2006 peter_e 1485 GIC 3 : iacls.objtype = OBJECT_FUNCTION;
4934 tgl 1486 CBC 3 : break;
3773 1487 3 : case DEFACLOBJ_TYPE:
2006 peter_e 1488 3 : iacls.objtype = OBJECT_TYPE;
3773 tgl 1489 3 : break;
2203 teodor 1490 3 : case DEFACLOBJ_NAMESPACE:
2006 peter_e 1491 3 : iacls.objtype = OBJECT_SCHEMA;
2203 teodor 1492 3 : break;
4934 tgl 1493 LBC 0 : default:
4934 tgl 1494 ECB : /* Shouldn't get here */
3773 tgl 1495 LBC 0 : elog(ERROR, "unexpected default ACL type: %d",
3773 tgl 1496 ECB : (int) pg_default_acl_tuple->defaclobjtype);
4934 1497 : break;
1498 : }
1499 :
4934 tgl 1500 CBC 15 : systable_endscan(scan);
1539 andres 1501 GBC 15 : table_close(rel, AccessShareLock);
1502 :
4934 tgl 1503 15 : iacls.is_grant = false;
4934 tgl 1504 GIC 15 : iacls.all_privs = true;
1505 15 : iacls.privileges = ACL_NO_RIGHTS;
1506 15 : iacls.grantees = list_make1_oid(roleid);
1507 15 : iacls.grant_option = false;
4934 tgl 1508 CBC 15 : iacls.behavior = DROP_CASCADE;
4934 tgl 1509 ECB :
1510 : /* Do it */
4934 tgl 1511 CBC 15 : SetDefaultACL(&iacls);
4934 tgl 1512 ECB : }
1513 : else
1514 : {
1515 : InternalGrant istmt;
1516 :
4934 tgl 1517 GIC 90 : switch (classid)
1518 : {
4934 tgl 1519 CBC 38 : case RelationRelationId:
1520 : /* it's OK to use TABLE for a sequence */
2006 peter_e 1521 GIC 38 : istmt.objtype = OBJECT_TABLE;
4934 tgl 1522 38 : break;
1523 4 : case DatabaseRelationId:
2006 peter_e 1524 4 : istmt.objtype = OBJECT_DATABASE;
4934 tgl 1525 CBC 4 : break;
4128 peter_e 1526 UIC 0 : case TypeRelationId:
2006 peter_e 1527 LBC 0 : istmt.objtype = OBJECT_TYPE;
4128 peter_e 1528 UIC 0 : break;
4934 tgl 1529 CBC 14 : case ProcedureRelationId:
2006 peter_e 1530 14 : istmt.objtype = OBJECT_ROUTINE;
4934 tgl 1531 14 : break;
4934 tgl 1532 LBC 0 : case LanguageRelationId:
2006 peter_e 1533 0 : istmt.objtype = OBJECT_LANGUAGE;
4934 tgl 1534 UBC 0 : break;
4867 itagaki.takahiro 1535 GBC 9 : case LargeObjectRelationId:
2006 peter_e 1536 9 : istmt.objtype = OBJECT_LARGEOBJECT;
4867 itagaki.takahiro 1537 CBC 9 : break;
4934 tgl 1538 6 : case NamespaceRelationId:
2006 peter_e 1539 6 : istmt.objtype = OBJECT_SCHEMA;
4934 tgl 1540 GBC 6 : break;
4934 tgl 1541 UBC 0 : case TableSpaceRelationId:
2006 peter_e 1542 0 : istmt.objtype = OBJECT_TABLESPACE;
4934 tgl 1543 LBC 0 : break;
4531 heikki.linnakangas 1544 CBC 6 : case ForeignServerRelationId:
2006 peter_e 1545 6 : istmt.objtype = OBJECT_FOREIGN_SERVER;
4531 heikki.linnakangas 1546 6 : break;
1547 1 : case ForeignDataWrapperRelationId:
2006 peter_e 1548 1 : istmt.objtype = OBJECT_FDW;
4531 heikki.linnakangas 1549 GBC 1 : break;
368 tgl 1550 12 : case ParameterAclRelationId:
1551 12 : istmt.objtype = OBJECT_PARAMETER_ACL;
368 tgl 1552 CBC 12 : break;
4934 tgl 1553 LBC 0 : default:
1554 0 : elog(ERROR, "unexpected object class %u", classid);
4934 tgl 1555 ECB : break;
1556 : }
4934 tgl 1557 CBC 90 : istmt.is_grant = false;
1558 90 : istmt.objects = list_make1_oid(objid);
1559 90 : istmt.all_privs = true;
1560 90 : istmt.privileges = ACL_NO_RIGHTS;
4934 tgl 1561 GBC 90 : istmt.col_privs = NIL;
1562 90 : istmt.grantees = list_make1_oid(roleid);
4934 tgl 1563 GIC 90 : istmt.grant_option = false;
1564 90 : istmt.behavior = DROP_CASCADE;
4934 tgl 1565 ECB :
4934 tgl 1566 CBC 90 : ExecGrantStmt_oids(&istmt);
4934 tgl 1567 ECB : }
4934 tgl 1568 CBC 105 : }
4934 tgl 1569 ECB :
1570 :
5190 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
5190 tgl 1579 GIC 469 : 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 5620 : foreach(cell, colnames)
5190 tgl 1587 ECB : {
5190 tgl 1588 GIC 5151 : char *colname = strVal(lfirst(cell));
1589 : AttrNumber attnum;
1590 :
1591 5151 : attnum = get_attnum(table_oid, colname);
1592 5151 : if (attnum == InvalidAttrNumber)
5190 tgl 1593 UIC 0 : ereport(ERROR,
5190 tgl 1594 ECB : (errcode(ERRCODE_UNDEFINED_COLUMN),
1595 : errmsg("column \"%s\" of relation \"%s\" does not exist",
1596 : colname, get_rel_name(table_oid))));
5190 tgl 1597 GIC 5151 : attnum -= FirstLowInvalidHeapAttributeNumber;
1598 5151 : if (attnum <= 0 || attnum >= num_col_privileges)
5050 bruce 1599 LBC 0 : elog(ERROR, "column number out of range"); /* safety check */
5190 tgl 1600 CBC 5151 : col_privileges[attnum] |= this_privileges;
5190 tgl 1601 EUB : }
5190 tgl 1602 GIC 469 : }
1603 :
1604 : /*
5190 tgl 1605 ECB : * expand_all_col_privileges
1606 : *
5190 tgl 1607 EUB : * OR the specified privilege(s) into per-column array entries for each valid
5190 tgl 1608 ECB : * attribute of a relation. The per-column array is indexed starting at
1609 : * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1610 : */
1611 : static void
5190 tgl 1612 GIC 4456 : 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 4456 : Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
5190 tgl 1620 CBC 4456 : for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
5190 tgl 1621 GIC 74307 : curr_att <= classForm->relnatts;
1622 69851 : curr_att++)
1623 : {
1624 : HeapTuple attTuple;
1625 : bool isdropped;
1626 :
5190 tgl 1627 CBC 69851 : if (curr_att == InvalidAttrNumber)
1628 4456 : continue;
5190 tgl 1629 ECB :
1630 : /* Views don't have any system columns at all */
5190 tgl 1631 GIC 65395 : if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1632 14628 : continue;
1633 :
4802 rhaas 1634 50767 : attTuple = SearchSysCache2(ATTNUM,
4802 rhaas 1635 ECB : ObjectIdGetDatum(table_oid),
1636 : Int16GetDatum(curr_att));
5190 tgl 1637 GIC 50767 : if (!HeapTupleIsValid(attTuple))
5190 tgl 1638 UIC 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
5190 tgl 1639 ECB : curr_att, table_oid);
1640 :
5190 tgl 1641 GIC 50767 : isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
5190 tgl 1642 ECB :
5190 tgl 1643 GIC 50767 : ReleaseSysCache(attTuple);
1644 :
5190 tgl 1645 ECB : /* ignore dropped columns */
5190 tgl 1646 GBC 50767 : if (isdropped)
5190 tgl 1647 GIC 3 : continue;
1648 :
5190 tgl 1649 CBC 50764 : col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1650 : }
1651 4456 : }
1652 :
1653 : /*
5190 tgl 1654 ECB : * This processes attributes, but expects to be called from
1371 michael 1655 : * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1656 : */
5190 tgl 1657 : static void
5190 tgl 1658 GIC 55894 : ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
5190 tgl 1659 ECB : 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;
5050 bruce 1666 : Acl *merged_acl;
1667 : Datum aclDatum;
1668 : bool isNull;
1669 : Oid grantorId;
1670 : AclMode avail_goptions;
1671 : bool need_update;
1672 : HeapTuple newtuple;
267 peter 1673 GNC 55894 : Datum values[Natts_pg_attribute] = {0};
1674 55894 : bool nulls[Natts_pg_attribute] = {0};
1675 55894 : bool replaces[Natts_pg_attribute] = {0};
1676 : int noldmembers;
1677 : int nnewmembers;
1678 : Oid *oldmembers;
1679 : Oid *newmembers;
1680 :
4802 rhaas 1681 CBC 55894 : attr_tuple = SearchSysCache2(ATTNUM,
4802 rhaas 1682 ECB : ObjectIdGetDatum(relOid),
1683 : Int16GetDatum(attnum));
5190 tgl 1684 GIC 55894 : if (!HeapTupleIsValid(attr_tuple))
5190 tgl 1685 UIC 0 : elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1686 : attnum, relOid);
5190 tgl 1687 GIC 55894 : pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1688 :
5190 tgl 1689 ECB : /*
1690 : * Get working copy of existing ACL. If there's no ACL, substitute the
1691 : * proper default.
1692 : */
5190 tgl 1693 GBC 55894 : aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1694 : &isNull);
5190 tgl 1695 CBC 55894 : if (isNull)
1696 : {
2006 peter_e 1697 GIC 55743 : old_acl = acldefault(OBJECT_COLUMN, ownerId);
1698 : /* There are no old member roles according to the catalogs */
4752 tgl 1699 55743 : noldmembers = 0;
1700 55743 : oldmembers = NULL;
4752 tgl 1701 ECB : }
1702 : else
1703 : {
5190 tgl 1704 GIC 151 : old_acl = DatumGetAclPCopy(aclDatum);
4752 tgl 1705 ECB : /* Get the roles mentioned in the existing ACL */
4752 tgl 1706 GIC 151 : noldmembers = aclmembers(old_acl, &oldmembers);
4752 tgl 1707 ECB : }
5190 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
5050 bruce 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.)
5190 tgl 1714 : */
5190 tgl 1715 GIC 55894 : merged_acl = aclconcat(old_rel_acl, old_acl);
1716 :
1717 : /* Determine ID to do the grant as, and available grant options */
1718 55894 : select_best_grantor(GetUserId(), col_privileges,
1719 : merged_acl, ownerId,
1720 : &grantorId, &avail_goptions);
1721 :
1722 55894 : pfree(merged_acl);
5190 tgl 1723 ECB :
1724 : /*
1725 : * Restrict the privileges to what we can actually grant, and emit the
5050 bruce 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 =
5190 tgl 1733 GIC 55894 : 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 55894 : NameStr(pg_attribute_tuple->attname));
1739 :
1740 : /*
5190 tgl 1741 ECB : * Generate new ACL.
1742 : */
5190 tgl 1743 GIC 55894 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1744 55894 : istmt->grant_option,
1745 : istmt->behavior, istmt->grantees,
5190 tgl 1746 ECB : col_privileges, grantorId,
1747 : ownerId);
1748 :
1749 : /*
1750 : * We need the members of both old and new ACLs so we can correct the
4752 1751 : * shared dependency information.
1752 : */
5190 tgl 1753 GIC 55894 : nnewmembers = aclmembers(new_acl, &newmembers);
1754 :
1755 : /* finished building new ACL value, now insert it */
1756 :
1757 : /*
5050 bruce 1758 ECB : * 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 : */
5190 tgl 1764 GIC 55894 : if (ACL_NUM(new_acl) > 0)
1765 : {
1766 5162 : values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1767 5162 : need_update = true;
1768 : }
5190 tgl 1769 ECB : else
1770 : {
5190 tgl 1771 CBC 50732 : nulls[Anum_pg_attribute_attacl - 1] = true;
1772 50732 : need_update = !isNull;
1773 : }
5190 tgl 1774 GIC 55894 : replaces[Anum_pg_attribute_attacl - 1] = true;
1775 :
5190 tgl 1776 CBC 55894 : if (need_update)
5190 tgl 1777 ECB : {
5190 tgl 1778 GIC 5208 : newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
5190 tgl 1779 ECB : values, nulls, replaces);
1780 :
2259 alvherre 1781 CBC 5208 : CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1782 :
2559 sfrost 1783 ECB : /* Update initial privileges for extensions */
2559 sfrost 1784 GIC 5208 : recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1785 5208 : ACL_NUM(new_acl) > 0 ? new_acl : NULL);
2559 sfrost 1786 ECB :
1787 : /* Update the shared dependency ACL info */
5190 tgl 1788 GIC 5208 : updateAclDependencies(RelationRelationId, relOid, attnum,
4752 tgl 1789 ECB : ownerId,
5190 1790 : noldmembers, oldmembers,
1791 : nnewmembers, newmembers);
1792 : }
1793 :
5190 tgl 1794 GIC 55894 : pfree(new_acl);
1795 :
1796 55894 : ReleaseSysCache(attr_tuple);
1797 55894 : }
1798 :
6287 bruce 1799 ECB : /*
1800 : * This processes both sequences and non-sequences.
1801 : */
6348 alvherre 1802 : static void
6338 alvherre 1803 GIC 25114 : ExecGrant_Relation(InternalGrant *istmt)
1804 : {
1805 : Relation relation;
1806 : Relation attRelation;
1807 : ListCell *cell;
6348 alvherre 1808 ECB :
1539 andres 1809 GIC 25114 : relation = table_open(RelationRelationId, RowExclusiveLock);
1810 25114 : attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1811 :
6338 alvherre 1812 50258 : foreach(cell, istmt->objects)
1813 : {
6348 alvherre 1814 CBC 25147 : Oid relOid = lfirst_oid(cell);
7974 peter_e 1815 ECB : Datum aclDatum;
1816 : Form_pg_class pg_class_tuple;
1817 : bool isNull;
1818 : AclMode this_privileges;
5050 bruce 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 :
4802 rhaas 1830 GIC 25147 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
7974 peter_e 1831 25147 : if (!HeapTupleIsValid(tuple))
7202 tgl 1832 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", relOid);
7974 peter_e 1833 GIC 25147 : pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1834 :
7202 tgl 1835 ECB : /* Not sensible to grant on an index */
1906 alvherre 1836 CBC 25147 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
1906 alvherre 1837 GBC 25147 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
7202 tgl 1838 LBC 0 : ereport(ERROR,
1839 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1840 : errmsg("\"%s\" is an index",
6348 alvherre 1841 ECB : NameStr(pg_class_tuple->relname))));
7974 peter_e 1842 :
6886 tgl 1843 EUB : /* Composite types aren't tables either */
6886 tgl 1844 GIC 25147 : if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
6886 tgl 1845 UIC 0 : ereport(ERROR,
1846 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1847 : errmsg("\"%s\" is a composite type",
1848 : NameStr(pg_class_tuple->relname))));
6347 bruce 1849 ECB :
6287 bruce 1850 EUB : /* Used GRANT SEQUENCE on a non-sequence? */
2006 peter_e 1851 GIC 25147 : if (istmt->objtype == OBJECT_SEQUENCE &&
6287 bruce 1852 6 : pg_class_tuple->relkind != RELKIND_SEQUENCE)
6287 bruce 1853 UIC 0 : ereport(ERROR,
1854 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1855 : errmsg("\"%s\" is not a sequence",
6287 bruce 1856 ECB : NameStr(pg_class_tuple->relname))));
1857 :
4481 rhaas 1858 EUB : /* Adjust the default permissions based on object type */
6287 bruce 1859 GIC 25147 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1860 : {
1861 4483 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1862 35 : this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1863 : else
6287 bruce 1864 CBC 4448 : this_privileges = ACL_ALL_RIGHTS_RELATION;
1865 : }
6287 bruce 1866 ECB : else
6287 bruce 1867 CBC 20664 : this_privileges = istmt->privileges;
1868 :
6287 bruce 1869 ECB : /*
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
6031 1872 : * permissions. The OR of table and sequence permissions were already
1873 : * checked.
1874 : */
2006 peter_e 1875 GIC 25147 : if (istmt->objtype == OBJECT_TABLE)
1876 : {
6287 bruce 1877 25141 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1878 : {
1879 : /*
5190 tgl 1880 ECB : * For backward compatibility, just throw a warning for
1881 : * invalid sequence permissions when using the non-sequence
1882 : * GRANT syntax.
1883 : */
6287 bruce 1884 GIC 70 : 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
6031 bruce 1889 ECB : * WARNING allows the command to continue.
1890 : */
6287 bruce 1891 UIC 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;
6287 bruce 1896 EUB : }
1897 : }
1898 : else
1899 : {
6287 bruce 1900 GBC 25071 : 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
6031 bruce 1905 ECB : * because we didn't in the combined TABLE | SEQUENCE
1906 : * check.
1907 : */
6287 bruce 1908 UIC 0 : ereport(ERROR,
1909 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1910 : errmsg("invalid privilege type %s for table",
1911 : "USAGE")));
1912 : }
6287 bruce 1913 EUB : }
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 : */
5190 tgl 1921 GIC 25147 : num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1922 25147 : col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1923 25147 : have_col_privileges = false;
1924 :
1925 : /*
5190 tgl 1926 ECB : * 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 : */
5190 tgl 1932 GIC 25147 : if (!istmt->is_grant &&
1933 4484 : (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1934 : {
1935 4456 : expand_all_col_privileges(relOid, pg_class_tuple,
1936 : this_privileges & ACL_ALL_RIGHTS_COLUMN,
5190 tgl 1937 ECB : col_privileges,
1938 : num_col_privileges);
5190 tgl 1939 GIC 4456 : have_col_privileges = true;
5190 tgl 1940 ECB : }
1941 :
1942 : /*
1943 : * Get owner ID and working copy of existing ACL. If there's no ACL,
6385 bruce 1944 : * substitute the proper default.
1945 : */
6886 tgl 1946 GIC 25147 : ownerId = pg_class_tuple->relowner;
6390 1947 25147 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1948 : &isNull);
1949 25147 : if (isNull)
1950 : {
4481 rhaas 1951 CBC 23554 : switch (pg_class_tuple->relkind)
4481 rhaas 1952 ECB : {
4481 rhaas 1953 GIC 40 : case RELKIND_SEQUENCE:
2006 peter_e 1954 CBC 40 : old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
4481 rhaas 1955 GIC 40 : break;
4481 rhaas 1956 CBC 23514 : default:
2006 peter_e 1957 GIC 23514 : old_acl = acldefault(OBJECT_TABLE, ownerId);
4481 rhaas 1958 CBC 23514 : break;
4481 rhaas 1959 ECB : }
4752 tgl 1960 : /* There are no old member roles according to the catalogs */
4752 tgl 1961 CBC 23554 : noldmembers = 0;
1962 23554 : oldmembers = NULL;
4752 tgl 1963 ECB : }
1964 : else
1965 : {
6390 tgl 1966 CBC 1593 : old_acl = DatumGetAclPCopy(aclDatum);
4752 tgl 1967 ECB : /* Get the roles mentioned in the existing ACL */
4752 tgl 1968 GIC 1593 : noldmembers = aclmembers(old_acl, &oldmembers);
1969 : }
1970 :
5190 tgl 1971 ECB : /* Need an extra copy of original rel ACL for column handling */
5190 tgl 1972 GIC 25147 : old_rel_acl = aclcopy(old_acl);
6886 tgl 1973 ECB :
1974 : /*
1975 : * Handle relation-level privileges, if any were specified
1976 : */
5190 tgl 1977 CBC 25147 : if (this_privileges != ACL_NO_RIGHTS)
1978 : {
1979 : AclMode avail_goptions;
1980 : Acl *new_acl;
1981 : Oid grantorId;
5190 tgl 1982 ECB : HeapTuple newtuple;
267 peter 1983 GNC 24684 : Datum values[Natts_pg_class] = {0};
1984 24684 : bool nulls[Natts_pg_class] = {0};
1985 24684 : bool replaces[Natts_pg_class] = {0};
1986 : int nnewmembers;
1987 : Oid *newmembers;
1954 peter_e 1988 ECB : ObjectType objtype;
5190 tgl 1989 :
1990 : /* Determine ID to do the grant as, and available grant options */
5190 tgl 1991 GIC 24684 : select_best_grantor(GetUserId(), this_privileges,
1992 : old_acl, ownerId,
1993 : &grantorId, &avail_goptions);
1994 :
4481 rhaas 1995 24684 : switch (pg_class_tuple->relkind)
4481 rhaas 1996 ECB : {
4481 rhaas 1997 GIC 76 : case RELKIND_SEQUENCE:
1954 peter_e 1998 76 : objtype = OBJECT_SEQUENCE;
4481 rhaas 1999 76 : break;
4481 rhaas 2000 CBC 24608 : default:
1954 peter_e 2001 GIC 24608 : objtype = OBJECT_TABLE;
4481 rhaas 2002 CBC 24608 : break;
4481 rhaas 2003 ECB : }
2004 :
5190 tgl 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 =
5190 tgl 2010 GIC 24684 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
2011 24684 : istmt->all_privs, this_privileges,
2012 : relOid, grantorId, objtype,
2013 24684 : NameStr(pg_class_tuple->relname),
2014 : 0, NULL);
5190 tgl 2015 ECB :
2016 : /*
2017 : * Generate new ACL.
2018 : */
5190 tgl 2019 GIC 24684 : new_acl = merge_acl_with_grant(old_acl,
2020 24684 : istmt->is_grant,
2021 24684 : istmt->grant_option,
2022 : istmt->behavior,
2023 : istmt->grantees,
5190 tgl 2024 ECB : 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 : */
5190 tgl 2032 GIC 24681 : nnewmembers = aclmembers(new_acl, &newmembers);
2033 :
2034 : /* finished building new ACL value, now insert it */
2035 24681 : replaces[Anum_pg_class_relacl - 1] = true;
5190 tgl 2036 CBC 24681 : values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
5190 tgl 2037 ECB :
5190 tgl 2038 GIC 24681 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
5190 tgl 2039 ECB : values, nulls, replaces);
2040 :
2259 alvherre 2041 GIC 24681 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
5190 tgl 2042 ECB :
2043 : /* Update initial privileges for extensions */
2559 sfrost 2044 GIC 24681 : recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
2559 sfrost 2045 ECB :
2046 : /* Update the shared dependency ACL info */
5190 tgl 2047 GIC 24681 : updateAclDependencies(RelationRelationId, relOid, 0,
4752 tgl 2048 ECB : ownerId,
2049 : noldmembers, oldmembers,
2050 : nnewmembers, newmembers);
2051 :
5190 tgl 2052 GIC 24681 : pfree(new_acl);
5190 tgl 2053 ECB : }
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 : */
5190 tgl 2060 GIC 25613 : foreach(cell_colprivs, istmt->col_privs)
5190 tgl 2061 ECB : {
5050 bruce 2062 GIC 469 : AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
6485 tgl 2063 ECB :
5190 tgl 2064 GIC 469 : if (col_privs->priv_name == NULL)
5190 tgl 2065 CBC 9 : this_privileges = ACL_ALL_RIGHTS_COLUMN;
5190 tgl 2066 ECB : else
5190 tgl 2067 GIC 460 : this_privileges = string_to_privilege(col_privs->priv_name);
7974 peter_e 2068 ECB :
5190 tgl 2069 GIC 469 : if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
5190 tgl 2070 LBC 0 : ereport(ERROR,
5190 tgl 2071 EUB : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2072 : errmsg("invalid privilege type %s for column",
2073 : privilege_to_string(this_privileges))));
2074 :
5190 tgl 2075 GIC 469 : if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
5190 tgl 2076 LBC 0 : this_privileges & ~((AclMode) ACL_SELECT))
5190 tgl 2077 EUB : {
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 : */
5190 tgl 2083 UIC 0 : ereport(WARNING,
5190 tgl 2084 EUB : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2085 : errmsg("sequence \"%s\" only supports SELECT column privileges",
2086 : NameStr(pg_class_tuple->relname))));
2087 :
5190 tgl 2088 UIC 0 : this_privileges &= (AclMode) ACL_SELECT;
5190 tgl 2089 EUB : }
2090 :
5190 tgl 2091 GIC 469 : expand_col_privileges(col_privs->cols, relOid,
5190 tgl 2092 ECB : this_privileges,
2093 : col_privileges,
2094 : num_col_privileges);
5190 tgl 2095 GIC 469 : have_col_privileges = true;
5190 tgl 2096 ECB : }
2097 :
5190 tgl 2098 GIC 25144 : if (have_col_privileges)
5190 tgl 2099 ECB : {
2100 : AttrNumber i;
2101 :
5190 tgl 2102 GIC 88733 : for (i = 0; i < num_col_privileges; i++)
5190 tgl 2103 ECB : {
5190 tgl 2104 GIC 83817 : if (col_privileges[i] == ACL_NO_RIGHTS)
5190 tgl 2105 CBC 27923 : continue;
2106 55894 : ExecGrant_Attribute(istmt,
5190 tgl 2107 ECB : relOid,
5190 tgl 2108 GIC 55894 : NameStr(pg_class_tuple->relname),
5190 tgl 2109 CBC 55894 : i + FirstLowInvalidHeapAttributeNumber,
5190 tgl 2110 ECB : ownerId,
5190 tgl 2111 GIC 55894 : col_privileges[i],
5190 tgl 2112 ECB : attRelation,
2113 : old_rel_acl);
2114 : }
2115 : }
2116 :
5190 tgl 2117 GIC 25144 : pfree(old_rel_acl);
5190 tgl 2118 CBC 25144 : pfree(col_privileges);
6485 tgl 2119 ECB :
6485 tgl 2120 GIC 25144 : ReleaseSysCache(tuple);
6485 tgl 2121 ECB :
2122 : /* prevent error when processing duplicate objects */
6449 bruce 2123 GIC 25144 : CommandCounterIncrement();
7974 peter_e 2124 ECB : }
2125 :
1539 andres 2126 GIC 25111 : table_close(attRelation, RowExclusiveLock);
1539 andres 2127 CBC 25111 : table_close(relation, RowExclusiveLock);
9770 scrappy 2128 25111 : }
9770 scrappy 2129 ECB :
2130 : static void
117 peter 2131 GNC 23681 : ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
2132 : void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
7658 tgl 2133 ECB : {
2134 : int cacheid;
2135 : Relation relation;
2136 : ListCell *cell;
2137 :
6338 alvherre 2138 GIC 23681 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
117 peter 2139 GNC 231 : istmt->privileges = default_privs;
2140 :
2141 23681 : cacheid = get_object_catcache_oid(classid);
2142 :
2143 23681 : relation = table_open(classid, RowExclusiveLock);
5224 peter_e 2144 ECB :
5224 peter_e 2145 GIC 47662 : foreach(cell, istmt->objects)
5224 peter_e 2146 ECB : {
117 peter 2147 GNC 24008 : Oid objectid = lfirst_oid(cell);
2148 : Datum aclDatum;
2149 : Datum nameDatum;
5224 peter_e 2150 ECB : 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;
117 peter 2159 GNC 24008 : Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2160 24008 : bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2161 24008 : bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2162 : int noldmembers;
2163 : int nnewmembers;
2164 : Oid *oldmembers;
5224 peter_e 2165 ECB : Oid *newmembers;
2166 :
117 peter 2167 GNC 24008 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
5224 peter_e 2168 GIC 24008 : if (!HeapTupleIsValid(tuple))
117 peter 2169 UNC 0 : elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2170 :
2171 : /*
2172 : * Additional object-type-specific checks
2173 : */
117 peter 2174 GNC 24008 : if (object_check)
2175 74 : object_check(istmt, tuple);
5224 peter_e 2176 ECB :
2177 : /*
5224 peter_e 2178 EUB : * Get owner ID and working copy of existing ACL. If there's no ACL,
2179 : * substitute the proper default.
2180 : */
15 dgustafsson 2181 GNC 23999 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2182 : tuple,
2183 23999 : get_object_attnum_owner(classid)));
117 peter 2184 23999 : aclDatum = SysCacheGetAttr(cacheid,
2185 : tuple,
2186 23999 : get_object_attnum_acl(classid),
2187 : &isNull);
5224 peter_e 2188 CBC 23999 : if (isNull)
2189 : {
117 peter 2190 GNC 20613 : old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2191 : /* There are no old member roles according to the catalogs */
4752 tgl 2192 GIC 20613 : noldmembers = 0;
2193 20613 : oldmembers = NULL;
4752 tgl 2194 ECB : }
2195 : else
2196 : {
5224 peter_e 2197 CBC 3386 : old_acl = DatumGetAclPCopy(aclDatum);
2198 : /* Get the roles mentioned in the existing ACL */
4752 tgl 2199 3386 : noldmembers = aclmembers(old_acl, &oldmembers);
2200 : }
5224 peter_e 2201 ECB :
2202 : /* Determine ID to do the grant as, and available grant options */
5224 peter_e 2203 CBC 23999 : select_best_grantor(GetUserId(), istmt->privileges,
2204 : old_acl, ownerId,
5224 peter_e 2205 ECB : &grantorId, &avail_goptions);
2206 :
15 dgustafsson 2207 GNC 23999 : nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2208 23999 : 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.
5224 peter_e 2213 ECB : */
2214 : this_privileges =
5224 peter_e 2215 CBC 47998 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
5224 peter_e 2216 GIC 23999 : istmt->all_privs, istmt->privileges,
2217 : objectid, grantorId, get_object_type(classid, objectid),
117 peter 2218 GNC 23999 : NameStr(*DatumGetName(nameDatum)),
5190 tgl 2219 ECB : 0, NULL);
2220 :
2221 : /*
2222 : * Generate new ACL.
5224 peter_e 2223 : */
5224 peter_e 2224 CBC 23984 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
5224 peter_e 2225 GIC 23984 : 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
4752 tgl 2231 ECB : * shared dependency information.
2232 : */
5224 peter_e 2233 GIC 23981 : nnewmembers = aclmembers(new_acl, &newmembers);
5224 peter_e 2234 ECB :
2235 : /* finished building new ACL value, now insert it */
117 peter 2236 GNC 23981 : replaces[get_object_attnum_acl(classid) - 1] = true;
2237 23981 : values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2238 :
5224 peter_e 2239 GIC 23981 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2240 : nulls, replaces);
2241 :
2259 alvherre 2242 23981 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2243 :
2244 : /* Update initial privileges for extensions */
117 peter 2245 GNC 23981 : recordExtensionInitPriv(objectid, classid, 0, new_acl);
2246 :
2247 : /* Update the shared dependency ACL info */
2248 23981 : updateAclDependencies(classid,
2249 : objectid, 0,
2250 : ownerId,
2251 : noldmembers, oldmembers,
5224 peter_e 2252 ECB : nnewmembers, newmembers);
2253 :
5224 peter_e 2254 GIC 23981 : ReleaseSysCache(tuple);
5224 peter_e 2255 ECB :
5224 peter_e 2256 GIC 23981 : pfree(new_acl);
2257 :
5224 peter_e 2258 ECB : /* prevent error when processing duplicate objects */
5224 peter_e 2259 GIC 23981 : CommandCounterIncrement();
2260 : }
5224 peter_e 2261 ECB :
1539 andres 2262 GIC 23654 : table_close(relation, RowExclusiveLock);
5224 peter_e 2263 23654 : }
5224 peter_e 2264 ECB :
2265 : static void
117 peter 2266 GNC 21 : ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
2267 : {
2268 : Form_pg_language pg_language_tuple;
5224 peter_e 2269 ECB :
117 peter 2270 GNC 21 : pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2271 :
2272 21 : if (!pg_language_tuple->lanpltrusted)
2273 3 : 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.")));
5224 peter_e 2279 GBC 18 : }
5224 peter_e 2280 EUB :
7720 2281 : static void
117 peter 2282 GBC 37 : ExecGrant_Largeobject(InternalGrant *istmt)
7720 peter_e 2283 EUB : {
6348 alvherre 2284 : Relation relation;
6348 alvherre 2285 ECB : ListCell *cell;
7720 peter_e 2286 :
6338 alvherre 2287 CBC 37 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
117 peter 2288 GBC 22 : istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
7658 tgl 2289 EUB :
117 peter 2290 GBC 37 : relation = table_open(LargeObjectMetadataRelationId,
117 peter 2291 EUB : RowExclusiveLock);
7720 peter_e 2292 :
6338 alvherre 2293 GBC 77 : foreach(cell, istmt->objects)
7720 peter_e 2294 EUB : {
117 peter 2295 GBC 40 : Oid loid = lfirst_oid(cell);
117 peter 2296 EUB : Form_pg_largeobject_metadata form_lo_meta;
117 peter 2297 ECB : char loname[NAMEDATALEN];
7720 peter_e 2298 : Datum aclDatum;
2299 : bool isNull;
6390 tgl 2300 : AclMode avail_goptions;
6886 2301 : AclMode this_privileges;
7720 peter_e 2302 : Acl *old_acl;
7720 peter_e 2303 EUB : Acl *new_acl;
6385 bruce 2304 : Oid grantorId;
2305 : Oid ownerId;
7720 peter_e 2306 : HeapTuple newtuple;
117 peter 2307 GNC 40 : Datum values[Natts_pg_largeobject_metadata] = {0};
2308 40 : bool nulls[Natts_pg_largeobject_metadata] = {0};
2309 40 : bool replaces[Natts_pg_largeobject_metadata] = {0};
6485 tgl 2310 ECB : int noldmembers;
2311 : int nnewmembers;
2312 : Oid *oldmembers;
2313 : Oid *newmembers;
117 peter 2314 : ScanKeyData entry[1];
2315 : SysScanDesc scan;
117 peter 2316 EUB : HeapTuple tuple;
2317 :
2318 : /* There's no syscache for pg_largeobject_metadata */
117 peter 2319 GIC 40 : ScanKeyInit(&entry[0],
2320 : Anum_pg_largeobject_metadata_oid,
2321 : BTEqualStrategyNumber, F_OIDEQ,
2322 : ObjectIdGetDatum(loid));
2323 :
2324 40 : scan = systable_beginscan(relation,
2325 : LargeObjectMetadataOidIndexId, true,
2326 : NULL, 1, entry);
2327 :
2328 40 : tuple = systable_getnext(scan);
7720 peter_e 2329 40 : if (!HeapTupleIsValid(tuple))
117 peter 2330 UIC 0 : elog(ERROR, "could not find tuple for large object %u", loid);
2331 :
117 peter 2332 GIC 40 : form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2333 :
6390 tgl 2334 EUB : /*
2335 : * Get owner ID and working copy of existing ACL. If there's no ACL,
2336 : * substitute the proper default.
6390 tgl 2337 ECB : */
117 peter 2338 GIC 40 : ownerId = form_lo_meta->lomowner;
2339 40 : aclDatum = heap_getattr(tuple,
2340 : Anum_pg_largeobject_metadata_lomacl,
2341 : RelationGetDescr(relation), &isNull);
6390 tgl 2342 CBC 40 : if (isNull)
2343 : {
117 peter 2344 22 : old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2345 : /* There are no old member roles according to the catalogs */
4752 tgl 2346 GIC 22 : noldmembers = 0;
2347 22 : oldmembers = NULL;
4752 tgl 2348 ECB : }
6390 2349 : else
4752 2350 : {
6390 tgl 2351 GBC 18 : old_acl = DatumGetAclPCopy(aclDatum);
4752 tgl 2352 EUB : /* Get the roles mentioned in the existing ACL */
4752 tgl 2353 GBC 18 : noldmembers = aclmembers(old_acl, &oldmembers);
4752 tgl 2354 ECB : }
6390 2355 :
2356 : /* Determine ID to do the grant as, and available grant options */
6338 alvherre 2357 GBC 40 : select_best_grantor(GetUserId(), istmt->privileges,
6390 tgl 2358 EUB : old_acl, ownerId,
2359 : &grantorId, &avail_goptions);
7100 2360 :
6886 2361 : /*
6031 bruce 2362 : * Restrict the privileges to what we can actually grant, and emit the
2363 : * standards-mandated warning and error messages.
6886 tgl 2364 : */
117 peter 2365 GBC 40 : snprintf(loname, sizeof(loname), "large object %u", loid);
6338 alvherre 2366 EUB : this_privileges =
6338 alvherre 2367 GBC 40 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
2368 40 : istmt->all_privs, istmt->privileges,
117 peter 2369 ECB : loid, grantorId, OBJECT_LARGEOBJECT,
2370 : loname, 0, NULL);
7720 peter_e 2371 :
2372 : /*
6390 tgl 2373 : * Generate new ACL.
6485 2374 : */
6338 alvherre 2375 GBC 40 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2376 40 : istmt->grant_option, istmt->behavior,
6338 alvherre 2377 EUB : istmt->grantees, this_privileges,
7100 tgl 2378 ECB : grantorId, ownerId);
7720 peter_e 2379 :
4752 tgl 2380 : /*
2381 : * We need the members of both old and new ACLs so we can correct the
2382 : * shared dependency information.
2383 : */
6485 tgl 2384 CBC 40 : nnewmembers = aclmembers(new_acl, &newmembers);
6485 tgl 2385 ECB :
7720 peter_e 2386 : /* finished building new ACL value, now insert it */
117 peter 2387 GBC 40 : replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
117 peter 2388 EUB : values[Anum_pg_largeobject_metadata_lomacl - 1]
117 peter 2389 CBC 40 : = PointerGetDatum(new_acl);
7658 tgl 2390 ECB :
117 peter 2391 CBC 40 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
117 peter 2392 ECB : values, nulls, replaces);
7720 peter_e 2393 :
2259 alvherre 2394 CBC 40 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
7720 peter_e 2395 ECB :
2559 sfrost 2396 : /* Update initial privileges for extensions */
117 peter 2397 CBC 40 : recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2559 sfrost 2398 ECB :
6485 tgl 2399 : /* Update the shared dependency ACL info */
117 peter 2400 CBC 40 : updateAclDependencies(LargeObjectRelationId,
117 peter 2401 ECB : form_lo_meta->oid, 0,
4752 tgl 2402 : ownerId,
6485 2403 : noldmembers, oldmembers,
6485 tgl 2404 EUB : nnewmembers, newmembers);
2405 :
117 peter 2406 GBC 40 : systable_endscan(scan);
6485 tgl 2407 ECB :
7720 peter_e 2408 CBC 40 : pfree(new_acl);
7720 peter_e 2409 ECB :
6449 bruce 2410 : /* prevent error when processing duplicate objects */
6449 bruce 2411 CBC 40 : CommandCounterIncrement();
7720 peter_e 2412 ECB : }
6348 alvherre 2413 :
1539 andres 2414 CBC 37 : table_close(relation, RowExclusiveLock);
7720 peter_e 2415 37 : }
7720 peter_e 2416 ECB :
2417 : static void
117 peter 2418 GNC 53 : ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
7720 peter_e 2419 ECB : {
2420 : Form_pg_type pg_type_tuple;
117 peter 2421 :
117 peter 2422 GNC 53 : pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
117 peter 2423 ECB :
117 peter 2424 GNC 53 : if (IsTrueArrayType(pg_type_tuple))
2425 3 : 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.")));
117 peter 2429 ECB :
2430 : /* Used GRANT DOMAIN on a non-domain? */
117 peter 2431 GNC 50 : if (istmt->objtype == OBJECT_DOMAIN &&
2432 10 : pg_type_tuple->typtype != TYPTYPE_DOMAIN)
2433 3 : ereport(ERROR,
2434 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2435 : errmsg("\"%s\" is not a domain",
2436 : NameStr(pg_type_tuple->typname))));
4128 peter_e 2437 GIC 47 : }
2438 :
2439 : static void
368 tgl 2440 49 : ExecGrant_Parameter(InternalGrant *istmt)
2441 : {
2442 : Relation relation;
368 tgl 2443 ECB : ListCell *cell;
2444 :
368 tgl 2445 GIC 49 : if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2446 21 : istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
2447 :
2448 49 : relation = table_open(ParameterAclRelationId, RowExclusiveLock);
2449 :
2450 117 : foreach(cell, istmt->objects)
2451 : {
2452 68 : Oid parameterId = lfirst_oid(cell);
2453 : Datum nameDatum;
2454 : const char *parname;
2455 : Datum aclDatum;
2456 : bool isNull;
368 tgl 2457 ECB : AclMode avail_goptions;
2458 : AclMode this_privileges;
2459 : Acl *old_acl;
368 tgl 2460 EUB : 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 :
368 tgl 2469 GIC 68 : tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
2470 68 : if (!HeapTupleIsValid(tuple))
368 tgl 2471 UIC 0 : elog(ERROR, "cache lookup failed for parameter ACL %u",
2472 : parameterId);
368 tgl 2473 ECB :
2474 : /* We'll need the GUC's name */
15 dgustafsson 2475 GNC 68 : nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
2476 : Anum_pg_parameter_acl_parname);
368 tgl 2477 GIC 68 : parname = TextDatumGetCString(nameDatum);
2478 :
2479 : /* Treat all parameters as belonging to the bootstrap superuser. */
2480 68 : ownerId = BOOTSTRAP_SUPERUSERID;
368 tgl 2481 ECB :
2482 : /*
2483 : * Get working copy of existing ACL. If there's no ACL, substitute the
2484 : * proper default.
2485 : */
368 tgl 2486 GIC 68 : aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
2487 : Anum_pg_parameter_acl_paracl,
2488 : &isNull);
2489 :
368 tgl 2490 CBC 68 : if (isNull)
2491 : {
2492 34 : old_acl = acldefault(istmt->objtype, ownerId);
368 tgl 2493 ECB : /* There are no old member roles according to the catalogs */
368 tgl 2494 GIC 34 : noldmembers = 0;
2495 34 : oldmembers = NULL;
2496 : }
2497 : else
2498 : {
368 tgl 2499 CBC 34 : old_acl = DatumGetAclPCopy(aclDatum);
2500 : /* Get the roles mentioned in the existing ACL */
2501 34 : noldmembers = aclmembers(old_acl, &oldmembers);
2502 : }
368 tgl 2503 ECB :
2504 : /* Determine ID to do the grant as, and available grant options */
368 tgl 2505 GIC 68 : select_best_grantor(GetUserId(), istmt->privileges,
368 tgl 2506 ECB : 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 =
368 tgl 2514 GIC 68 : restrict_and_check_grant(istmt->is_grant, avail_goptions,
368 tgl 2515 CBC 68 : istmt->all_privs, istmt->privileges,
2516 : parameterId, grantorId,
2517 : OBJECT_PARAMETER_ACL,
2518 : parname,
2519 : 0, NULL);
368 tgl 2520 ECB :
2521 : /*
2522 : * Generate new ACL.
2523 : */
368 tgl 2524 GIC 68 : new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2525 68 : istmt->grant_option, istmt->behavior,
368 tgl 2526 ECB : 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 : */
368 tgl 2533 GIC 68 : nnewmembers = aclmembers(new_acl, &newmembers);
2534 :
2535 : /*
368 tgl 2536 ECB : * 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 : */
368 tgl 2540 GIC 68 : if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
2541 : {
2542 29 : CatalogTupleDelete(relation, &tuple->t_self);
2543 : }
2544 : else
2545 : {
2546 : /* finished building new ACL value, now insert it */
368 tgl 2547 ECB : HeapTuple newtuple;
267 peter 2548 GNC 39 : Datum values[Natts_pg_parameter_acl] = {0};
2549 39 : bool nulls[Natts_pg_parameter_acl] = {0};
2550 39 : bool replaces[Natts_pg_parameter_acl] = {0};
2551 :
368 tgl 2552 GIC 39 : replaces[Anum_pg_parameter_acl_paracl - 1] = true;
2553 39 : values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
368 tgl 2554 ECB :
368 tgl 2555 CBC 39 : newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
368 tgl 2556 ECB : values, nulls, replaces);
2557 :
368 tgl 2558 GIC 39 : CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
368 tgl 2559 ECB : }
2560 :
2561 : /* Update initial privileges for extensions */
368 tgl 2562 GIC 68 : recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
2563 : new_acl);
2564 :
2565 : /* Update the shared dependency ACL info */
2566 68 : updateAclDependencies(ParameterAclRelationId, parameterId, 0,
368 tgl 2567 ECB : ownerId,
2568 : noldmembers, oldmembers,
2569 : nnewmembers, newmembers);
2570 :
368 tgl 2571 GIC 68 : ReleaseSysCache(tuple);
2572 68 : pfree(new_acl);
2573 :
2574 : /* prevent error when processing duplicate objects */
368 tgl 2575 CBC 68 : CommandCounterIncrement();
368 tgl 2576 ECB : }
2577 :
368 tgl 2578 GIC 49 : table_close(relation, RowExclusiveLock);
368 tgl 2579 CBC 49 : }
368 tgl 2580 ECB :
2581 :
2582 : static AclMode
6494 tgl 2583 CBC 45208 : string_to_privilege(const char *privname)
2584 : {
2585 45208 : if (strcmp(privname, "insert") == 0)
6494 tgl 2586 GIC 111 : return ACL_INSERT;
2587 45097 : if (strcmp(privname, "select") == 0)
6494 tgl 2588 CBC 20424 : return ACL_SELECT;
6494 tgl 2589 GIC 24673 : if (strcmp(privname, "update") == 0)
2590 426 : return ACL_UPDATE;
2591 24247 : if (strcmp(privname, "delete") == 0)
2592 57 : return ACL_DELETE;
5326 2593 24190 : if (strcmp(privname, "truncate") == 0)
2594 17 : return ACL_TRUNCATE;
6494 2595 24173 : if (strcmp(privname, "references") == 0)
6494 tgl 2596 CBC 7 : return ACL_REFERENCES;
6494 tgl 2597 GIC 24166 : if (strcmp(privname, "trigger") == 0)
2598 4 : return ACL_TRIGGER;
6494 tgl 2599 CBC 24162 : if (strcmp(privname, "execute") == 0)
6494 tgl 2600 GIC 22027 : return ACL_EXECUTE;
2601 2135 : if (strcmp(privname, "usage") == 0)
6494 tgl 2602 GBC 821 : return ACL_USAGE;
2603 1314 : if (strcmp(privname, "create") == 0)
6494 tgl 2604 GIC 651 : return ACL_CREATE;
2605 663 : if (strcmp(privname, "temporary") == 0)
2606 607 : return ACL_CREATE_TEMP;
2607 56 : if (strcmp(privname, "temp") == 0)
6494 tgl 2608 LBC 0 : return ACL_CREATE_TEMP;
6188 tgl 2609 GIC 56 : if (strcmp(privname, "connect") == 0)
bruce 2610 3 : return ACL_CONNECT;
368 tgl 2611 CBC 53 : if (strcmp(privname, "set") == 0)
368 tgl 2612 GIC 25 : return ACL_SET;
2613 28 : if (strcmp(privname, "alter system") == 0)
368 tgl 2614 CBC 12 : return ACL_ALTER_SYSTEM;
117 jdavis 2615 GNC 16 : if (strcmp(privname, "maintain") == 0)
2616 16 : return ACL_MAINTAIN;
6060 tgl 2617 LBC 0 : if (strcmp(privname, "rule") == 0)
6060 tgl 2618 UIC 0 : return 0; /* ignore old RULE privileges */
6494 tgl 2619 LBC 0 : ereport(ERROR,
2620 : (errcode(ERRCODE_SYNTAX_ERROR),
2621 : errmsg("unrecognized privilege type \"%s\"", privname)));
6494 tgl 2622 ECB : return 0; /* appease compiler */
2623 : }
2624 :
7658 2625 : static const char *
7658 tgl 2626 GIC 12 : privilege_to_string(AclMode privilege)
2627 : {
2628 12 : switch (privilege)
2629 : {
2630 3 : case ACL_INSERT:
2631 3 : return "INSERT";
7658 tgl 2632 UIC 0 : case ACL_SELECT:
7658 tgl 2633 UBC 0 : return "SELECT";
7658 tgl 2634 UIC 0 : case ACL_UPDATE:
2635 0 : return "UPDATE";
2636 0 : case ACL_DELETE:
2637 0 : return "DELETE";
5326 2638 0 : case ACL_TRUNCATE:
2639 0 : return "TRUNCATE";
7658 2640 0 : case ACL_REFERENCES:
2641 0 : return "REFERENCES";
7658 tgl 2642 UBC 0 : case ACL_TRIGGER:
2643 0 : return "TRIGGER";
7658 tgl 2644 UIC 0 : case ACL_EXECUTE:
2645 0 : return "EXECUTE";
7658 tgl 2646 GBC 9 : case ACL_USAGE:
2647 9 : return "USAGE";
7658 tgl 2648 UBC 0 : case ACL_CREATE:
7658 tgl 2649 UIC 0 : return "CREATE";
2650 0 : case ACL_CREATE_TEMP:
2651 0 : return "TEMP";
6188 bruce 2652 0 : case ACL_CONNECT:
6188 tgl 2653 UBC 0 : return "CONNECT";
368 tgl 2654 UIC 0 : case ACL_SET:
2655 0 : return "SET";
368 tgl 2656 UBC 0 : case ACL_ALTER_SYSTEM:
368 tgl 2657 UIC 0 : return "ALTER SYSTEM";
117 jdavis 2658 UNC 0 : case ACL_MAINTAIN:
2659 0 : return "MAINTAIN";
7658 tgl 2660 UIC 0 : default:
7202 tgl 2661 UBC 0 : elog(ERROR, "unrecognized privilege: %d", (int) privilege);
7658 tgl 2662 EUB : }
2663 : return NULL; /* appease compiler */
2664 : }
2665 :
2666 : /*
7652 2667 : * Standardized reporting of aclcheck permissions failures.
2668 : *
2669 : * Note: we do not double-quote the %s's below, because many callers
7191 2670 : * supply strings that might be already quoted.
2671 : */
2672 : void
1954 peter_e 2673 GBC 1165 : aclcheck_error(AclResult aclerr, ObjectType objtype,
7191 tgl 2674 EUB : const char *objectname)
2675 : {
7202 tgl 2676 GBC 1165 : switch (aclerr)
2677 : {
7652 tgl 2678 UBC 0 : case ACLCHECK_OK:
2679 : /* no error, so return to caller */
7652 tgl 2680 UIC 0 : break;
7652 tgl 2681 GIC 893 : case ACLCHECK_NO_PRIV:
2682 : {
1906 2683 893 : const char *msg = "???";
2684 :
2685 : switch (objtype)
2686 : {
1954 peter_e 2687 3 : case OBJECT_AGGREGATE:
2688 3 : msg = gettext_noop("permission denied for aggregate %s");
2689 3 : break;
1954 peter_e 2690 UIC 0 : case OBJECT_COLLATION:
2691 0 : msg = gettext_noop("permission denied for collation %s");
2692 0 : break;
2693 0 : case OBJECT_COLUMN:
1954 peter_e 2694 LBC 0 : msg = gettext_noop("permission denied for column %s");
1954 peter_e 2695 UIC 0 : break;
2696 0 : case OBJECT_CONVERSION:
2697 0 : msg = gettext_noop("permission denied for conversion %s");
2698 0 : break;
1954 peter_e 2699 GIC 9 : case OBJECT_DATABASE:
2700 9 : msg = gettext_noop("permission denied for database %s");
2701 9 : break;
1954 peter_e 2702 UIC 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:
1954 peter_e 2709 LBC 0 : msg = gettext_noop("permission denied for extension %s");
2710 0 : break;
1954 peter_e 2711 GIC 22 : case OBJECT_FDW:
2712 22 : msg = gettext_noop("permission denied for foreign-data wrapper %s");
2713 22 : break;
2714 10 : case OBJECT_FOREIGN_SERVER:
1954 peter_e 2715 CBC 10 : msg = gettext_noop("permission denied for foreign server %s");
1954 peter_e 2716 GIC 10 : break;
2717 1 : case OBJECT_FOREIGN_TABLE:
1954 peter_e 2718 CBC 1 : msg = gettext_noop("permission denied for foreign table %s");
1954 peter_e 2719 GIC 1 : break;
2720 50 : case OBJECT_FUNCTION:
2721 50 : msg = gettext_noop("permission denied for function %s");
2722 50 : break;
1954 peter_e 2723 LBC 0 : case OBJECT_INDEX:
1954 peter_e 2724 UIC 0 : msg = gettext_noop("permission denied for index %s");
2725 0 : break;
1954 peter_e 2726 GIC 4 : case OBJECT_LANGUAGE:
1954 peter_e 2727 CBC 4 : msg = gettext_noop("permission denied for language %s");
2728 4 : break;
1954 peter_e 2729 UBC 0 : case OBJECT_LARGEOBJECT:
1954 peter_e 2730 UIC 0 : msg = gettext_noop("permission denied for large object %s");
2731 0 : break;
2732 0 : case OBJECT_MATVIEW:
1954 peter_e 2733 LBC 0 : msg = gettext_noop("permission denied for materialized view %s");
1954 peter_e 2734 UIC 0 : break;
1954 peter_e 2735 LBC 0 : case OBJECT_OPCLASS:
1954 peter_e 2736 UIC 0 : msg = gettext_noop("permission denied for operator class %s");
2737 0 : break;
1954 peter_e 2738 LBC 0 : case OBJECT_OPERATOR:
1954 peter_e 2739 UIC 0 : msg = gettext_noop("permission denied for operator %s");
2740 0 : break;
1954 peter_e 2741 LBC 0 : case OBJECT_OPFAMILY:
2742 0 : msg = gettext_noop("permission denied for operator family %s");
1954 peter_e 2743 UIC 0 : break;
368 tgl 2744 0 : case OBJECT_PARAMETER_ACL:
2745 0 : msg = gettext_noop("permission denied for parameter %s");
2746 0 : break;
1954 peter_e 2747 LBC 0 : case OBJECT_POLICY:
1954 peter_e 2748 UIC 0 : msg = gettext_noop("permission denied for policy %s");
2749 0 : break;
1954 peter_e 2750 CBC 6 : case OBJECT_PROCEDURE:
1954 peter_e 2751 GIC 6 : msg = gettext_noop("permission denied for procedure %s");
2752 6 : break;
1954 peter_e 2753 LBC 0 : case OBJECT_PUBLICATION:
2754 0 : msg = gettext_noop("permission denied for publication %s");
1954 peter_e 2755 UIC 0 : break;
1954 peter_e 2756 LBC 0 : case OBJECT_ROUTINE:
1954 peter_e 2757 UIC 0 : msg = gettext_noop("permission denied for routine %s");
1954 peter_e 2758 LBC 0 : break;
1954 peter_e 2759 GIC 7 : case OBJECT_SCHEMA:
1954 peter_e 2760 CBC 7 : msg = gettext_noop("permission denied for schema %s");
1954 peter_e 2761 GIC 7 : break;
1954 peter_e 2762 UIC 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");
1954 peter_e 2767 LBC 0 : break;
1954 peter_e 2768 UIC 0 : case OBJECT_SUBSCRIPTION:
2769 0 : msg = gettext_noop("permission denied for subscription %s");
2770 0 : break;
1954 peter_e 2771 GIC 582 : case OBJECT_TABLE:
2772 582 : msg = gettext_noop("permission denied for table %s");
2773 582 : break;
2774 9 : case OBJECT_TABLESPACE:
2775 9 : msg = gettext_noop("permission denied for tablespace %s");
2776 9 : break;
1954 peter_e 2777 UIC 0 : case OBJECT_TSCONFIGURATION:
1954 peter_e 2778 LBC 0 : msg = gettext_noop("permission denied for text search configuration %s");
2779 0 : break;
1954 peter_e 2780 UIC 0 : case OBJECT_TSDICTIONARY:
2781 0 : msg = gettext_noop("permission denied for text search dictionary %s");
2782 0 : break;
1954 peter_e 2783 GIC 57 : case OBJECT_TYPE:
2784 57 : msg = gettext_noop("permission denied for type %s");
2785 57 : break;
2786 133 : case OBJECT_VIEW:
2787 133 : msg = gettext_noop("permission denied for view %s");
2788 133 : break;
2789 : /* these currently aren't used */
1954 peter_e 2790 UIC 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:
1954 peter_e 2800 ECB : case OBJECT_ROLE:
2801 : case OBJECT_RULE:
2802 : case OBJECT_TABCONSTRAINT:
2803 : case OBJECT_TRANSFORM:
2804 : case OBJECT_TRIGGER:
2805 : case OBJECT_TSPARSER:
1954 peter_e 2806 EUB : case OBJECT_TSTEMPLATE:
2807 : case OBJECT_USER_MAPPING:
152 peter 2808 UNC 0 : elog(ERROR, "unsupported object type: %d", objtype);
2809 : }
2810 :
1954 peter_e 2811 GIC 893 : ereport(ERROR,
1954 peter_e 2812 ECB : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2813 : errmsg(msg, objectname)));
1954 peter_e 2814 EUB : break;
2815 : }
7652 tgl 2816 GIC 272 : case ACLCHECK_NOT_OWNER:
2817 : {
1906 tgl 2818 CBC 272 : const char *msg = "???";
2819 :
1954 peter_e 2820 ECB : switch (objtype)
2821 : {
1954 peter_e 2822 CBC 3 : case OBJECT_AGGREGATE:
1954 peter_e 2823 GIC 3 : msg = gettext_noop("must be owner of aggregate %s");
2824 3 : break;
1954 peter_e 2825 LBC 0 : case OBJECT_COLLATION:
2826 0 : msg = gettext_noop("must be owner of collation %s");
1954 peter_e 2827 UIC 0 : break;
1954 peter_e 2828 GIC 9 : case OBJECT_CONVERSION:
2829 9 : msg = gettext_noop("must be owner of conversion %s");
2830 9 : break;
1954 peter_e 2831 LBC 0 : case OBJECT_DATABASE:
1954 peter_e 2832 UIC 0 : msg = gettext_noop("must be owner of database %s");
2833 0 : break;
1954 peter_e 2834 LBC 0 : case OBJECT_DOMAIN:
1954 peter_e 2835 UIC 0 : msg = gettext_noop("must be owner of domain %s");
2836 0 : break;
1954 peter_e 2837 LBC 0 : case OBJECT_EVENT_TRIGGER:
2838 0 : msg = gettext_noop("must be owner of event trigger %s");
1954 peter_e 2839 UIC 0 : break;
1954 peter_e 2840 LBC 0 : case OBJECT_EXTENSION:
1954 peter_e 2841 UIC 0 : msg = gettext_noop("must be owner of extension %s");
2842 0 : break;
1954 peter_e 2843 GIC 9 : case OBJECT_FDW:
2844 9 : msg = gettext_noop("must be owner of foreign-data wrapper %s");
2845 9 : break;
2846 57 : case OBJECT_FOREIGN_SERVER:
2847 57 : msg = gettext_noop("must be owner of foreign server %s");
1954 peter_e 2848 CBC 57 : break;
1954 peter_e 2849 LBC 0 : case OBJECT_FOREIGN_TABLE:
2850 0 : msg = gettext_noop("must be owner of foreign table %s");
2851 0 : break;
1954 peter_e 2852 CBC 21 : case OBJECT_FUNCTION:
1954 peter_e 2853 GIC 21 : msg = gettext_noop("must be owner of function %s");
2854 21 : break;
2855 18 : case OBJECT_INDEX:
2856 18 : msg = gettext_noop("must be owner of index %s");
2857 18 : break;
2858 6 : case OBJECT_LANGUAGE:
1954 peter_e 2859 CBC 6 : msg = gettext_noop("must be owner of language %s");
1954 peter_e 2860 GIC 6 : break;
1954 peter_e 2861 UIC 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;
1954 peter_e 2867 GIC 9 : case OBJECT_OPCLASS:
2868 9 : msg = gettext_noop("must be owner of operator class %s");
2869 9 : break;
2870 9 : case OBJECT_OPERATOR:
1954 peter_e 2871 CBC 9 : msg = gettext_noop("must be owner of operator %s");
2872 9 : break;
1954 peter_e 2873 GIC 9 : case OBJECT_OPFAMILY:
2874 9 : msg = gettext_noop("must be owner of operator family %s");
2875 9 : break;
2876 3 : case OBJECT_PROCEDURE:
1954 peter_e 2877 CBC 3 : msg = gettext_noop("must be owner of procedure %s");
2878 3 : break;
1954 peter_e 2879 GBC 3 : case OBJECT_PUBLICATION:
1954 peter_e 2880 GIC 3 : msg = gettext_noop("must be owner of publication %s");
2881 3 : break;
1954 peter_e 2882 UIC 0 : case OBJECT_ROUTINE:
1954 peter_e 2883 LBC 0 : msg = gettext_noop("must be owner of routine %s");
1954 peter_e 2884 UIC 0 : break;
1954 peter_e 2885 GIC 3 : case OBJECT_SEQUENCE:
2886 3 : msg = gettext_noop("must be owner of sequence %s");
2887 3 : break;
2888 3 : case OBJECT_SUBSCRIPTION:
1954 peter_e 2889 CBC 3 : msg = gettext_noop("must be owner of subscription %s");
1954 peter_e 2890 GIC 3 : break;
1954 peter_e 2891 CBC 44 : case OBJECT_TABLE:
1954 peter_e 2892 GIC 44 : msg = gettext_noop("must be owner of table %s");
1954 peter_e 2893 CBC 44 : break;
1954 peter_e 2894 GIC 3 : case OBJECT_TYPE:
1954 peter_e 2895 CBC 3 : msg = gettext_noop("must be owner of type %s");
1954 peter_e 2896 GIC 3 : break;
1954 peter_e 2897 CBC 9 : case OBJECT_VIEW:
1954 peter_e 2898 GBC 9 : msg = gettext_noop("must be owner of view %s");
1954 peter_e 2899 CBC 9 : break;
1954 peter_e 2900 GIC 9 : case OBJECT_SCHEMA:
2901 9 : msg = gettext_noop("must be owner of schema %s");
2902 9 : break;
2903 18 : case OBJECT_STATISTIC_EXT:
2904 18 : msg = gettext_noop("must be owner of statistics object %s");
1954 peter_e 2905 CBC 18 : break;
1954 peter_e 2906 UIC 0 : case OBJECT_TABLESPACE:
1954 peter_e 2907 LBC 0 : msg = gettext_noop("must be owner of tablespace %s");
1954 peter_e 2908 UIC 0 : break;
1954 peter_e 2909 CBC 9 : case OBJECT_TSCONFIGURATION:
1954 peter_e 2910 GIC 9 : msg = gettext_noop("must be owner of text search configuration %s");
2911 9 : break;
1954 peter_e 2912 CBC 9 : case OBJECT_TSDICTIONARY:
2913 9 : msg = gettext_noop("must be owner of text search dictionary %s");
1954 peter_e 2914 GIC 9 : break;
2915 :
2916 : /*
2917 : * Special cases: For these, the error message talks
1809 tgl 2918 ECB : * about "relation", because that's where the
2919 : * ownership is attached. See also
2920 : * check_object_ownership().
2921 : */
1954 peter_e 2922 GIC 9 : case OBJECT_COLUMN:
2923 : case OBJECT_POLICY:
1954 peter_e 2924 ECB : case OBJECT_RULE:
2925 : case OBJECT_TABCONSTRAINT:
2926 : case OBJECT_TRIGGER:
1954 peter_e 2927 CBC 9 : msg = gettext_noop("must be owner of relation %s");
1954 peter_e 2928 GIC 9 : break;
1809 tgl 2929 ECB : /* these currently aren't used */
1954 peter_e 2930 UIC 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:
1954 peter_e 2936 ECB : case OBJECT_DEFACL:
2937 : case OBJECT_DOMCONSTRAINT:
368 tgl 2938 : case OBJECT_PARAMETER_ACL:
529 akapila 2939 : case OBJECT_PUBLICATION_NAMESPACE:
2940 : case OBJECT_PUBLICATION_REL:
1954 peter_e 2941 : case OBJECT_ROLE:
2942 : case OBJECT_TRANSFORM:
2943 : case OBJECT_TSPARSER:
2944 : case OBJECT_TSTEMPLATE:
2945 : case OBJECT_USER_MAPPING:
152 peter 2946 UNC 0 : elog(ERROR, "unsupported object type: %d", objtype);
2947 : }
2948 :
1954 peter_e 2949 GIC 272 : ereport(ERROR,
2950 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2951 : errmsg(msg, objectname)));
2952 : break;
2953 : }
7652 tgl 2954 UIC 0 : default:
7202 tgl 2955 LBC 0 : elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2956 : break;
2957 : }
7652 2958 0 : }
2959 :
2960 :
2961 : void
1954 peter_e 2962 UIC 0 : aclcheck_error_col(AclResult aclerr, ObjectType objtype,
2963 : const char *objectname, const char *colname)
2964 : {
5190 tgl 2965 0 : switch (aclerr)
2966 : {
2967 0 : case ACLCHECK_OK:
2968 : /* no error, so return to caller */
5190 tgl 2969 LBC 0 : break;
5190 tgl 2970 UIC 0 : case ACLCHECK_NO_PRIV:
2971 0 : ereport(ERROR,
5190 tgl 2972 ECB : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2973 : errmsg("permission denied for column \"%s\" of relation \"%s\"",
2118 2974 : colname, objectname)));
2975 : break;
5190 tgl 2976 LBC 0 : case ACLCHECK_NOT_OWNER:
2977 : /* relation msg is OK since columns don't have separate owners */
1954 peter_e 2978 UIC 0 : aclcheck_error(aclerr, objtype, objectname);
5190 tgl 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
3950 peter_e 2992 GIC 57 : aclcheck_error_type(AclResult aclerr, Oid typeOid)
2993 : {
3602 bruce 2994 57 : Oid element_type = get_element_type(typeOid);
2995 :
1954 peter_e 2996 57 : aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
3950 peter_e 2997 UIC 0 : }
2998 :
3950 peter_e 2999 ECB :
3000 : /*
3001 : * Relay for the various pg_*_mask routines depending on object kind
3002 : */
3003 : static AclMode
147 peter 3004 GNC 33 : pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
3005 : AclMode mask, AclMaskHow how)
3006 : {
1954 peter_e 3007 GIC 33 : switch (objtype)
3008 : {
1954 peter_e 3009 UIC 0 : case OBJECT_COLUMN:
3010 : return
147 peter 3011 UNC 0 : pg_class_aclmask(object_oid, roleid, mask, how) |
3012 0 : pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
1954 peter_e 3013 CBC 6 : case OBJECT_TABLE:
1954 peter_e 3014 ECB : case OBJECT_SEQUENCE:
147 peter 3015 GNC 6 : return pg_class_aclmask(object_oid, roleid, mask, how);
1954 peter_e 3016 LBC 0 : case OBJECT_DATABASE:
147 peter 3017 UNC 0 : return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
1954 peter_e 3018 LBC 0 : case OBJECT_FUNCTION:
147 peter 3019 UNC 0 : return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
1954 peter_e 3020 CBC 3 : case OBJECT_LANGUAGE:
147 peter 3021 GNC 3 : return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
1954 peter_e 3022 UIC 0 : case OBJECT_LARGEOBJECT:
147 peter 3023 UNC 0 : return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3024 : mask, how, NULL);
368 tgl 3025 UIC 0 : case OBJECT_PARAMETER_ACL:
147 peter 3026 UNC 0 : return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
1954 peter_e 3027 UIC 0 : case OBJECT_SCHEMA:
147 peter 3028 UNC 0 : return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
1954 peter_e 3029 UIC 0 : case OBJECT_STATISTIC_EXT:
2156 tgl 3030 0 : elog(ERROR, "grantable rights not supported for statistics objects");
3031 : /* not reached, but keep compiler quiet */
3032 : return ACL_NO_RIGHTS;
1954 peter_e 3033 LBC 0 : case OBJECT_TABLESPACE:
147 peter 3034 UNC 0 : return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
1954 peter_e 3035 GIC 9 : case OBJECT_FDW:
147 peter 3036 GNC 9 : return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
1954 peter_e 3037 GBC 9 : case OBJECT_FOREIGN_SERVER:
147 peter 3038 GNC 9 : return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
1954 peter_e 3039 UIC 0 : case OBJECT_EVENT_TRIGGER:
3917 rhaas 3040 LBC 0 : elog(ERROR, "grantable rights not supported for event triggers");
3041 : /* not reached, but keep compiler quiet */
3917 rhaas 3042 ECB : return ACL_NO_RIGHTS;
1954 peter_e 3043 CBC 6 : case OBJECT_TYPE:
147 peter 3044 GNC 6 : return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
6338 alvherre 3045 UIC 0 : default:
152 peter 3046 UNC 0 : elog(ERROR, "unrecognized object type: %d",
3047 : (int) objtype);
3048 : /* not reached, but keep compiler quiet */
3049 : return ACL_NO_RIGHTS;
3050 : }
6338 alvherre 3051 ECB : }
6524 tgl 3052 :
3053 :
5190 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 : *
7202 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
5190 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
147 peter 3069 GNC 1975448 : 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 1975448 : switch (classid)
3082 : {
3083 524988 : case NamespaceRelationId:
3084 524988 : return pg_namespace_aclmask(objectid, roleid, mask, how);
3085 620267 : case TypeRelationId:
3086 620267 : return pg_type_aclmask(objectid, roleid, mask, how);
3087 : }
3088 :
3089 : /* Even more special cases */
3090 830193 : Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3091 830193 : Assert(classid != LargeObjectMetadataRelationId); /* should use
3092 : * pg_largeobject_acl* */
3093 :
3094 : /* Superusers bypass all permission checking. */
3095 830193 : if (superuser_arg(roleid))
3096 812942 : return mask;
3097 :
3098 : /*
3099 : * Get the objects's ACL from its catalog
3100 : */
3101 :
3102 17251 : cacheid = get_object_catcache_oid(classid);
3103 :
3104 17251 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3105 17251 : if (!HeapTupleIsValid(tuple))
147 peter 3106 UNC 0 : ereport(ERROR,
3107 : (errcode(ERRCODE_UNDEFINED_DATABASE),
3108 : errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
3109 :
15 dgustafsson 3110 GNC 17251 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3111 : tuple,
3112 17251 : get_object_attnum_owner(classid)));
3113 :
147 peter 3114 17251 : aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3115 : &isNull);
3116 17251 : if (isNull)
3117 : {
3118 : /* No ACL, so build default ACL */
3119 16045 : acl = acldefault(get_object_type(classid, objectid), ownerId);
3120 16045 : aclDatum = (Datum) 0;
3121 : }
3122 : else
3123 : {
3124 : /* detoast ACL if necessary */
3125 1206 : acl = DatumGetAclP(aclDatum);
3126 : }
3127 :
3128 17251 : result = aclmask(acl, roleid, ownerId, mask, how);
3129 :
3130 : /* if we have a detoasted copy, free it */
3131 17251 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3132 17251 : pfree(acl);
3133 :
3134 17251 : ReleaseSysCache(tuple);
3135 :
3136 17251 : return result;
3137 : }
3138 :
3139 : /*
3140 : * Routine for examining a user's privileges for a column
5190 tgl 3141 ECB : *
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
5190 tgl 3148 GIC 90 : pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
3149 : AclMode mask, AclMaskHow how)
3150 : {
739 mail 3151 90 : 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 : *
739 mail 3158 ECB : * 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
739 mail 3162 GIC 2730 : 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;
5190 tgl 3170 ECB : 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 : */
4802 rhaas 3178 GIC 2730 : attTuple = SearchSysCache2(ATTNUM,
3179 : ObjectIdGetDatum(table_oid),
3180 : Int16GetDatum(attnum));
5190 tgl 3181 2730 : if (!HeapTupleIsValid(attTuple))
3182 : {
739 mail 3183 15 : if (is_missing != NULL)
3184 : {
739 mail 3185 ECB : /* return "no privileges" instead of throwing an error */
739 mail 3186 GIC 15 : *is_missing = true;
739 mail 3187 CBC 15 : return 0;
739 mail 3188 ECB : }
3189 : else
739 mail 3190 LBC 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 :
5190 tgl 3196 GIC 2715 : attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
5190 tgl 3197 ECB :
3198 : /* Check dropped columns, too */
5190 tgl 3199 GIC 2715 : if (attributeForm->attisdropped)
739 mail 3200 ECB : {
739 mail 3201 GIC 6 : if (is_missing != NULL)
739 mail 3202 ECB : {
3203 : /* return "no privileges" instead of throwing an error */
739 mail 3204 CBC 6 : *is_missing = true;
739 mail 3205 GIC 6 : ReleaseSysCache(attTuple);
3206 6 : return 0;
3207 : }
3208 : else
739 mail 3209 UIC 0 : ereport(ERROR,
3210 : (errcode(ERRCODE_UNDEFINED_COLUMN),
739 mail 3211 ECB : errmsg("attribute %d of relation with OID %u does not exist",
3212 : attnum, table_oid)));
3213 : }
3214 :
5190 tgl 3215 GIC 2709 : aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3216 : &isNull);
5190 tgl 3217 ECB :
5175 3218 : /*
3219 : * Here we hard-wire knowledge that the default ACL for a column grants no
5050 bruce 3220 : * privileges, so that we can fall out quickly in the very common case
3221 : * where attacl is null.
3222 : */
5190 tgl 3223 GIC 2709 : if (isNull)
3224 : {
5175 tgl 3225 CBC 1481 : ReleaseSysCache(attTuple);
3226 1481 : return 0;
5190 tgl 3227 EUB : }
3228 :
3229 : /*
3230 : * Must get the relation's ownerId from pg_class. Since we already found
5050 bruce 3231 ECB : * 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 : */
4802 rhaas 3237 GIC 1228 : classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
5175 tgl 3238 1228 : if (!HeapTupleIsValid(classTuple))
3239 : {
5175 tgl 3240 UIC 0 : ReleaseSysCache(attTuple);
3241 0 : return 0;
3242 : }
5175 tgl 3243 GIC 1228 : classForm = (Form_pg_class) GETSTRUCT(classTuple);
3244 :
3245 1228 : ownerId = classForm->relowner;
5175 tgl 3246 ECB :
5175 tgl 3247 GIC 1228 : ReleaseSysCache(classTuple);
5175 tgl 3248 ECB :
3249 : /* detoast column's ACL if necessary */
5175 tgl 3250 GIC 1228 : acl = DatumGetAclP(aclDatum);
3251 :
5190 3252 1228 : result = aclmask(acl, roleid, ownerId, mask, how);
5190 tgl 3253 ECB :
3254 : /* if we have a detoasted copy, free it */
5190 tgl 3255 GIC 1228 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3256 1228 : pfree(acl);
5190 tgl 3257 ECB :
5190 tgl 3258 CBC 1228 : ReleaseSysCache(attTuple);
5190 tgl 3259 EUB :
5190 tgl 3260 GIC 1228 : return result;
3261 : }
3262 :
5190 tgl 3263 ECB : /*
3264 : * Exported routine for examining a user's privileges for a table
3265 : */
3266 : AclMode
6494 tgl 3267 CBC 237909 : pg_class_aclmask(Oid table_oid, Oid roleid,
3268 : AclMode mask, AclMaskHow how)
739 mail 3269 ECB : {
739 mail 3270 CBC 237909 : return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3271 : }
3272 :
739 mail 3273 ECB : /*
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
739 mail 3280 GIC 1090166 : 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;
8224 tgl 3288 ECB : Acl *acl;
3289 : Oid ownerId;
9345 bruce 3290 :
3291 : /*
3292 : * Must get the relation's tuple from pg_class
3293 : */
4802 rhaas 3294 CBC 1090166 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
7689 tgl 3295 1090166 : if (!HeapTupleIsValid(tuple))
3296 : {
739 mail 3297 LBC 0 : if (is_missing != NULL)
739 mail 3298 ECB : {
3299 : /* return "no privileges" instead of throwing an error */
739 mail 3300 LBC 0 : *is_missing = true;
3301 0 : return 0;
3302 : }
739 mail 3303 ECB : else
739 mail 3304 UIC 0 : ereport(ERROR,
3305 : (errcode(ERRCODE_UNDEFINED_TABLE),
3306 : errmsg("relation with OID %u does not exist",
739 mail 3307 ECB : table_oid)));
3308 : }
3309 :
7025 tgl 3310 GIC 1090166 : classForm = (Form_pg_class) GETSTRUCT(tuple);
3311 :
3312 : /*
9345 bruce 3313 ECB : * Deny anyone permission to update a system catalog unless
1227 peter 3314 : * pg_authid.rolsuper is set.
3315 : *
6797 bruce 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.
9345 3319 : */
5326 tgl 3320 CBC 1416751 : if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3419 rhaas 3321 GIC 326585 : IsSystemClass(table_oid, classForm) &&
7025 tgl 3322 CBC 5461 : classForm->relkind != RELKIND_VIEW &&
1227 peter 3323 GIC 5461 : !superuser_arg(roleid))
5326 tgl 3324 35 : mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
3325 :
3326 : /*
3327 : * Otherwise, superusers bypass all permission-checking.
3328 : */
6494 3329 1090166 : if (superuser_arg(roleid))
3330 : {
8179 tgl 3331 CBC 1075559 : ReleaseSysCache(tuple);
6907 tgl 3332 GIC 1075559 : return mask;
9345 bruce 3333 ECB : }
3334 :
3335 : /*
8224 tgl 3336 : * Normal case: get the relation's ACL from pg_class
3337 : */
6886 tgl 3338 GIC 14607 : ownerId = classForm->relowner;
3339 :
7689 3340 14607 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
8224 tgl 3341 ECB : &isNull);
8224 tgl 3342 GIC 14607 : if (isNull)
3343 : {
3344 : /* No ACL, so build default ACL */
4481 rhaas 3345 2939 : switch (classForm->relkind)
4481 rhaas 3346 ECB : {
4481 rhaas 3347 GIC 18 : case RELKIND_SEQUENCE:
2006 peter_e 3348 18 : acl = acldefault(OBJECT_SEQUENCE, ownerId);
4481 rhaas 3349 CBC 18 : break;
3350 2921 : default:
2006 peter_e 3351 2921 : acl = acldefault(OBJECT_TABLE, ownerId);
4481 rhaas 3352 GIC 2921 : break;
3353 : }
7978 tgl 3354 CBC 2939 : aclDatum = (Datum) 0;
3355 : }
3356 : else
3357 : {
3358 : /* detoast rel's ACL if necessary */
7978 tgl 3359 GIC 11668 : acl = DatumGetAclP(aclDatum);
3360 : }
3361 :
6494 3362 14607 : result = aclmask(acl, roleid, ownerId, mask, how);
3363 :
3364 : /* if we have a detoasted copy, free it */
7978 3365 14607 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
9345 bruce 3366 CBC 14607 : pfree(acl);
3367 :
8179 tgl 3368 GIC 14607 : 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 : */
734 sfrost 3375 15555 : if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
729 noah 3376 948 : has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
734 sfrost 3377 6 : result |= ACL_SELECT;
734 sfrost 3378 ECB :
734 sfrost 3379 EUB : /*
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
697 tgl 3382 ECB : * 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).
734 sfrost 3385 : */
734 sfrost 3386 CBC 14607 : if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
697 tgl 3387 GIC 2991 : !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
729 noah 3388 CBC 621 : has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
734 sfrost 3389 9 : result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
734 sfrost 3390 ECB :
3391 : /*
3392 : * Check if ACL_MAINTAIN is being checked and, if so, and not already set as
3393 : * 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.
132 andrew 3396 : */
117 jdavis 3397 GNC 14607 : if (mask & ACL_MAINTAIN &&
3398 1250 : !(result & ACL_MAINTAIN) &&
3399 435 : has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
3400 33 : result |= ACL_MAINTAIN;
3401 :
8986 bruce 3402 GIC 14607 : return result;
3403 : }
3404 :
3405 : /*
3406 : * Routine for examining a user's privileges for a configuration
368 tgl 3407 ECB : * parameter (GUC), identified by GUC name.
3408 : */
3409 : static AclMode
368 tgl 3410 CBC 85 : pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
3411 : {
3412 : AclMode result;
368 tgl 3413 ECB : char *parname;
3414 : text *partext;
3415 : HeapTuple tuple;
3416 :
3417 : /* Superusers bypass all permission checking. */
368 tgl 3418 GIC 85 : if (superuser_arg(roleid))
3419 1 : return mask;
3420 :
3421 : /* Convert name to the form it should have in pg_parameter_acl... */
3422 84 : parname = convert_GUC_name_for_parameter_acl(name);
3423 84 : partext = cstring_to_text(parname);
3424 :
3425 : /* ... and look it up */
368 tgl 3426 CBC 84 : tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3427 :
368 tgl 3428 GIC 84 : if (!HeapTupleIsValid(tuple))
3429 : {
3430 : /* If no entry, GUC has no permissions for non-superusers */
3431 39 : result = ACL_NO_RIGHTS;
3432 : }
3433 : else
3434 : {
368 tgl 3435 ECB : Datum aclDatum;
3436 : bool isNull;
3437 : Acl *acl;
3438 :
368 tgl 3439 GIC 45 : aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3440 : Anum_pg_parameter_acl_paracl,
3441 : &isNull);
368 tgl 3442 CBC 45 : if (isNull)
368 tgl 3443 ECB : {
368 tgl 3444 EUB : /* No ACL, so build default ACL */
368 tgl 3445 LBC 0 : acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
368 tgl 3446 UIC 0 : aclDatum = (Datum) 0;
3447 : }
3448 : else
3449 : {
3450 : /* detoast ACL if necessary */
368 tgl 3451 GIC 45 : acl = DatumGetAclP(aclDatum);
368 tgl 3452 ECB : }
3453 :
368 tgl 3454 CBC 45 : result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3455 :
368 tgl 3456 EUB : /* if we have a detoasted copy, free it */
368 tgl 3457 GBC 45 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
368 tgl 3458 GIC 45 : pfree(acl);
3459 :
3460 45 : ReleaseSysCache(tuple);
3461 : }
3462 :
3463 84 : pfree(parname);
368 tgl 3464 CBC 84 : pfree(partext);
3465 :
368 tgl 3466 GIC 84 : return result;
368 tgl 3467 ECB : }
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
368 tgl 3474 LBC 0 : pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
3475 : {
3476 : AclMode result;
3477 : HeapTuple tuple;
368 tgl 3478 ECB : Datum aclDatum;
368 tgl 3479 EUB : bool isNull;
3480 : Acl *acl;
3481 :
368 tgl 3482 ECB : /* Superusers bypass all permission checking. */
368 tgl 3483 UIC 0 : if (superuser_arg(roleid))
368 tgl 3484 LBC 0 : return mask;
368 tgl 3485 ECB :
3486 : /* Get the ACL from pg_parameter_acl */
368 tgl 3487 UIC 0 : tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
368 tgl 3488 LBC 0 : if (!HeapTupleIsValid(tuple))
368 tgl 3489 UIC 0 : ereport(ERROR,
3490 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3491 : errmsg("parameter ACL with OID %u does not exist",
3492 : acl_oid)));
368 tgl 3493 ECB :
368 tgl 3494 UIC 0 : aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
368 tgl 3495 ECB : Anum_pg_parameter_acl_paracl,
3496 : &isNull);
368 tgl 3497 UIC 0 : if (isNull)
3498 : {
368 tgl 3499 ECB : /* No ACL, so build default ACL */
368 tgl 3500 LBC 0 : acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
368 tgl 3501 UIC 0 : aclDatum = (Datum) 0;
368 tgl 3502 ECB : }
3503 : else
3504 : {
3505 : /* detoast ACL if necessary */
368 tgl 3506 LBC 0 : acl = DatumGetAclP(aclDatum);
3507 : }
3508 :
368 tgl 3509 UIC 0 : result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
368 tgl 3510 ECB :
3511 : /* if we have a detoasted copy, free it */
368 tgl 3512 LBC 0 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
368 tgl 3513 UIC 0 : pfree(acl);
368 tgl 3514 ECB :
368 tgl 3515 UIC 0 : ReleaseSysCache(tuple);
3516 :
368 tgl 3517 LBC 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
3568 rhaas 3524 ECB : * 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
3568 rhaas 3529 EUB : * snapshot, since all we do with the snapshot argument is pass it through
3530 : * to systable_beginscan().
3531 : */
3532 : static AclMode
4867 itagaki.takahiro 3533 CBC 292 : pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
3534 : AclMode mask, AclMaskHow how,
4867 itagaki.takahiro 3535 ECB : Snapshot snapshot)
3536 : {
3537 : AclMode result;
3538 : Relation pg_lo_meta;
4790 bruce 3539 : ScanKeyData entry[1];
3540 : SysScanDesc scan;
3541 : HeapTuple tuple;
3542 : Datum aclDatum;
4867 itagaki.takahiro 3543 : bool isNull;
3544 : Acl *acl;
3545 : Oid ownerId;
3546 :
3547 : /* Superusers bypass all permission checking. */
4867 itagaki.takahiro 3548 GIC 292 : if (superuser_arg(roleid))
3549 217 : return mask;
3550 :
3551 : /*
3552 : * Get the largeobject's ACL from pg_largeobject_metadata
3553 : */
1539 andres 3554 75 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
3555 : AccessShareLock);
3556 :
4867 itagaki.takahiro 3557 75 : ScanKeyInit(&entry[0],
3558 : Anum_pg_largeobject_metadata_oid,
3559 : BTEqualStrategyNumber, F_OIDEQ,
3560 : ObjectIdGetDatum(lobj_oid));
3561 :
3562 75 : scan = systable_beginscan(pg_lo_meta,
3563 : LargeObjectMetadataOidIndexId, true,
4867 itagaki.takahiro 3564 ECB : snapshot, 1, entry);
3565 :
4867 itagaki.takahiro 3566 GIC 75 : tuple = systable_getnext(scan);
3567 75 : if (!HeapTupleIsValid(tuple))
4867 itagaki.takahiro 3568 UIC 0 : ereport(ERROR,
3569 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3570 : errmsg("large object %u does not exist", lobj_oid)));
3571 :
4867 itagaki.takahiro 3572 GIC 75 : ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
3573 :
4867 itagaki.takahiro 3574 CBC 75 : aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
4867 itagaki.takahiro 3575 ECB : RelationGetDescr(pg_lo_meta), &isNull);
3576 :
4867 itagaki.takahiro 3577 CBC 75 : if (isNull)
3578 : {
3579 : /* No ACL, so build default ACL */
2006 peter_e 3580 GIC 18 : acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
4867 itagaki.takahiro 3581 18 : aclDatum = (Datum) 0;
3582 : }
3583 : else
3584 : {
3585 : /* detoast ACL if necessary */
3586 57 : acl = DatumGetAclP(aclDatum);
3587 : }
3588 :
3589 75 : result = aclmask(acl, roleid, ownerId, mask, how);
3590 :
3591 : /* if we have a detoasted copy, free it */
3592 75 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
4867 itagaki.takahiro 3593 CBC 75 : pfree(acl);
3594 :
4867 itagaki.takahiro 3595 GIC 75 : systable_endscan(scan);
3596 :
1539 andres 3597 75 : table_close(pg_lo_meta, AccessShareLock);
3598 :
4867 itagaki.takahiro 3599 75 : return result;
3600 : }
4867 itagaki.takahiro 3601 ECB :
3602 : /*
3603 : * Routine for examining a user's privileges for a namespace
3604 : */
3605 : static AclMode
6494 tgl 3606 GIC 524988 : pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
6907 tgl 3607 ECB : AclMode mask, AclMaskHow how)
3608 : {
3609 : AclMode result;
3610 : HeapTuple tuple;
7658 3611 : Datum aclDatum;
3612 : bool isNull;
3613 : Acl *acl;
3614 : Oid ownerId;
3615 :
3616 : /* Superusers bypass all permission checking. */
6494 tgl 3617 GIC 524988 : if (superuser_arg(roleid))
6907 3618 517205 : return mask;
3619 :
6892 bruce 3620 ECB : /*
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
6385 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.
6892 3626 : *
6347 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
6385 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.
6890 tgl 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.
6892 bruce 3638 : */
6890 tgl 3639 GIC 7783 : if (isTempNamespace(nsp_oid))
3640 : {
147 peter 3641 GNC 96 : if (object_aclcheck(DatabaseRelationId, MyDatabaseId, roleid,
3642 : ACL_CREATE_TEMP) == ACLCHECK_OK)
2006 peter_e 3643 CBC 96 : return mask & ACL_ALL_RIGHTS_SCHEMA;
3644 : else
6890 tgl 3645 UIC 0 : return mask & ACL_USAGE;
3646 : }
3647 :
7720 peter_e 3648 ECB : /*
7202 tgl 3649 : * Get the schema's ACL from pg_namespace
3650 : */
4802 rhaas 3651 GIC 7687 : tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
7658 tgl 3652 7687 : if (!HeapTupleIsValid(tuple))
7202 tgl 3653 UIC 0 : ereport(ERROR,
3654 : (errcode(ERRCODE_UNDEFINED_SCHEMA),
3655 : errmsg("schema with OID %u does not exist", nsp_oid)));
3656 :
6886 tgl 3657 CBC 7687 : ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3658 :
7658 tgl 3659 GIC 7687 : aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
7658 tgl 3660 ECB : &isNull);
7658 tgl 3661 CBC 7687 : if (isNull)
7658 tgl 3662 ECB : {
3663 : /* No ACL, so build default ACL */
2006 peter_e 3664 GIC 126 : acl = acldefault(OBJECT_SCHEMA, ownerId);
7658 tgl 3665 CBC 126 : aclDatum = (Datum) 0;
7658 tgl 3666 ECB : }
3667 : else
3668 : {
3669 : /* detoast ACL if necessary */
7658 tgl 3670 CBC 7561 : acl = DatumGetAclP(aclDatum);
3671 : }
7658 tgl 3672 ECB :
6494 tgl 3673 GIC 7687 : result = aclmask(acl, roleid, ownerId, mask, how);
3674 :
3675 : /* if we have a detoasted copy, free it */
7720 peter_e 3676 CBC 7687 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
7720 peter_e 3677 GIC 7687 : pfree(acl);
3678 :
7720 peter_e 3679 CBC 7687 : ReleaseSysCache(tuple);
3680 :
734 sfrost 3681 ECB : /*
697 tgl 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 : */
734 sfrost 3687 GIC 7706 : if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
729 noah 3688 35 : (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
3689 16 : has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
734 sfrost 3690 6 : result |= ACL_USAGE;
7720 peter_e 3691 7687 : return result;
3692 : }
3693 :
3694 : /*
3695 : * Routine for examining a user's privileges for a type.
3696 : */
3697 : static AclMode
4128 3698 620267 : 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 620267 : if (superuser_arg(roleid))
3711 618269 : return mask;
3712 :
3713 : /*
3714 : * Must get the type's tuple from pg_type
3715 : */
3716 1998 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3717 1998 : if (!HeapTupleIsValid(tuple))
4128 peter_e 3718 UIC 0 : ereport(ERROR,
3719 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3720 : errmsg("type with OID %u does not exist",
3721 : type_oid)));
4128 peter_e 3722 GIC 1998 : 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 : */
851 tgl 3728 1998 : if (IsTrueArrayType(typeForm))
3729 : {
3955 bruce 3730 18 : Oid elttype_oid = typeForm->typelem;
3731 :
4128 peter_e 3732 18 : ReleaseSysCache(tuple);
3733 :
3734 18 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3735 : /* this case is not a user-facing error, so elog not ereport */
3736 18 : if (!HeapTupleIsValid(tuple))
2491 tgl 3737 UIC 0 : elog(ERROR, "cache lookup failed for type %u", elttype_oid);
4128 peter_e 3738 GIC 18 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
3739 : }
3740 :
3741 : /*
3742 : * Now get the type's owner and ACL from the tuple
3743 : */
3744 1998 : ownerId = typeForm->typowner;
3745 :
3746 1998 : aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3747 : Anum_pg_type_typacl, &isNull);
3748 1998 : if (isNull)
3749 : {
3750 : /* No ACL, so build default ACL */
2006 3751 1887 : acl = acldefault(OBJECT_TYPE, ownerId);
4128 3752 1887 : aclDatum = (Datum) 0;
3753 : }
3754 : else
3755 : {
3756 : /* detoast rel's ACL if necessary */
3757 111 : acl = DatumGetAclP(aclDatum);
3758 : }
3759 :
3760 1998 : result = aclmask(acl, roleid, ownerId, mask, how);
3761 :
3762 : /* if we have a detoasted copy, free it */
3763 1998 : if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3764 1998 : pfree(acl);
3765 :
3766 1998 : ReleaseSysCache(tuple);
3767 :
3768 1998 : return result;
3769 : }
3770 :
3771 : /*
3772 : * Exported generic routine for checking a user's access privileges to an object
3773 : */
3774 : AclResult
147 peter 3775 GNC 1975421 : object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
3776 : {
3777 1975421 : if (object_aclmask(classid, objectid, roleid, mode, ACLMASK_ANY) != 0)
3778 1975150 : return ACLCHECK_OK;
3779 : else
3780 271 : 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
5190 tgl 3794 GIC 1576 : pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
3795 : Oid roleid, AclMode mode)
3796 : {
739 mail 3797 1576 : 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 2640 : pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
3809 : Oid roleid, AclMode mode, bool *is_missing)
3810 : {
3811 2640 : if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3812 : ACLMASK_ANY, is_missing) != 0)
5190 tgl 3813 904 : return ACLCHECK_OK;
3814 : else
3815 1736 : 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 84 : 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 : */
4802 rhaas 3852 84 : classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
5190 tgl 3853 84 : if (!HeapTupleIsValid(classTuple))
5175 tgl 3854 UIC 0 : return ACLCHECK_NO_PRIV;
5190 tgl 3855 GIC 84 : classForm = (Form_pg_class) GETSTRUCT(classTuple);
3856 :
3857 84 : nattrs = classForm->relnatts;
3858 :
3859 84 : 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 84 : result = ACLCHECK_NO_PRIV;
3866 :
3867 216 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
3868 : {
3869 : HeapTuple attTuple;
3870 : AclMode attmask;
3871 :
4802 rhaas 3872 171 : attTuple = SearchSysCache2(ATTNUM,
3873 : ObjectIdGetDatum(table_oid),
3874 : Int16GetDatum(curr_att));
5190 tgl 3875 171 : if (!HeapTupleIsValid(attTuple))
5175 tgl 3876 UIC 0 : continue;
3877 :
3878 : /* ignore dropped columns */
5175 tgl 3879 GIC 171 : if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
3880 : {
3881 9 : ReleaseSysCache(attTuple);
5190 3882 9 : 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 : */
1838 andrew 3890 162 : if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
5175 tgl 3891 72 : attmask = 0;
3892 : else
3893 90 : attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
3894 : mode, ACLMASK_ANY);
3895 :
3896 162 : ReleaseSysCache(attTuple);
3897 :
3898 162 : if (attmask != 0)
3899 : {
5190 3900 81 : result = ACLCHECK_OK;
3901 81 : if (how == ACLMASK_ANY)
3902 21 : break; /* succeed on any success */
3903 : }
3904 : else
3905 : {
3906 81 : result = ACLCHECK_NO_PRIV;
3907 81 : if (how == ACLMASK_ALL)
3908 18 : break; /* fail on any failure */
3909 : }
3910 : }
3911 :
3912 84 : 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
6494 3923 851220 : pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
3924 : {
739 mail 3925 851220 : 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 852257 : pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
3936 : AclMode mode, bool *is_missing)
3937 : {
3938 852257 : if (pg_class_aclmask_ext(table_oid, roleid, mode,
3939 : ACLMASK_ANY, is_missing) != 0)
6907 tgl 3940 851590 : return ACLCHECK_OK;
3941 : else
3942 667 : 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
368 3950 85 : pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
3951 : {
3952 85 : if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
3953 35 : return ACLCHECK_OK;
3954 : else
3955 50 : return ACLCHECK_NO_PRIV;
3956 : }
3957 :
3958 : /*
3959 : * Exported routine for checking a user's access privileges to a largeobject
3960 : */
3961 : AclResult
4867 itagaki.takahiro 3962 292 : pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
3963 : Snapshot snapshot)
3964 : {
3965 292 : if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
3966 : ACLMASK_ANY, snapshot) != 0)
3967 265 : return ACLCHECK_OK;
3968 : else
3969 27 : return ACLCHECK_NO_PRIV;
3970 : }
3971 :
3972 : /*
3973 : * Generic ownership check for an object
3974 : */
3975 : bool
147 peter 3976 GNC 331205 : object_ownercheck(Oid classid, Oid objectid, Oid roleid)
3977 : {
3978 : int cacheid;
3979 : Oid ownerId;
3980 :
3981 : /* Superusers bypass all permission checking. */
4439 peter_e 3982 331205 : if (superuser_arg(roleid))
3983 327414 : return true;
3984 :
147 peter 3985 3791 : cacheid = get_object_catcache_oid(classid);
3986 3791 : if (cacheid != -1)
3987 : {
3988 : HeapTuple tuple;
3989 :
3990 3781 : tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3991 3781 : if (!HeapTupleIsValid(tuple))
147 peter 3992 UNC 0 : ereport(ERROR,
3993 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3994 : errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
3995 :
15 dgustafsson 3996 GNC 3781 : ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3997 : tuple,
3998 3781 : get_object_attnum_owner(classid)));
147 peter 3999 3781 : 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 10 : rel = table_open(classid, AccessShareLock);
4012 :
4013 20 : ScanKeyInit(&entry[0],
4014 10 : get_object_attnum_oid(classid),
4015 : BTEqualStrategyNumber, F_OIDEQ,
4016 : ObjectIdGetDatum(objectid));
4017 :
4018 10 : scan = systable_beginscan(rel,
4019 : get_object_oid_index(classid), true,
4020 : NULL, 1, entry);
4021 :
4022 10 : tuple = systable_getnext(scan);
4023 10 : if (!HeapTupleIsValid(tuple))
147 peter 4024 UNC 0 : ereport(ERROR,
4025 : (errcode(ERRCODE_UNDEFINED_OBJECT),
4026 : errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
4027 :
147 peter 4028 GNC 10 : ownerId = DatumGetObjectId(heap_getattr(tuple,
4029 10 : get_object_attnum_owner(classid),
4030 : RelationGetDescr(rel),
4031 : &isnull));
4032 10 : Assert(!isnull);
4033 :
4034 10 : systable_endscan(scan);
4035 10 : table_close(rel, AccessShareLock);
4036 : }
4037 :
2207 alvherre 4038 GIC 3791 : 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
3029 4053 1136 : has_createrole_privilege(Oid roleid)
4054 : {
4055 1136 : bool result = false;
4056 : HeapTuple utup;
4057 :
4058 : /* Superusers bypass all permission checking. */
4059 1136 : if (superuser_arg(roleid))
4060 871 : return true;
4061 :
4062 265 : utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4063 265 : if (HeapTupleIsValid(utup))
4064 : {
4065 265 : result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4066 265 : ReleaseSysCache(utup);
4067 : }
4068 265 : return result;
4069 : }
4070 :
4071 : bool
4072 2110 : has_bypassrls_privilege(Oid roleid)
4073 : {
4074 2110 : bool result = false;
4075 : HeapTuple utup;
4076 :
4077 : /* Superusers bypass all permission checking. */
4078 2110 : if (superuser_arg(roleid))
4079 673 : return true;
4080 :
4081 1437 : utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4082 1437 : if (HeapTupleIsValid(utup))
4083 : {
4084 1437 : result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4085 1437 : ReleaseSysCache(utup);
4086 : }
4087 1437 : 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 *
4934 tgl 4096 153856 : get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
4097 : {
4098 153856 : Acl *result = NULL;
4099 : HeapTuple tuple;
4100 :
4802 rhaas 4101 153856 : tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4102 : ObjectIdGetDatum(roleId),
4103 : ObjectIdGetDatum(nsp_oid),
4104 : CharGetDatum(objtype));
4105 :
4934 tgl 4106 153856 : if (HeapTupleIsValid(tuple))
4107 : {
4108 : Datum aclDatum;
4109 : bool isNull;
4110 :
4111 114 : aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4112 : Anum_pg_default_acl_defaclacl,
4113 : &isNull);
4114 114 : if (!isNull)
4115 114 : result = DatumGetAclPCopy(aclDatum);
4116 114 : ReleaseSysCache(tuple);
4117 : }
4118 :
4119 153856 : 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 *
2006 peter_e 4131 76928 : 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 : */
4934 tgl 4143 76928 : if (IsBootstrapProcessingMode())
4934 tgl 4144 UIC 0 : return NULL;
4145 :
4146 : /* Check if object type is supported in pg_default_acl */
4934 tgl 4147 GIC 76928 : switch (objtype)
4148 : {
2006 peter_e 4149 61675 : case OBJECT_TABLE:
4934 tgl 4150 61675 : defaclobjtype = DEFACLOBJ_RELATION;
4151 61675 : break;
4152 :
2006 peter_e 4153 744 : case OBJECT_SEQUENCE:
4934 tgl 4154 744 : defaclobjtype = DEFACLOBJ_SEQUENCE;
4155 744 : break;
4156 :
2006 peter_e 4157 11262 : case OBJECT_FUNCTION:
4934 tgl 4158 11262 : defaclobjtype = DEFACLOBJ_FUNCTION;
4159 11262 : break;
4160 :
2006 peter_e 4161 2598 : case OBJECT_TYPE:
4128 4162 2598 : defaclobjtype = DEFACLOBJ_TYPE;
4163 2598 : break;
4164 :
2006 4165 649 : case OBJECT_SCHEMA:
2203 teodor 4166 649 : defaclobjtype = DEFACLOBJ_NAMESPACE;
4167 649 : break;
4168 :
4934 tgl 4169 UIC 0 : default:
4170 0 : return NULL;
4171 : }
4172 :
4173 : /* Look up the relevant pg_default_acl entries */
4934 tgl 4174 GIC 76928 : glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4175 76928 : schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4176 :
4177 : /* Quick out if neither entry exists */
4178 76928 : if (glob_acl == NULL && schema_acl == NULL)
4179 76832 : return NULL;
4180 :
4181 : /* We need to know the hard-wired default value, too */
4182 96 : def_acl = acldefault(objtype, ownerId);
4183 :
4184 : /* If there's no global entry, substitute the hard-wired default */
4185 96 : if (glob_acl == NULL)
4186 9 : glob_acl = def_acl;
4187 :
4188 : /* Merge in any per-schema privileges */
4189 96 : 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 96 : aclitemsort(result);
4196 96 : aclitemsort(def_acl);
4197 96 : if (aclequal(result, def_acl))
4198 12 : result = NULL;
4199 :
4200 96 : return result;
4201 : }
4202 :
4203 : /*
4204 : * Record dependencies on roles mentioned in a new object's ACL.
4205 : */
4206 : void
1612 4207 77982 : 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 77982 : if (acl == NULL)
4215 77898 : return;
4216 :
4217 : /* Extract roles mentioned in ACL */
4218 84 : nmembers = aclmembers(acl, &members);
4219 :
4220 : /* Update the shared dependency ACL info */
4221 84 : 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
2261 sfrost 4234 28 : 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 28 : if (classoid == RelationRelationId)
4244 : {
4245 : Form_pg_class pg_class_tuple;
4246 : Datum aclDatum;
4247 : bool isNull;
4248 : HeapTuple tuple;
4249 :
4250 7 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4251 7 : if (!HeapTupleIsValid(tuple))
2261 sfrost 4252 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", objoid);
2261 sfrost 4253 GIC 7 : 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 : */
1906 alvherre 4260 7 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
1087 tgl 4261 7 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4262 7 : pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4263 : {
1087 tgl 4264 UIC 0 : ReleaseSysCache(tuple);
2261 sfrost 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 : */
2261 sfrost 4272 GIC 7 : if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4273 : {
4274 : AttrNumber curr_att;
4275 6 : AttrNumber nattrs = pg_class_tuple->relnatts;
4276 :
4277 16 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
4278 : {
4279 : HeapTuple attTuple;
4280 : Datum attaclDatum;
4281 :
4282 10 : attTuple = SearchSysCache2(ATTNUM,
4283 : ObjectIdGetDatum(objoid),
4284 : Int16GetDatum(curr_att));
4285 :
4286 10 : if (!HeapTupleIsValid(attTuple))
2261 sfrost 4287 UIC 0 : continue;
4288 :
4289 : /* ignore dropped columns */
2261 sfrost 4290 GIC 10 : if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4291 : {
4292 1 : ReleaseSysCache(attTuple);
4293 1 : continue;
4294 : }
4295 :
4296 9 : attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4297 : Anum_pg_attribute_attacl,
4298 : &isNull);
4299 :
4300 : /* no need to do anything for a NULL ACL */
4301 9 : if (isNull)
4302 : {
4303 7 : ReleaseSysCache(attTuple);
4304 7 : continue;
4305 : }
4306 :
4307 2 : recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4308 2 : DatumGetAclP(attaclDatum));
4309 :
4310 2 : ReleaseSysCache(attTuple);
4311 : }
4312 : }
4313 :
4314 7 : aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4315 : &isNull);
4316 :
4317 : /* Add the record, if any, for the top-level object */
4318 7 : if (!isNull)
4319 4 : recordExtensionInitPrivWorker(objoid, classoid, 0,
4320 4 : DatumGetAclP(aclDatum));
4321 :
4322 7 : ReleaseSysCache(tuple);
4323 : }
4324 : /* pg_largeobject_metadata */
4325 21 : 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 : */
1539 andres 4339 UIC 0 : relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4340 :
4341 : /* There's no syscache for pg_largeobject_metadata */
2261 sfrost 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))
2135 tgl 4353 0 : elog(ERROR, "could not find tuple for large object %u", objoid);
4354 :
2261 sfrost 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. */
82 peter 4367 GNC 21 : else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4368 : {
4369 : Datum aclDatum;
4370 : bool isNull;
4371 : HeapTuple tuple;
4372 :
4373 10 : tuple = SearchSysCache1(get_object_catcache_oid(classoid),
4374 : ObjectIdGetDatum(objoid));
2261 sfrost 4375 GIC 10 : if (!HeapTupleIsValid(tuple))
82 peter 4376 UNC 0 : elog(ERROR, "cache lookup failed for %s %u",
4377 : get_object_class_descr(classoid), objoid);
4378 :
82 peter 4379 GNC 10 : aclDatum = SysCacheGetAttr(get_object_catcache_oid(classoid), tuple,
4380 10 : get_object_attnum_acl(classoid),
4381 : &isNull);
4382 :
4383 : /* Add the record, if any, for the top-level object */
2261 sfrost 4384 GIC 10 : if (!isNull)
4385 5 : recordExtensionInitPrivWorker(objoid, classoid, 0,
4386 5 : DatumGetAclP(aclDatum));
4387 :
4388 10 : 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 58 : 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 58 : if (classoid == RelationRelationId)
4405 : {
4406 : Form_pg_class pg_class_tuple;
4407 : HeapTuple tuple;
4408 :
4409 16 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4410 16 : if (!HeapTupleIsValid(tuple))
2261 sfrost 4411 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", objoid);
2261 sfrost 4412 GIC 16 : 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 : */
1906 alvherre 4419 16 : if (pg_class_tuple->relkind == RELKIND_INDEX ||
1087 tgl 4420 16 : pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4421 16 : pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4422 : {
1087 tgl 4423 UIC 0 : ReleaseSysCache(tuple);
2261 sfrost 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 : */
2261 sfrost 4431 GIC 16 : if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4432 : {
4433 : AttrNumber curr_att;
4434 16 : AttrNumber nattrs = pg_class_tuple->relnatts;
4435 :
4436 375 : for (curr_att = 1; curr_att <= nattrs; curr_att++)
4437 : {
4438 : HeapTuple attTuple;
4439 :
4440 359 : attTuple = SearchSysCache2(ATTNUM,
4441 : ObjectIdGetDatum(objoid),
4442 : Int16GetDatum(curr_att));
4443 :
4444 359 : if (!HeapTupleIsValid(attTuple))
2261 sfrost 4445 UIC 0 : continue;
4446 :
4447 : /* when removing, remove all entries, even dropped columns */
4448 :
2261 sfrost 4449 GIC 359 : recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4450 :
4451 359 : ReleaseSysCache(attTuple);
4452 : }
4453 : }
4454 :
4455 16 : ReleaseSysCache(tuple);
4456 : }
4457 :
4458 : /* Remove the record, if any, for the top-level object */
4459 58 : 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
2559 4480 53978 : 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 53978 : if (!creating_extension && !binary_upgrade_record_init_privs)
4491 53751 : return;
4492 :
2261 4493 227 : 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 655 : 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 :
1539 andres 4517 655 : relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4518 :
2559 sfrost 4519 655 : ScanKeyInit(&key[0],
4520 : Anum_pg_init_privs_objoid,
4521 : BTEqualStrategyNumber, F_OIDEQ,
4522 : ObjectIdGetDatum(objoid));
4523 655 : ScanKeyInit(&key[1],
4524 : Anum_pg_init_privs_classoid,
4525 : BTEqualStrategyNumber, F_OIDEQ,
4526 : ObjectIdGetDatum(classoid));
4527 655 : ScanKeyInit(&key[2],
4528 : Anum_pg_init_privs_objsubid,
4529 : BTEqualStrategyNumber, F_INT4EQ,
4530 : Int32GetDatum(objsubid));
4531 :
4532 655 : scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4533 : NULL, 3, key);
4534 :
4535 : /* There should exist only one entry or none. */
4536 655 : oldtuple = systable_getnext(scan);
4537 :
4538 : /* If we find an entry, update it with the latest ACL. */
4539 655 : if (HeapTupleIsValid(oldtuple))
4540 : {
267 peter 4541 GNC 85 : Datum values[Natts_pg_init_privs] = {0};
4542 85 : bool nulls[Natts_pg_init_privs] = {0};
4543 85 : bool replace[Natts_pg_init_privs] = {0};
4544 :
4545 : /* If we have a new ACL to set, then update the row with it. */
2559 sfrost 4546 GIC 85 : if (new_acl)
4547 : {
1863 tgl 4548 57 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4549 57 : replace[Anum_pg_init_privs_initprivs - 1] = true;
4550 :
2559 sfrost 4551 57 : oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4552 : values, nulls, replace);
4553 :
2259 alvherre 4554 57 : CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4555 : }
4556 : else
4557 : {
4558 : /* new_acl is NULL, so delete the entry we found. */
2258 tgl 4559 28 : CatalogTupleDelete(relation, &oldtuple->t_self);
4560 : }
4561 : }
4562 : else
4563 : {
267 peter 4564 GNC 570 : Datum values[Natts_pg_init_privs] = {0};
4565 570 : 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 : */
2261 sfrost 4573 GIC 570 : if (new_acl)
4574 : {
4575 : /* No entry found, so add it. */
4576 179 : values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4577 179 : values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4578 179 : values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4579 :
4580 : /* This function only handles initial privileges of extensions */
4581 179 : values[Anum_pg_init_privs_privtype - 1] =
4582 179 : CharGetDatum(INITPRIVS_EXTENSION);
4583 :
1863 tgl 4584 179 : values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4585 :
2261 sfrost 4586 179 : tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4587 :
2259 alvherre 4588 179 : CatalogTupleInsert(relation, tuple);
4589 : }
4590 : }
4591 :
2550 sfrost 4592 655 : systable_endscan(scan);
4593 :
4594 : /* prevent error when processing objects multiple times */
2559 4595 655 : CommandCounterIncrement();
4596 :
1539 andres 4597 655 : table_close(relation, RowExclusiveLock);
2559 sfrost 4598 655 : }
|