Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * user.c
4 : * Commands for manipulating roles (formerly called users).
5 : *
6 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * src/backend/commands/user.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 : #include "postgres.h"
14 :
15 : #include "access/genam.h"
16 : #include "access/htup_details.h"
17 : #include "access/table.h"
18 : #include "access/xact.h"
19 : #include "catalog/binary_upgrade.h"
20 : #include "catalog/catalog.h"
21 : #include "catalog/dependency.h"
22 : #include "catalog/indexing.h"
23 : #include "catalog/objectaccess.h"
24 : #include "catalog/pg_auth_members.h"
25 : #include "catalog/pg_authid.h"
26 : #include "catalog/pg_database.h"
27 : #include "catalog/pg_db_role_setting.h"
28 : #include "commands/comment.h"
29 : #include "commands/dbcommands.h"
30 : #include "commands/defrem.h"
31 : #include "commands/seclabel.h"
32 : #include "commands/user.h"
33 : #include "libpq/crypt.h"
34 : #include "miscadmin.h"
35 : #include "storage/lmgr.h"
36 : #include "utils/acl.h"
37 : #include "utils/builtins.h"
38 : #include "utils/catcache.h"
39 : #include "utils/fmgroids.h"
40 : #include "utils/syscache.h"
41 : #include "utils/varlena.h"
42 :
43 : /*
44 : * Removing a role grant - or the admin option on it - might recurse to
45 : * dependent grants. We use these values to reason about what would need to
46 : * be done in such cases.
47 : *
48 : * RRG_NOOP indicates a grant that would not need to be altered by the
49 : * operation.
50 : *
51 : * RRG_REMOVE_ADMIN_OPTION indicates a grant that would need to have
52 : * admin_option set to false by the operation.
53 : *
54 : * Similarly, RRG_REMOVE_INHERIT_OPTION and RRG_REMOVE_SET_OPTION indicate
55 : * grants that would need to have the corresponding options set to false.
56 : *
57 : * RRG_DELETE_GRANT indicates a grant that would need to be removed entirely
58 : * by the operation.
59 : */
60 : typedef enum
61 : {
62 : RRG_NOOP,
63 : RRG_REMOVE_ADMIN_OPTION,
64 : RRG_REMOVE_INHERIT_OPTION,
65 : RRG_REMOVE_SET_OPTION,
66 : RRG_DELETE_GRANT,
67 : } RevokeRoleGrantAction;
68 :
69 : /* Potentially set by pg_upgrade_support functions */
70 : Oid binary_upgrade_next_pg_authid_oid = InvalidOid;
71 :
72 : typedef struct
73 : {
74 : unsigned specified;
75 : bool admin;
76 : bool inherit;
77 : bool set;
78 : } GrantRoleOptions;
79 :
80 : #define GRANT_ROLE_SPECIFIED_ADMIN 0x0001
81 : #define GRANT_ROLE_SPECIFIED_INHERIT 0x0002
82 : #define GRANT_ROLE_SPECIFIED_SET 0x0004
83 :
84 : /* GUC parameters */
85 : int Password_encryption = PASSWORD_TYPE_SCRAM_SHA_256;
86 : char *createrole_self_grant = "";
87 : static bool createrole_self_grant_enabled = false;
88 : static GrantRoleOptions createrole_self_grant_options;
89 :
90 : /* Hook to check passwords in CreateRole() and AlterRole() */
91 : check_password_hook_type check_password_hook = NULL;
92 :
93 : static void AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
94 : List *memberSpecs, List *memberIds,
95 : Oid grantorId, GrantRoleOptions *popt);
96 : static void DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
97 : List *memberSpecs, List *memberIds,
98 : Oid grantorId, GrantRoleOptions *popt,
99 : DropBehavior behavior);
100 : static void check_role_membership_authorization(Oid currentUserId, Oid roleid,
101 : bool is_grant);
102 : static Oid check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId,
103 : bool is_grant);
104 : static RevokeRoleGrantAction *initialize_revoke_actions(CatCList *memlist);
105 : static bool plan_single_revoke(CatCList *memlist,
106 : RevokeRoleGrantAction *actions,
107 : Oid member, Oid grantor,
108 : GrantRoleOptions *popt,
109 : DropBehavior behavior);
110 : static void plan_member_revoke(CatCList *memlist,
111 : RevokeRoleGrantAction *actions, Oid member);
112 : static void plan_recursive_revoke(CatCList *memlist,
113 : RevokeRoleGrantAction *actions,
114 : int index,
115 : bool revoke_admin_option_only,
116 : DropBehavior behavior);
117 : static void InitGrantRoleOptions(GrantRoleOptions *popt);
118 :
119 :
120 : /* Check if current user has createrole privileges */
121 : static bool
122 2128 : have_createrole_privilege(void)
123 : {
124 2128 : return has_createrole_privilege(GetUserId());
125 : }
126 :
127 :
128 : /*
129 : * CREATE ROLE
130 : */
131 : Oid
132 1752 : CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
133 : {
134 : Relation pg_authid_rel;
135 : TupleDesc pg_authid_dsc;
136 : HeapTuple tuple;
137 1752 : Datum new_record[Natts_pg_authid] = {0};
138 1752 : bool new_record_nulls[Natts_pg_authid] = {0};
139 1752 : Oid currentUserId = GetUserId();
140 : Oid roleid;
141 : ListCell *item;
142 : ListCell *option;
143 1752 : char *password = NULL; /* user password */
144 1752 : bool issuper = false; /* Make the user a superuser? */
145 1752 : bool inherit = true; /* Auto inherit privileges? */
146 1752 : bool createrole = false; /* Can this user create roles? */
147 1752 : bool createdb = false; /* Can the user create databases? */
148 1752 : bool canlogin = false; /* Can this user login? */
149 1752 : bool isreplication = false; /* Is this a replication role? */
150 1752 : bool bypassrls = false; /* Is this a row security enabled role? */
151 1752 : int connlimit = -1; /* maximum connections allowed */
152 1752 : List *addroleto = NIL; /* roles to make this a member of */
153 1752 : List *rolemembers = NIL; /* roles to be members of this role */
154 1752 : List *adminmembers = NIL; /* roles to be admins of this role */
155 1752 : char *validUntil = NULL; /* time the login is valid until */
156 : Datum validUntil_datum; /* same, as timestamptz Datum */
157 : bool validUntil_null;
158 1752 : DefElem *dpassword = NULL;
159 1752 : DefElem *dissuper = NULL;
160 1752 : DefElem *dinherit = NULL;
161 1752 : DefElem *dcreaterole = NULL;
162 1752 : DefElem *dcreatedb = NULL;
163 1752 : DefElem *dcanlogin = NULL;
164 1752 : DefElem *disreplication = NULL;
165 1752 : DefElem *dconnlimit = NULL;
166 1752 : DefElem *daddroleto = NULL;
167 1752 : DefElem *drolemembers = NULL;
168 1752 : DefElem *dadminmembers = NULL;
169 1752 : DefElem *dvalidUntil = NULL;
170 1752 : DefElem *dbypassRLS = NULL;
171 : GrantRoleOptions popt;
172 :
173 : /* The defaults can vary depending on the original statement type */
174 1752 : switch (stmt->stmt_type)
175 : {
176 1286 : case ROLESTMT_ROLE:
177 1286 : break;
178 442 : case ROLESTMT_USER:
179 442 : canlogin = true;
180 : /* may eventually want inherit to default to false here */
181 442 : break;
182 24 : case ROLESTMT_GROUP:
183 24 : break;
184 : }
185 :
186 : /* Extract options from the statement node tree */
187 2922 : foreach(option, stmt->options)
188 : {
189 1170 : DefElem *defel = (DefElem *) lfirst(option);
190 :
191 1170 : if (strcmp(defel->defname, "password") == 0)
192 : {
193 112 : if (dpassword)
194 0 : errorConflictingDefElem(defel, pstate);
195 112 : dpassword = defel;
196 : }
197 1058 : else if (strcmp(defel->defname, "sysid") == 0)
198 : {
199 6 : ereport(NOTICE,
200 : (errmsg("SYSID can no longer be specified")));
201 : }
202 1052 : else if (strcmp(defel->defname, "superuser") == 0)
203 : {
204 194 : if (dissuper)
205 0 : errorConflictingDefElem(defel, pstate);
206 194 : dissuper = defel;
207 : }
208 858 : else if (strcmp(defel->defname, "inherit") == 0)
209 : {
210 66 : if (dinherit)
211 0 : errorConflictingDefElem(defel, pstate);
212 66 : dinherit = defel;
213 : }
214 792 : else if (strcmp(defel->defname, "createrole") == 0)
215 : {
216 92 : if (dcreaterole)
217 0 : errorConflictingDefElem(defel, pstate);
218 92 : dcreaterole = defel;
219 : }
220 700 : else if (strcmp(defel->defname, "createdb") == 0)
221 : {
222 72 : if (dcreatedb)
223 0 : errorConflictingDefElem(defel, pstate);
224 72 : dcreatedb = defel;
225 : }
226 628 : else if (strcmp(defel->defname, "canlogin") == 0)
227 : {
228 294 : if (dcanlogin)
229 0 : errorConflictingDefElem(defel, pstate);
230 294 : dcanlogin = defel;
231 : }
232 334 : else if (strcmp(defel->defname, "isreplication") == 0)
233 : {
234 92 : if (disreplication)
235 0 : errorConflictingDefElem(defel, pstate);
236 92 : disreplication = defel;
237 : }
238 242 : else if (strcmp(defel->defname, "connectionlimit") == 0)
239 : {
240 12 : if (dconnlimit)
241 0 : errorConflictingDefElem(defel, pstate);
242 12 : dconnlimit = defel;
243 : }
244 230 : else if (strcmp(defel->defname, "addroleto") == 0)
245 : {
246 100 : if (daddroleto)
247 0 : errorConflictingDefElem(defel, pstate);
248 100 : daddroleto = defel;
249 : }
250 130 : else if (strcmp(defel->defname, "rolemembers") == 0)
251 : {
252 22 : if (drolemembers)
253 0 : errorConflictingDefElem(defel, pstate);
254 22 : drolemembers = defel;
255 : }
256 108 : else if (strcmp(defel->defname, "adminmembers") == 0)
257 : {
258 22 : if (dadminmembers)
259 0 : errorConflictingDefElem(defel, pstate);
260 22 : dadminmembers = defel;
261 : }
262 86 : else if (strcmp(defel->defname, "validUntil") == 0)
263 : {
264 2 : if (dvalidUntil)
265 0 : errorConflictingDefElem(defel, pstate);
266 2 : dvalidUntil = defel;
267 : }
268 84 : else if (strcmp(defel->defname, "bypassrls") == 0)
269 : {
270 84 : if (dbypassRLS)
271 0 : errorConflictingDefElem(defel, pstate);
272 84 : dbypassRLS = defel;
273 : }
274 : else
275 0 : elog(ERROR, "option \"%s\" not recognized",
276 : defel->defname);
277 : }
278 :
279 1752 : if (dpassword && dpassword->arg)
280 100 : password = strVal(dpassword->arg);
281 1752 : if (dissuper)
282 194 : issuper = boolVal(dissuper->arg);
283 1752 : if (dinherit)
284 66 : inherit = boolVal(dinherit->arg);
285 1752 : if (dcreaterole)
286 92 : createrole = boolVal(dcreaterole->arg);
287 1752 : if (dcreatedb)
288 72 : createdb = boolVal(dcreatedb->arg);
289 1752 : if (dcanlogin)
290 294 : canlogin = boolVal(dcanlogin->arg);
291 1752 : if (disreplication)
292 92 : isreplication = boolVal(disreplication->arg);
293 1752 : if (dconnlimit)
294 : {
295 12 : connlimit = intVal(dconnlimit->arg);
296 12 : if (connlimit < -1)
297 0 : ereport(ERROR,
298 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
299 : errmsg("invalid connection limit: %d", connlimit)));
300 : }
301 1752 : if (daddroleto)
302 100 : addroleto = (List *) daddroleto->arg;
303 1752 : if (drolemembers)
304 22 : rolemembers = (List *) drolemembers->arg;
305 1752 : if (dadminmembers)
306 22 : adminmembers = (List *) dadminmembers->arg;
307 1752 : if (dvalidUntil)
308 2 : validUntil = strVal(dvalidUntil->arg);
309 1752 : if (dbypassRLS)
310 84 : bypassrls = boolVal(dbypassRLS->arg);
311 :
312 : /* Check some permissions first */
313 1752 : if (!superuser_arg(currentUserId))
314 : {
315 222 : if (!has_createrole_privilege(currentUserId))
316 0 : ereport(ERROR,
317 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
318 : errmsg("permission denied to create role"),
319 : errdetail("Only roles with the %s attribute may create roles.",
320 : "CREATEROLE")));
321 222 : if (issuper)
322 6 : ereport(ERROR,
323 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
324 : errmsg("permission denied to create role"),
325 : errdetail("Only roles with the %s attribute may create roles with the %s attribute.",
326 : "SUPERUSER", "SUPERUSER")));
327 216 : if (createdb && !have_createdb_privilege())
328 6 : ereport(ERROR,
329 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
330 : errmsg("permission denied to create role"),
331 : errdetail("Only roles with the %s attribute may create roles with the %s attribute.",
332 : "CREATEDB", "CREATEDB")));
333 210 : if (isreplication && !has_rolreplication(currentUserId))
334 12 : ereport(ERROR,
335 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
336 : errmsg("permission denied to create role"),
337 : errdetail("Only roles with the %s attribute may create roles with the %s attribute.",
338 : "REPLICATION", "REPLICATION")));
339 198 : if (bypassrls && !has_bypassrls_privilege(currentUserId))
340 6 : ereport(ERROR,
341 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
342 : errmsg("permission denied to create role"),
343 : errdetail("Only roles with the %s attribute may create roles with the %s attribute.",
344 : "BYPASSRLS", "BYPASSRLS")));
345 : }
346 :
347 : /*
348 : * Check that the user is not trying to create a role in the reserved
349 : * "pg_" namespace.
350 : */
351 1722 : if (IsReservedName(stmt->role))
352 8 : ereport(ERROR,
353 : (errcode(ERRCODE_RESERVED_NAME),
354 : errmsg("role name \"%s\" is reserved",
355 : stmt->role),
356 : errdetail("Role names starting with \"pg_\" are reserved.")));
357 :
358 : /*
359 : * If built with appropriate switch, whine when regression-testing
360 : * conventions for role names are violated.
361 : */
362 : #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
363 : if (strncmp(stmt->role, "regress_", 8) != 0)
364 : elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
365 : #endif
366 :
367 : /*
368 : * Check the pg_authid relation to be certain the role doesn't already
369 : * exist.
370 : */
371 1714 : pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
372 1714 : pg_authid_dsc = RelationGetDescr(pg_authid_rel);
373 :
374 1714 : if (OidIsValid(get_role_oid(stmt->role, true)))
375 8 : ereport(ERROR,
376 : (errcode(ERRCODE_DUPLICATE_OBJECT),
377 : errmsg("role \"%s\" already exists",
378 : stmt->role)));
379 :
380 : /* Convert validuntil to internal form */
381 1706 : if (validUntil)
382 : {
383 2 : validUntil_datum = DirectFunctionCall3(timestamptz_in,
384 : CStringGetDatum(validUntil),
385 : ObjectIdGetDatum(InvalidOid),
386 : Int32GetDatum(-1));
387 2 : validUntil_null = false;
388 : }
389 : else
390 : {
391 1704 : validUntil_datum = (Datum) 0;
392 1704 : validUntil_null = true;
393 : }
394 :
395 : /*
396 : * Call the password checking hook if there is one defined
397 : */
398 1706 : if (check_password_hook && password)
399 0 : (*check_password_hook) (stmt->role,
400 : password,
401 : get_password_type(password),
402 : validUntil_datum,
403 : validUntil_null);
404 :
405 : /*
406 : * Build a tuple to insert
407 : */
408 1706 : new_record[Anum_pg_authid_rolname - 1] =
409 1706 : DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
410 1706 : new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
411 1706 : new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
412 1706 : new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
413 1706 : new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
414 1706 : new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
415 1706 : new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
416 1706 : new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
417 :
418 1706 : if (password)
419 : {
420 : char *shadow_pass;
421 100 : const char *logdetail = NULL;
422 :
423 : /*
424 : * Don't allow an empty password. Libpq treats an empty password the
425 : * same as no password at all, and won't even try to authenticate. But
426 : * other clients might, so allowing it would be confusing. By clearing
427 : * the password when an empty string is specified, the account is
428 : * consistently locked for all clients.
429 : *
430 : * Note that this only covers passwords stored in the database itself.
431 : * There are also checks in the authentication code, to forbid an
432 : * empty password from being used with authentication methods that
433 : * fetch the password from an external system, like LDAP or PAM.
434 : */
435 194 : if (password[0] == '\0' ||
436 94 : plain_crypt_verify(stmt->role, password, "", &logdetail) == STATUS_OK)
437 : {
438 6 : ereport(NOTICE,
439 : (errmsg("empty string is not a valid password, clearing password")));
440 6 : new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
441 : }
442 : else
443 : {
444 : /* Encrypt the password to the requested format. */
445 94 : shadow_pass = encrypt_password(Password_encryption, stmt->role,
446 : password);
447 88 : new_record[Anum_pg_authid_rolpassword - 1] =
448 88 : CStringGetTextDatum(shadow_pass);
449 : }
450 : }
451 : else
452 1606 : new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
453 :
454 1700 : new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
455 1700 : new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
456 :
457 1700 : new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
458 :
459 : /*
460 : * pg_largeobject_metadata contains pg_authid.oid's, so we use the
461 : * binary-upgrade override.
462 : */
463 1700 : if (IsBinaryUpgrade)
464 : {
465 0 : if (!OidIsValid(binary_upgrade_next_pg_authid_oid))
466 0 : ereport(ERROR,
467 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
468 : errmsg("pg_authid OID value not set when in binary upgrade mode")));
469 :
470 0 : roleid = binary_upgrade_next_pg_authid_oid;
471 0 : binary_upgrade_next_pg_authid_oid = InvalidOid;
472 : }
473 : else
474 : {
475 1700 : roleid = GetNewOidWithIndex(pg_authid_rel, AuthIdOidIndexId,
476 : Anum_pg_authid_oid);
477 : }
478 :
479 1700 : new_record[Anum_pg_authid_oid - 1] = ObjectIdGetDatum(roleid);
480 :
481 1700 : tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
482 :
483 : /*
484 : * Insert new record in the pg_authid table
485 : */
486 1700 : CatalogTupleInsert(pg_authid_rel, tuple);
487 :
488 : /*
489 : * Advance command counter so we can see new record; else tests in
490 : * AddRoleMems may fail.
491 : */
492 1700 : if (addroleto || adminmembers || rolemembers)
493 138 : CommandCounterIncrement();
494 :
495 : /* Default grant. */
496 1700 : InitGrantRoleOptions(&popt);
497 :
498 : /*
499 : * Add the new role to the specified existing roles.
500 : */
501 1700 : if (addroleto)
502 : {
503 100 : RoleSpec *thisrole = makeNode(RoleSpec);
504 100 : List *thisrole_list = list_make1(thisrole);
505 100 : List *thisrole_oidlist = list_make1_oid(roleid);
506 :
507 100 : thisrole->roletype = ROLESPEC_CSTRING;
508 100 : thisrole->rolename = stmt->role;
509 100 : thisrole->location = -1;
510 :
511 128 : foreach(item, addroleto)
512 : {
513 100 : RoleSpec *oldrole = lfirst(item);
514 100 : HeapTuple oldroletup = get_rolespec_tuple(oldrole);
515 100 : Form_pg_authid oldroleform = (Form_pg_authid) GETSTRUCT(oldroletup);
516 100 : Oid oldroleid = oldroleform->oid;
517 100 : char *oldrolename = NameStr(oldroleform->rolname);
518 :
519 : /* can only add this role to roles for which you have rights */
520 100 : check_role_membership_authorization(currentUserId, oldroleid, true);
521 28 : AddRoleMems(currentUserId, oldrolename, oldroleid,
522 : thisrole_list,
523 : thisrole_oidlist,
524 : InvalidOid, &popt);
525 :
526 28 : ReleaseSysCache(oldroletup);
527 : }
528 : }
529 :
530 : /*
531 : * If the current user isn't a superuser, make them an admin of the new
532 : * role so that they can administer the new object they just created.
533 : * Superusers will be able to do that anyway.
534 : *
535 : * The grantor of record for this implicit grant is the bootstrap
536 : * superuser, which means that the CREATEROLE user cannot revoke the
537 : * grant. They can however grant the created role back to themselves with
538 : * different options, since they enjoy ADMIN OPTION on it.
539 : */
540 1628 : if (!superuser())
541 : {
542 120 : RoleSpec *current_role = makeNode(RoleSpec);
543 : GrantRoleOptions poptself;
544 : List *memberSpecs;
545 120 : List *memberIds = list_make1_oid(currentUserId);
546 :
547 120 : current_role->roletype = ROLESPEC_CURRENT_ROLE;
548 120 : current_role->location = -1;
549 120 : memberSpecs = list_make1(current_role);
550 :
551 120 : poptself.specified = GRANT_ROLE_SPECIFIED_ADMIN
552 : | GRANT_ROLE_SPECIFIED_INHERIT
553 : | GRANT_ROLE_SPECIFIED_SET;
554 120 : poptself.admin = true;
555 120 : poptself.inherit = false;
556 120 : poptself.set = false;
557 :
558 120 : AddRoleMems(BOOTSTRAP_SUPERUSERID, stmt->role, roleid,
559 : memberSpecs, memberIds,
560 : BOOTSTRAP_SUPERUSERID, &poptself);
561 :
562 : /*
563 : * We must make the implicit grant visible to the code below, else the
564 : * additional grants will fail.
565 : */
566 120 : CommandCounterIncrement();
567 :
568 : /*
569 : * Because of the implicit grant above, a CREATEROLE user who creates
570 : * a role has the ability to grant that role back to themselves with
571 : * the INHERIT or SET options, if they wish to inherit the role's
572 : * privileges or be able to SET ROLE to it. The createrole_self_grant
573 : * GUC can be used to make this happen automatically. This has no
574 : * security implications since the same user is able to make the same
575 : * grant using an explicit GRANT statement; it's just convenient.
576 : */
577 120 : if (createrole_self_grant_enabled)
578 6 : AddRoleMems(currentUserId, stmt->role, roleid,
579 : memberSpecs, memberIds,
580 : currentUserId, &createrole_self_grant_options);
581 : }
582 :
583 : /*
584 : * Add the specified members to this new role. adminmembers get the admin
585 : * option, rolemembers don't.
586 : *
587 : * NB: No permissions check is required here. If you have enough rights to
588 : * create a role, you can add any members you like.
589 : */
590 1628 : AddRoleMems(currentUserId, stmt->role, roleid,
591 : rolemembers, roleSpecsToIds(rolemembers),
592 : InvalidOid, &popt);
593 1622 : popt.specified |= GRANT_ROLE_SPECIFIED_ADMIN;
594 1622 : popt.admin = true;
595 1622 : AddRoleMems(currentUserId, stmt->role, roleid,
596 : adminmembers, roleSpecsToIds(adminmembers),
597 : InvalidOid, &popt);
598 :
599 : /* Post creation hook for new role */
600 1616 : InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
601 :
602 : /*
603 : * Close pg_authid, but keep lock till commit.
604 : */
605 1616 : table_close(pg_authid_rel, NoLock);
606 :
607 1616 : return roleid;
608 : }
609 :
610 :
611 : /*
612 : * ALTER ROLE
613 : *
614 : * Note: the rolemembers option accepted here is intended to support the
615 : * backwards-compatible ALTER GROUP syntax. Although it will work to say
616 : * "ALTER ROLE role ROLE rolenames", we don't document it.
617 : */
618 : Oid
619 430 : AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
620 : {
621 430 : Datum new_record[Natts_pg_authid] = {0};
622 430 : bool new_record_nulls[Natts_pg_authid] = {0};
623 430 : bool new_record_repl[Natts_pg_authid] = {0};
624 : Relation pg_authid_rel;
625 : TupleDesc pg_authid_dsc;
626 : HeapTuple tuple,
627 : new_tuple;
628 : Form_pg_authid authform;
629 : ListCell *option;
630 : char *rolename;
631 430 : char *password = NULL; /* user password */
632 430 : int connlimit = -1; /* maximum connections allowed */
633 430 : char *validUntil = NULL; /* time the login is valid until */
634 : Datum validUntil_datum; /* same, as timestamptz Datum */
635 : bool validUntil_null;
636 430 : DefElem *dpassword = NULL;
637 430 : DefElem *dissuper = NULL;
638 430 : DefElem *dinherit = NULL;
639 430 : DefElem *dcreaterole = NULL;
640 430 : DefElem *dcreatedb = NULL;
641 430 : DefElem *dcanlogin = NULL;
642 430 : DefElem *disreplication = NULL;
643 430 : DefElem *dconnlimit = NULL;
644 430 : DefElem *drolemembers = NULL;
645 430 : DefElem *dvalidUntil = NULL;
646 430 : DefElem *dbypassRLS = NULL;
647 : Oid roleid;
648 430 : Oid currentUserId = GetUserId();
649 : GrantRoleOptions popt;
650 :
651 430 : check_rolespec_name(stmt->role,
652 430 : _("Cannot alter reserved roles."));
653 :
654 : /* Extract options from the statement node tree */
655 1040 : foreach(option, stmt->options)
656 : {
657 610 : DefElem *defel = (DefElem *) lfirst(option);
658 :
659 610 : if (strcmp(defel->defname, "password") == 0)
660 : {
661 90 : if (dpassword)
662 0 : errorConflictingDefElem(defel, pstate);
663 90 : dpassword = defel;
664 : }
665 520 : else if (strcmp(defel->defname, "superuser") == 0)
666 : {
667 86 : if (dissuper)
668 0 : errorConflictingDefElem(defel, pstate);
669 86 : dissuper = defel;
670 : }
671 434 : else if (strcmp(defel->defname, "inherit") == 0)
672 : {
673 56 : if (dinherit)
674 0 : errorConflictingDefElem(defel, pstate);
675 56 : dinherit = defel;
676 : }
677 378 : else if (strcmp(defel->defname, "createrole") == 0)
678 : {
679 38 : if (dcreaterole)
680 0 : errorConflictingDefElem(defel, pstate);
681 38 : dcreaterole = defel;
682 : }
683 340 : else if (strcmp(defel->defname, "createdb") == 0)
684 : {
685 56 : if (dcreatedb)
686 0 : errorConflictingDefElem(defel, pstate);
687 56 : dcreatedb = defel;
688 : }
689 284 : else if (strcmp(defel->defname, "canlogin") == 0)
690 : {
691 62 : if (dcanlogin)
692 0 : errorConflictingDefElem(defel, pstate);
693 62 : dcanlogin = defel;
694 : }
695 222 : else if (strcmp(defel->defname, "isreplication") == 0)
696 : {
697 124 : if (disreplication)
698 0 : errorConflictingDefElem(defel, pstate);
699 124 : disreplication = defel;
700 : }
701 98 : else if (strcmp(defel->defname, "connectionlimit") == 0)
702 : {
703 12 : if (dconnlimit)
704 0 : errorConflictingDefElem(defel, pstate);
705 12 : dconnlimit = defel;
706 : }
707 86 : else if (strcmp(defel->defname, "rolemembers") == 0 &&
708 30 : stmt->action != 0)
709 : {
710 30 : if (drolemembers)
711 0 : errorConflictingDefElem(defel, pstate);
712 30 : drolemembers = defel;
713 : }
714 56 : else if (strcmp(defel->defname, "validUntil") == 0)
715 : {
716 0 : if (dvalidUntil)
717 0 : errorConflictingDefElem(defel, pstate);
718 0 : dvalidUntil = defel;
719 : }
720 56 : else if (strcmp(defel->defname, "bypassrls") == 0)
721 : {
722 56 : if (dbypassRLS)
723 0 : errorConflictingDefElem(defel, pstate);
724 56 : dbypassRLS = defel;
725 : }
726 : else
727 0 : elog(ERROR, "option \"%s\" not recognized",
728 : defel->defname);
729 : }
730 :
731 430 : if (dpassword && dpassword->arg)
732 90 : password = strVal(dpassword->arg);
733 430 : if (dconnlimit)
734 : {
735 12 : connlimit = intVal(dconnlimit->arg);
736 12 : if (connlimit < -1)
737 0 : ereport(ERROR,
738 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
739 : errmsg("invalid connection limit: %d", connlimit)));
740 : }
741 430 : if (dvalidUntil)
742 0 : validUntil = strVal(dvalidUntil->arg);
743 :
744 : /*
745 : * Scan the pg_authid relation to be certain the user exists.
746 : */
747 430 : pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
748 430 : pg_authid_dsc = RelationGetDescr(pg_authid_rel);
749 :
750 430 : tuple = get_rolespec_tuple(stmt->role);
751 414 : authform = (Form_pg_authid) GETSTRUCT(tuple);
752 414 : rolename = pstrdup(NameStr(authform->rolname));
753 414 : roleid = authform->oid;
754 :
755 : /* To mess with a superuser in any way you gotta be superuser. */
756 414 : if (!superuser() && authform->rolsuper)
757 0 : ereport(ERROR,
758 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
759 : errmsg("permission denied to alter role"),
760 : errdetail("Only roles with the %s attribute may alter roles with the %s attribute.",
761 : "SUPERUSER", "SUPERUSER")));
762 414 : if (!superuser() && dissuper)
763 18 : ereport(ERROR,
764 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
765 : errmsg("permission denied to alter role"),
766 : errdetail("Only roles with the %s attribute may change the %s attribute.",
767 : "SUPERUSER", "SUPERUSER")));
768 :
769 : /*
770 : * Most changes to a role require that you both have CREATEROLE privileges
771 : * and also ADMIN OPTION on the role.
772 : */
773 396 : if (!have_createrole_privilege() ||
774 372 : !is_admin_of_role(GetUserId(), roleid))
775 : {
776 : /* things an unprivileged user certainly can't do */
777 30 : if (dinherit || dcreaterole || dcreatedb || dcanlogin || dconnlimit ||
778 24 : dvalidUntil || disreplication || dbypassRLS)
779 6 : ereport(ERROR,
780 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
781 : errmsg("permission denied to alter role"),
782 : errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
783 : "CREATEROLE", "ADMIN", rolename)));
784 :
785 : /* an unprivileged user can change their own password */
786 24 : if (dpassword && roleid != currentUserId)
787 6 : ereport(ERROR,
788 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
789 : errmsg("permission denied to alter role"),
790 : errdetail("To change another role's password, the current user must have the %s attribute and the %s option on the role.",
791 : "CREATEROLE", "ADMIN")));
792 : }
793 366 : else if (!superuser())
794 : {
795 : /*
796 : * Even if you have both CREATEROLE and ADMIN OPTION on a role, you
797 : * can only change the CREATEDB, REPLICATION, or BYPASSRLS attributes
798 : * if they are set for your own role (or you are the superuser).
799 : */
800 60 : if (dcreatedb && !have_createdb_privilege())
801 6 : ereport(ERROR,
802 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
803 : errmsg("permission denied to alter role"),
804 : errdetail("Only roles with the %s attribute may change the %s attribute.",
805 : "CREATEDB", "CREATEDB")));
806 54 : if (disreplication && !has_rolreplication(currentUserId))
807 6 : ereport(ERROR,
808 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
809 : errmsg("permission denied to alter role"),
810 : errdetail("Only roles with the %s attribute may change the %s attribute.",
811 : "REPLICATION", "REPLICATION")));
812 48 : if (dbypassRLS && !has_bypassrls_privilege(currentUserId))
813 6 : ereport(ERROR,
814 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
815 : errmsg("permission denied to alter role"),
816 : errdetail("Only roles with the %s attribute may change the %s attribute.",
817 : "BYPASSRLS", "BYPASSRLS")));
818 : }
819 :
820 : /* To add members to a role, you need ADMIN OPTION. */
821 366 : if (drolemembers && !is_admin_of_role(currentUserId, roleid))
822 0 : ereport(ERROR,
823 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
824 : errmsg("permission denied to alter role"),
825 : errdetail("Only roles with the %s option on role \"%s\" may add members.",
826 : "ADMIN", rolename)));
827 :
828 : /* Convert validuntil to internal form */
829 366 : if (dvalidUntil)
830 : {
831 0 : validUntil_datum = DirectFunctionCall3(timestamptz_in,
832 : CStringGetDatum(validUntil),
833 : ObjectIdGetDatum(InvalidOid),
834 : Int32GetDatum(-1));
835 0 : validUntil_null = false;
836 : }
837 : else
838 : {
839 : /* fetch existing setting in case hook needs it */
840 366 : validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
841 : Anum_pg_authid_rolvaliduntil,
842 : &validUntil_null);
843 : }
844 :
845 : /*
846 : * Call the password checking hook if there is one defined
847 : */
848 366 : if (check_password_hook && password)
849 12 : (*check_password_hook) (rolename,
850 : password,
851 : get_password_type(password),
852 : validUntil_datum,
853 : validUntil_null);
854 :
855 : /*
856 : * Build an updated tuple, perusing the information just obtained
857 : */
858 :
859 : /*
860 : * issuper/createrole/etc
861 : */
862 358 : if (dissuper)
863 : {
864 68 : bool should_be_super = boolVal(dissuper->arg);
865 :
866 68 : if (!should_be_super && roleid == BOOTSTRAP_SUPERUSERID)
867 0 : ereport(ERROR,
868 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
869 : errmsg("permission denied to alter role"),
870 : errdetail("The bootstrap superuser must have the %s attribute.",
871 : "SUPERUSER")));
872 :
873 68 : new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(should_be_super);
874 68 : new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
875 : }
876 :
877 358 : if (dinherit)
878 : {
879 50 : new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(boolVal(dinherit->arg));
880 50 : new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
881 : }
882 :
883 358 : if (dcreaterole)
884 : {
885 38 : new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(boolVal(dcreaterole->arg));
886 38 : new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
887 : }
888 :
889 358 : if (dcreatedb)
890 : {
891 50 : new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(boolVal(dcreatedb->arg));
892 50 : new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
893 : }
894 :
895 358 : if (dcanlogin)
896 : {
897 56 : new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(boolVal(dcanlogin->arg));
898 56 : new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
899 : }
900 :
901 358 : if (disreplication)
902 : {
903 102 : new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(boolVal(disreplication->arg));
904 102 : new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
905 : }
906 :
907 358 : if (dconnlimit)
908 : {
909 6 : new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
910 6 : new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
911 : }
912 :
913 : /* password */
914 358 : if (password)
915 : {
916 : char *shadow_pass;
917 76 : const char *logdetail = NULL;
918 :
919 : /* Like in CREATE USER, don't allow an empty password. */
920 152 : if (password[0] == '\0' ||
921 76 : plain_crypt_verify(rolename, password, "", &logdetail) == STATUS_OK)
922 : {
923 12 : ereport(NOTICE,
924 : (errmsg("empty string is not a valid password, clearing password")));
925 12 : new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
926 : }
927 : else
928 : {
929 : /* Encrypt the password to the requested format. */
930 64 : shadow_pass = encrypt_password(Password_encryption, rolename,
931 : password);
932 58 : new_record[Anum_pg_authid_rolpassword - 1] =
933 58 : CStringGetTextDatum(shadow_pass);
934 : }
935 70 : new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
936 : }
937 :
938 : /* unset password */
939 352 : if (dpassword && dpassword->arg == NULL)
940 : {
941 0 : new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
942 0 : new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
943 : }
944 :
945 : /* valid until */
946 352 : new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
947 352 : new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
948 352 : new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
949 :
950 352 : if (dbypassRLS)
951 : {
952 50 : new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(boolVal(dbypassRLS->arg));
953 50 : new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
954 : }
955 :
956 352 : new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
957 : new_record_nulls, new_record_repl);
958 352 : CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple);
959 :
960 352 : InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
961 :
962 352 : ReleaseSysCache(tuple);
963 352 : heap_freetuple(new_tuple);
964 :
965 352 : InitGrantRoleOptions(&popt);
966 :
967 : /*
968 : * Advance command counter so we can see new record; else tests in
969 : * AddRoleMems may fail.
970 : */
971 352 : if (drolemembers)
972 : {
973 30 : List *rolemembers = (List *) drolemembers->arg;
974 :
975 30 : CommandCounterIncrement();
976 :
977 30 : if (stmt->action == +1) /* add members to role */
978 18 : AddRoleMems(currentUserId, rolename, roleid,
979 : rolemembers, roleSpecsToIds(rolemembers),
980 : InvalidOid, &popt);
981 12 : else if (stmt->action == -1) /* drop members from role */
982 12 : DelRoleMems(currentUserId, rolename, roleid,
983 : rolemembers, roleSpecsToIds(rolemembers),
984 : InvalidOid, &popt, DROP_RESTRICT);
985 : }
986 :
987 : /*
988 : * Close pg_authid, but keep lock till commit.
989 : */
990 352 : table_close(pg_authid_rel, NoLock);
991 :
992 352 : return roleid;
993 : }
994 :
995 :
996 : /*
997 : * ALTER ROLE ... SET
998 : */
999 : Oid
1000 82 : AlterRoleSet(AlterRoleSetStmt *stmt)
1001 : {
1002 : HeapTuple roletuple;
1003 : Form_pg_authid roleform;
1004 82 : Oid databaseid = InvalidOid;
1005 82 : Oid roleid = InvalidOid;
1006 :
1007 82 : if (stmt->role)
1008 : {
1009 74 : check_rolespec_name(stmt->role,
1010 74 : _("Cannot alter reserved roles."));
1011 :
1012 74 : roletuple = get_rolespec_tuple(stmt->role);
1013 66 : roleform = (Form_pg_authid) GETSTRUCT(roletuple);
1014 66 : roleid = roleform->oid;
1015 :
1016 : /*
1017 : * Obtain a lock on the role and make sure it didn't go away in the
1018 : * meantime.
1019 : */
1020 66 : shdepLockAndCheckObject(AuthIdRelationId, roleid);
1021 :
1022 : /*
1023 : * To mess with a superuser you gotta be superuser; otherwise you need
1024 : * CREATEROLE plus admin option on the target role; unless you're just
1025 : * trying to change your own settings
1026 : */
1027 66 : if (roleform->rolsuper)
1028 : {
1029 30 : if (!superuser())
1030 0 : ereport(ERROR,
1031 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1032 : errmsg("permission denied to alter role"),
1033 : errdetail("Only roles with the %s attribute may alter roles with the %s attribute.",
1034 : "SUPERUSER", "SUPERUSER")));
1035 : }
1036 : else
1037 : {
1038 36 : if ((!have_createrole_privilege() ||
1039 26 : !is_admin_of_role(GetUserId(), roleid))
1040 10 : && roleid != GetUserId())
1041 0 : ereport(ERROR,
1042 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1043 : errmsg("permission denied to alter role"),
1044 : errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
1045 : "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
1046 : }
1047 :
1048 66 : ReleaseSysCache(roletuple);
1049 : }
1050 :
1051 : /* look up and lock the database, if specified */
1052 74 : if (stmt->database != NULL)
1053 : {
1054 0 : databaseid = get_database_oid(stmt->database, false);
1055 0 : shdepLockAndCheckObject(DatabaseRelationId, databaseid);
1056 :
1057 0 : if (!stmt->role)
1058 : {
1059 : /*
1060 : * If no role is specified, then this is effectively the same as
1061 : * ALTER DATABASE ... SET, so use the same permission check.
1062 : */
1063 0 : if (!object_ownercheck(DatabaseRelationId, databaseid, GetUserId()))
1064 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
1065 0 : stmt->database);
1066 : }
1067 : }
1068 :
1069 74 : if (!stmt->role && !stmt->database)
1070 : {
1071 : /* Must be superuser to alter settings globally. */
1072 8 : if (!superuser())
1073 0 : ereport(ERROR,
1074 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1075 : errmsg("permission denied to alter setting"),
1076 : errdetail("Only roles with the %s attribute may alter settings globally.",
1077 : "SUPERUSER")));
1078 : }
1079 :
1080 74 : AlterSetting(databaseid, roleid, stmt->setstmt);
1081 :
1082 72 : return roleid;
1083 : }
1084 :
1085 :
1086 : /*
1087 : * DROP ROLE
1088 : */
1089 : void
1090 1672 : DropRole(DropRoleStmt *stmt)
1091 : {
1092 : Relation pg_authid_rel,
1093 : pg_auth_members_rel;
1094 : ListCell *item;
1095 1672 : List *role_oids = NIL;
1096 :
1097 1672 : if (!have_createrole_privilege())
1098 0 : ereport(ERROR,
1099 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1100 : errmsg("permission denied to drop role"),
1101 : errdetail("Only roles with the %s attribute and the %s option on the target roles may drop roles.",
1102 : "CREATEROLE", "ADMIN")));
1103 :
1104 : /*
1105 : * Scan the pg_authid relation to find the Oid of the role(s) to be
1106 : * deleted and perform preliminary permissions and sanity checks.
1107 : */
1108 1672 : pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
1109 1672 : pg_auth_members_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1110 :
1111 3332 : foreach(item, stmt->roles)
1112 : {
1113 1770 : RoleSpec *rolspec = lfirst(item);
1114 : char *role;
1115 : HeapTuple tuple,
1116 : tmp_tuple;
1117 : Form_pg_authid roleform;
1118 : ScanKeyData scankey;
1119 : SysScanDesc sscan;
1120 : Oid roleid;
1121 :
1122 1770 : if (rolspec->roletype != ROLESPEC_CSTRING)
1123 0 : ereport(ERROR,
1124 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1125 : errmsg("cannot use special role specifier in DROP ROLE")));
1126 1770 : role = rolspec->rolename;
1127 :
1128 1770 : tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
1129 1770 : if (!HeapTupleIsValid(tuple))
1130 : {
1131 302 : if (!stmt->missing_ok)
1132 : {
1133 92 : ereport(ERROR,
1134 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1135 : errmsg("role \"%s\" does not exist", role)));
1136 : }
1137 : else
1138 : {
1139 210 : ereport(NOTICE,
1140 : (errmsg("role \"%s\" does not exist, skipping",
1141 : role)));
1142 : }
1143 :
1144 210 : continue;
1145 : }
1146 :
1147 1468 : roleform = (Form_pg_authid) GETSTRUCT(tuple);
1148 1468 : roleid = roleform->oid;
1149 :
1150 1468 : if (roleid == GetUserId())
1151 6 : ereport(ERROR,
1152 : (errcode(ERRCODE_OBJECT_IN_USE),
1153 : errmsg("current user cannot be dropped")));
1154 1462 : if (roleid == GetOuterUserId())
1155 0 : ereport(ERROR,
1156 : (errcode(ERRCODE_OBJECT_IN_USE),
1157 : errmsg("current user cannot be dropped")));
1158 1462 : if (roleid == GetSessionUserId())
1159 0 : ereport(ERROR,
1160 : (errcode(ERRCODE_OBJECT_IN_USE),
1161 : errmsg("session user cannot be dropped")));
1162 :
1163 : /*
1164 : * For safety's sake, we allow createrole holders to drop ordinary
1165 : * roles but not superuser roles, and only if they also have ADMIN
1166 : * OPTION.
1167 : */
1168 1462 : if (roleform->rolsuper && !superuser())
1169 6 : ereport(ERROR,
1170 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1171 : errmsg("permission denied to drop role"),
1172 : errdetail("Only roles with the %s attribute may drop roles with the %s attribute.",
1173 : "SUPERUSER", "SUPERUSER")));
1174 1456 : if (!is_admin_of_role(GetUserId(), roleid))
1175 6 : ereport(ERROR,
1176 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1177 : errmsg("permission denied to drop role"),
1178 : errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may drop this role.",
1179 : "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
1180 :
1181 : /* DROP hook for the role being removed */
1182 1450 : InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
1183 :
1184 : /* Don't leak the syscache tuple */
1185 1450 : ReleaseSysCache(tuple);
1186 :
1187 : /*
1188 : * Lock the role, so nobody can add dependencies to her while we drop
1189 : * her. We keep the lock until the end of transaction.
1190 : */
1191 1450 : LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);
1192 :
1193 : /*
1194 : * If there is a pg_auth_members entry that has one of the roles to be
1195 : * dropped as the roleid or member, it should be silently removed, but
1196 : * if there is a pg_auth_members entry that has one of the roles to be
1197 : * dropped as the grantor, the operation should fail.
1198 : *
1199 : * It's possible, however, that a single pg_auth_members entry could
1200 : * fall into multiple categories - e.g. the user could do "GRANT foo
1201 : * TO bar GRANTED BY baz" and then "DROP ROLE baz, bar". We want such
1202 : * an operation to succeed regardless of the order in which the
1203 : * to-be-dropped roles are passed to DROP ROLE.
1204 : *
1205 : * To make that work, we remove all pg_auth_members entries that can
1206 : * be silently removed in this loop, and then below we'll make a
1207 : * second pass over the list of roles to be removed and check for any
1208 : * remaining dependencies.
1209 : */
1210 1450 : ScanKeyInit(&scankey,
1211 : Anum_pg_auth_members_roleid,
1212 : BTEqualStrategyNumber, F_OIDEQ,
1213 : ObjectIdGetDatum(roleid));
1214 :
1215 1450 : sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
1216 : true, NULL, 1, &scankey);
1217 :
1218 1696 : while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1219 : {
1220 : Form_pg_auth_members authmem_form;
1221 :
1222 246 : authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
1223 246 : deleteSharedDependencyRecordsFor(AuthMemRelationId,
1224 : authmem_form->oid, 0);
1225 246 : CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1226 : }
1227 :
1228 1450 : systable_endscan(sscan);
1229 :
1230 1450 : ScanKeyInit(&scankey,
1231 : Anum_pg_auth_members_member,
1232 : BTEqualStrategyNumber, F_OIDEQ,
1233 : ObjectIdGetDatum(roleid));
1234 :
1235 1450 : sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
1236 : true, NULL, 1, &scankey);
1237 :
1238 1704 : while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1239 : {
1240 : Form_pg_auth_members authmem_form;
1241 :
1242 254 : authmem_form = (Form_pg_auth_members) GETSTRUCT(tmp_tuple);
1243 254 : deleteSharedDependencyRecordsFor(AuthMemRelationId,
1244 : authmem_form->oid, 0);
1245 254 : CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1246 : }
1247 :
1248 1450 : systable_endscan(sscan);
1249 :
1250 : /*
1251 : * Advance command counter so that later iterations of this loop will
1252 : * see the changes already made. This is essential if, for example,
1253 : * we are trying to drop both a role and one of its direct members ---
1254 : * we'll get an error if we try to delete the linking pg_auth_members
1255 : * tuple twice. (We do not need a CCI between the two delete loops
1256 : * above, because it's not allowed for a role to directly contain
1257 : * itself.)
1258 : */
1259 1450 : CommandCounterIncrement();
1260 :
1261 : /* Looks tentatively OK, add it to the list if not there yet. */
1262 1450 : role_oids = list_append_unique_oid(role_oids, roleid);
1263 : }
1264 :
1265 : /*
1266 : * Second pass over the roles to be removed.
1267 : */
1268 2882 : foreach(item, role_oids)
1269 : {
1270 1444 : Oid roleid = lfirst_oid(item);
1271 : HeapTuple tuple;
1272 : Form_pg_authid roleform;
1273 : char *detail;
1274 : char *detail_log;
1275 :
1276 : /*
1277 : * Re-find the pg_authid tuple.
1278 : *
1279 : * Since we've taken a lock on the role OID, it shouldn't be possible
1280 : * for the tuple to have been deleted -- or for that matter updated --
1281 : * unless the user is manually modifying the system catalogs.
1282 : */
1283 1444 : tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
1284 1444 : if (!HeapTupleIsValid(tuple))
1285 0 : elog(ERROR, "could not find tuple for role %u", roleid);
1286 1444 : roleform = (Form_pg_authid) GETSTRUCT(tuple);
1287 :
1288 : /*
1289 : * Check for pg_shdepend entries depending on this role.
1290 : *
1291 : * This needs to happen after we've completed removing any
1292 : * pg_auth_members entries that can be removed silently, in order to
1293 : * avoid spurious failures. See notes above for more details.
1294 : */
1295 1444 : if (checkSharedDependencies(AuthIdRelationId, roleid,
1296 : &detail, &detail_log))
1297 124 : ereport(ERROR,
1298 : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1299 : errmsg("role \"%s\" cannot be dropped because some objects depend on it",
1300 : NameStr(roleform->rolname)),
1301 : errdetail_internal("%s", detail),
1302 : errdetail_log("%s", detail_log)));
1303 :
1304 : /*
1305 : * Remove the role from the pg_authid table
1306 : */
1307 1320 : CatalogTupleDelete(pg_authid_rel, &tuple->t_self);
1308 :
1309 1320 : ReleaseSysCache(tuple);
1310 :
1311 : /*
1312 : * Remove any comments or security labels on this role.
1313 : */
1314 1320 : DeleteSharedComments(roleid, AuthIdRelationId);
1315 1320 : DeleteSharedSecurityLabel(roleid, AuthIdRelationId);
1316 :
1317 : /*
1318 : * Remove settings for this role.
1319 : */
1320 1320 : DropSetting(InvalidOid, roleid);
1321 : }
1322 :
1323 : /*
1324 : * Now we can clean up; but keep locks until commit.
1325 : */
1326 1438 : table_close(pg_auth_members_rel, NoLock);
1327 1438 : table_close(pg_authid_rel, NoLock);
1328 1438 : }
1329 :
1330 : /*
1331 : * Rename role
1332 : */
1333 : ObjectAddress
1334 30 : RenameRole(const char *oldname, const char *newname)
1335 : {
1336 : HeapTuple oldtuple,
1337 : newtuple;
1338 : TupleDesc dsc;
1339 : Relation rel;
1340 : Datum datum;
1341 : bool isnull;
1342 : Datum repl_val[Natts_pg_authid];
1343 : bool repl_null[Natts_pg_authid];
1344 : bool repl_repl[Natts_pg_authid];
1345 : int i;
1346 : Oid roleid;
1347 : ObjectAddress address;
1348 : Form_pg_authid authform;
1349 :
1350 30 : rel = table_open(AuthIdRelationId, RowExclusiveLock);
1351 30 : dsc = RelationGetDescr(rel);
1352 :
1353 30 : oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
1354 30 : if (!HeapTupleIsValid(oldtuple))
1355 0 : ereport(ERROR,
1356 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1357 : errmsg("role \"%s\" does not exist", oldname)));
1358 :
1359 : /*
1360 : * XXX Client applications probably store the session user somewhere, so
1361 : * renaming it could cause confusion. On the other hand, there may not be
1362 : * an actual problem besides a little confusion, so think about this and
1363 : * decide. Same for SET ROLE ... we don't restrict renaming the current
1364 : * effective userid, though.
1365 : */
1366 :
1367 30 : authform = (Form_pg_authid) GETSTRUCT(oldtuple);
1368 30 : roleid = authform->oid;
1369 :
1370 30 : if (roleid == GetSessionUserId())
1371 0 : ereport(ERROR,
1372 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1373 : errmsg("session user cannot be renamed")));
1374 30 : if (roleid == GetOuterUserId())
1375 0 : ereport(ERROR,
1376 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1377 : errmsg("current user cannot be renamed")));
1378 :
1379 : /*
1380 : * Check that the user is not trying to rename a system role and not
1381 : * trying to rename a role into the reserved "pg_" namespace.
1382 : */
1383 30 : if (IsReservedName(NameStr(authform->rolname)))
1384 0 : ereport(ERROR,
1385 : (errcode(ERRCODE_RESERVED_NAME),
1386 : errmsg("role name \"%s\" is reserved",
1387 : NameStr(authform->rolname)),
1388 : errdetail("Role names starting with \"pg_\" are reserved.")));
1389 :
1390 30 : if (IsReservedName(newname))
1391 0 : ereport(ERROR,
1392 : (errcode(ERRCODE_RESERVED_NAME),
1393 : errmsg("role name \"%s\" is reserved",
1394 : newname),
1395 : errdetail("Role names starting with \"pg_\" are reserved.")));
1396 :
1397 : /*
1398 : * If built with appropriate switch, whine when regression-testing
1399 : * conventions for role names are violated.
1400 : */
1401 : #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
1402 : if (strncmp(newname, "regress_", 8) != 0)
1403 : elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
1404 : #endif
1405 :
1406 : /* make sure the new name doesn't exist */
1407 30 : if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
1408 0 : ereport(ERROR,
1409 : (errcode(ERRCODE_DUPLICATE_OBJECT),
1410 : errmsg("role \"%s\" already exists", newname)));
1411 :
1412 : /*
1413 : * Only superusers can mess with superusers. Otherwise, a user with
1414 : * CREATEROLE can rename a role for which they have ADMIN OPTION.
1415 : */
1416 30 : if (authform->rolsuper)
1417 : {
1418 6 : if (!superuser())
1419 0 : ereport(ERROR,
1420 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1421 : errmsg("permission denied to rename role"),
1422 : errdetail("Only roles with the %s attribute may rename roles with the %s attribute.",
1423 : "SUPERUSER", "SUPERUSER")));
1424 : }
1425 : else
1426 : {
1427 24 : if (!have_createrole_privilege() ||
1428 24 : !is_admin_of_role(GetUserId(), roleid))
1429 6 : ereport(ERROR,
1430 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1431 : errmsg("permission denied to rename role"),
1432 : errdetail("Only roles with the %s attribute and the %s option on role \"%s\" may rename this role.",
1433 : "CREATEROLE", "ADMIN", NameStr(authform->rolname))));
1434 : }
1435 :
1436 : /* OK, construct the modified tuple */
1437 312 : for (i = 0; i < Natts_pg_authid; i++)
1438 288 : repl_repl[i] = false;
1439 :
1440 24 : repl_repl[Anum_pg_authid_rolname - 1] = true;
1441 24 : repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
1442 : CStringGetDatum(newname));
1443 24 : repl_null[Anum_pg_authid_rolname - 1] = false;
1444 :
1445 24 : datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
1446 :
1447 24 : if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
1448 : {
1449 : /* MD5 uses the username as salt, so just clear it on a rename */
1450 6 : repl_repl[Anum_pg_authid_rolpassword - 1] = true;
1451 6 : repl_null[Anum_pg_authid_rolpassword - 1] = true;
1452 :
1453 6 : ereport(NOTICE,
1454 : (errmsg("MD5 password cleared because of role rename")));
1455 : }
1456 :
1457 24 : newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
1458 24 : CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple);
1459 :
1460 24 : InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
1461 :
1462 24 : ObjectAddressSet(address, AuthIdRelationId, roleid);
1463 :
1464 24 : ReleaseSysCache(oldtuple);
1465 :
1466 : /*
1467 : * Close pg_authid, but keep lock till commit.
1468 : */
1469 24 : table_close(rel, NoLock);
1470 :
1471 24 : return address;
1472 : }
1473 :
1474 : /*
1475 : * GrantRoleStmt
1476 : *
1477 : * Grant/Revoke roles to/from roles
1478 : */
1479 : void
1480 886 : GrantRole(ParseState *pstate, GrantRoleStmt *stmt)
1481 : {
1482 : Relation pg_authid_rel;
1483 : Oid grantor;
1484 : List *grantee_ids;
1485 : ListCell *item;
1486 : GrantRoleOptions popt;
1487 886 : Oid currentUserId = GetUserId();
1488 :
1489 : /* Parse options list. */
1490 886 : InitGrantRoleOptions(&popt);
1491 1250 : foreach(item, stmt->opt)
1492 : {
1493 364 : DefElem *opt = (DefElem *) lfirst(item);
1494 364 : char *optval = defGetString(opt);
1495 :
1496 364 : if (strcmp(opt->defname, "admin") == 0)
1497 : {
1498 188 : popt.specified |= GRANT_ROLE_SPECIFIED_ADMIN;
1499 :
1500 188 : if (parse_bool(optval, &popt.admin))
1501 188 : continue;
1502 : }
1503 176 : else if (strcmp(opt->defname, "inherit") == 0)
1504 : {
1505 94 : popt.specified |= GRANT_ROLE_SPECIFIED_INHERIT;
1506 94 : if (parse_bool(optval, &popt.inherit))
1507 94 : continue;
1508 : }
1509 82 : else if (strcmp(opt->defname, "set") == 0)
1510 : {
1511 82 : popt.specified |= GRANT_ROLE_SPECIFIED_SET;
1512 82 : if (parse_bool(optval, &popt.set))
1513 82 : continue;
1514 : }
1515 : else
1516 0 : ereport(ERROR,
1517 : errcode(ERRCODE_SYNTAX_ERROR),
1518 : errmsg("unrecognized role option \"%s\"", opt->defname),
1519 : parser_errposition(pstate, opt->location));
1520 :
1521 0 : ereport(ERROR,
1522 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1523 : errmsg("unrecognized value for role option \"%s\": \"%s\"",
1524 : opt->defname, optval),
1525 : parser_errposition(pstate, opt->location)));
1526 : }
1527 :
1528 : /* Lookup OID of grantor, if specified. */
1529 886 : if (stmt->grantor)
1530 120 : grantor = get_rolespec_oid(stmt->grantor, false);
1531 : else
1532 766 : grantor = InvalidOid;
1533 :
1534 880 : grantee_ids = roleSpecsToIds(stmt->grantee_roles);
1535 :
1536 : /* AccessShareLock is enough since we aren't modifying pg_authid */
1537 880 : pg_authid_rel = table_open(AuthIdRelationId, AccessShareLock);
1538 :
1539 : /*
1540 : * Step through all of the granted roles and add, update, or remove
1541 : * entries in pg_auth_members as appropriate. If stmt->is_grant is true,
1542 : * we are adding new grants or, if they already exist, updating options on
1543 : * those grants. If stmt->is_grant is false, we are revoking grants or
1544 : * removing options from them.
1545 : */
1546 1642 : foreach(item, stmt->granted_roles)
1547 : {
1548 882 : AccessPriv *priv = (AccessPriv *) lfirst(item);
1549 882 : char *rolename = priv->priv_name;
1550 : Oid roleid;
1551 :
1552 : /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
1553 882 : if (rolename == NULL || priv->cols != NIL)
1554 0 : ereport(ERROR,
1555 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1556 : errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
1557 :
1558 882 : roleid = get_role_oid(rolename, false);
1559 882 : check_role_membership_authorization(currentUserId,
1560 882 : roleid, stmt->is_grant);
1561 792 : if (stmt->is_grant)
1562 642 : AddRoleMems(currentUserId, rolename, roleid,
1563 : stmt->grantee_roles, grantee_ids,
1564 : grantor, &popt);
1565 : else
1566 150 : DelRoleMems(currentUserId, rolename, roleid,
1567 : stmt->grantee_roles, grantee_ids,
1568 : grantor, &popt, stmt->behavior);
1569 : }
1570 :
1571 : /*
1572 : * Close pg_authid, but keep lock till commit.
1573 : */
1574 760 : table_close(pg_authid_rel, NoLock);
1575 760 : }
1576 :
1577 : /*
1578 : * DropOwnedObjects
1579 : *
1580 : * Drop the objects owned by a given list of roles.
1581 : */
1582 : void
1583 148 : DropOwnedObjects(DropOwnedStmt *stmt)
1584 : {
1585 148 : List *role_ids = roleSpecsToIds(stmt->roles);
1586 : ListCell *cell;
1587 :
1588 : /* Check privileges */
1589 314 : foreach(cell, role_ids)
1590 : {
1591 178 : Oid roleid = lfirst_oid(cell);
1592 :
1593 178 : if (!has_privs_of_role(GetUserId(), roleid))
1594 12 : ereport(ERROR,
1595 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1596 : errmsg("permission denied to drop objects"),
1597 : errdetail("Only roles with privileges of role \"%s\" may drop objects owned by it.",
1598 : GetUserNameFromId(roleid, false))));
1599 : }
1600 :
1601 : /* Ok, do it */
1602 136 : shdepDropOwned(role_ids, stmt->behavior);
1603 130 : }
1604 :
1605 : /*
1606 : * ReassignOwnedObjects
1607 : *
1608 : * Give the objects owned by a given list of roles away to another user.
1609 : */
1610 : void
1611 40 : ReassignOwnedObjects(ReassignOwnedStmt *stmt)
1612 : {
1613 40 : List *role_ids = roleSpecsToIds(stmt->roles);
1614 : ListCell *cell;
1615 : Oid newrole;
1616 :
1617 : /* Check privileges */
1618 68 : foreach(cell, role_ids)
1619 : {
1620 40 : Oid roleid = lfirst_oid(cell);
1621 :
1622 40 : if (!has_privs_of_role(GetUserId(), roleid))
1623 12 : ereport(ERROR,
1624 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1625 : errmsg("permission denied to reassign objects"),
1626 : errdetail("Only roles with privileges of role \"%s\" may reassign objects owned by it.",
1627 : GetUserNameFromId(roleid, false))));
1628 : }
1629 :
1630 : /* Must have privileges on the receiving side too */
1631 28 : newrole = get_rolespec_oid(stmt->newrole, false);
1632 :
1633 28 : if (!has_privs_of_role(GetUserId(), newrole))
1634 6 : ereport(ERROR,
1635 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1636 : errmsg("permission denied to reassign objects"),
1637 : errdetail("Only roles with privileges of role \"%s\" may reassign objects to it.",
1638 : GetUserNameFromId(newrole, false))));
1639 :
1640 : /* Ok, do it */
1641 22 : shdepReassignOwned(role_ids, newrole);
1642 22 : }
1643 :
1644 : /*
1645 : * roleSpecsToIds
1646 : *
1647 : * Given a list of RoleSpecs, generate a list of role OIDs in the same order.
1648 : *
1649 : * ROLESPEC_PUBLIC is not allowed.
1650 : */
1651 : List *
1652 4378 : roleSpecsToIds(List *memberNames)
1653 : {
1654 4378 : List *result = NIL;
1655 : ListCell *l;
1656 :
1657 5638 : foreach(l, memberNames)
1658 : {
1659 1260 : RoleSpec *rolespec = lfirst_node(RoleSpec, l);
1660 : Oid roleid;
1661 :
1662 1260 : roleid = get_rolespec_oid(rolespec, false);
1663 1260 : result = lappend_oid(result, roleid);
1664 : }
1665 4378 : return result;
1666 : }
1667 :
1668 : /*
1669 : * AddRoleMems -- Add given members to the specified role
1670 : *
1671 : * currentUserId: OID of role performing the operation
1672 : * rolename: name of role to add to (used only for error messages)
1673 : * roleid: OID of role to add to
1674 : * memberSpecs: list of RoleSpec of roles to add (used only for error messages)
1675 : * memberIds: OIDs of roles to add
1676 : * grantorId: OID that should be recorded as having granted the membership
1677 : * (InvalidOid if not set explicitly)
1678 : * popt: information about grant options
1679 : */
1680 : static void
1681 4064 : AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
1682 : List *memberSpecs, List *memberIds,
1683 : Oid grantorId, GrantRoleOptions *popt)
1684 : {
1685 : Relation pg_authmem_rel;
1686 : TupleDesc pg_authmem_dsc;
1687 : ListCell *specitem;
1688 : ListCell *iditem;
1689 :
1690 : Assert(list_length(memberSpecs) == list_length(memberIds));
1691 :
1692 : /* Validate grantor (and resolve implicit grantor if not specified). */
1693 4064 : grantorId = check_role_grantor(currentUserId, roleid, grantorId, true);
1694 :
1695 4058 : pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1696 4058 : pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1697 :
1698 : /*
1699 : * Only allow changes to this role by one backend at a time, so that we
1700 : * can check integrity constraints like the lack of circular ADMIN OPTION
1701 : * grants without fear of race conditions.
1702 : */
1703 4058 : LockSharedObject(AuthIdRelationId, roleid, 0,
1704 : ShareUpdateExclusiveLock);
1705 :
1706 : /* Preliminary sanity checks. */
1707 4980 : forboth(specitem, memberSpecs, iditem, memberIds)
1708 : {
1709 940 : RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
1710 940 : Oid memberid = lfirst_oid(iditem);
1711 :
1712 : /*
1713 : * pg_database_owner is never a role member. Lifting this restriction
1714 : * would require a policy decision about membership loops. One could
1715 : * prevent loops, which would include making "ALTER DATABASE x OWNER
1716 : * TO proposed_datdba" fail if is_member_of_role(pg_database_owner,
1717 : * proposed_datdba). Hence, gaining a membership could reduce what a
1718 : * role could do. Alternately, one could allow these memberships to
1719 : * complete loops. A role could then have actual WITH ADMIN OPTION on
1720 : * itself, prompting a decision about is_admin_of_role() treatment of
1721 : * the case.
1722 : *
1723 : * Lifting this restriction also has policy implications for ownership
1724 : * of shared objects (databases and tablespaces). We allow such
1725 : * ownership, but we might find cause to ban it in the future.
1726 : * Designing such a ban would more troublesome if the design had to
1727 : * address pg_database_owner being a member of role FOO that owns a
1728 : * shared object. (The effect of such ownership is that any owner of
1729 : * another database can act as the owner of affected shared objects.)
1730 : */
1731 940 : if (memberid == ROLE_PG_DATABASE_OWNER)
1732 6 : ereport(ERROR,
1733 : errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1734 : errmsg("role \"%s\" cannot be a member of any role",
1735 : get_rolespec_name(memberRole)));
1736 :
1737 : /*
1738 : * Refuse creation of membership loops, including the trivial case
1739 : * where a role is made a member of itself. We do this by checking to
1740 : * see if the target role is already a member of the proposed member
1741 : * role. We have to ignore possible superuserness, however, else we
1742 : * could never grant membership in a superuser-privileged role.
1743 : */
1744 934 : if (is_member_of_role_nosuper(roleid, memberid))
1745 12 : ereport(ERROR,
1746 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1747 : errmsg("role \"%s\" is a member of role \"%s\"",
1748 : rolename, get_rolespec_name(memberRole))));
1749 : }
1750 :
1751 : /*
1752 : * Disallow attempts to grant ADMIN OPTION back to a user who granted it
1753 : * to you, similar to what check_circularity does for ACLs. We want the
1754 : * chains of grants to remain acyclic, so that it's always possible to use
1755 : * REVOKE .. CASCADE to clean up all grants that depend on the one being
1756 : * revoked.
1757 : *
1758 : * NB: This check might look redundant with the check for membership loops
1759 : * above, but it isn't. That's checking for role-member loop (e.g. A is a
1760 : * member of B and B is a member of A) while this is checking for a
1761 : * member-grantor loop (e.g. A gave ADMIN OPTION on X to B and now B, who
1762 : * has no other source of ADMIN OPTION on X, tries to give ADMIN OPTION on
1763 : * X back to A).
1764 : */
1765 4040 : if (popt->admin && grantorId != BOOTSTRAP_SUPERUSERID)
1766 : {
1767 : CatCList *memlist;
1768 : RevokeRoleGrantAction *actions;
1769 : int i;
1770 :
1771 : /* Get the list of members for this role. */
1772 144 : memlist = SearchSysCacheList1(AUTHMEMROLEMEM,
1773 : ObjectIdGetDatum(roleid));
1774 :
1775 : /*
1776 : * Figure out what would happen if we removed all existing grants to
1777 : * every role to which we've been asked to make a new grant.
1778 : */
1779 144 : actions = initialize_revoke_actions(memlist);
1780 228 : foreach(iditem, memberIds)
1781 : {
1782 84 : Oid memberid = lfirst_oid(iditem);
1783 :
1784 84 : if (memberid == BOOTSTRAP_SUPERUSERID)
1785 0 : ereport(ERROR,
1786 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1787 : errmsg("%s option cannot be granted back to your own grantor",
1788 : "ADMIN")));
1789 84 : plan_member_revoke(memlist, actions, memberid);
1790 : }
1791 :
1792 : /*
1793 : * If the result would be that the grantor role would no longer have
1794 : * the ability to perform the grant, then the proposed grant would
1795 : * create a circularity.
1796 : */
1797 174 : for (i = 0; i < memlist->n_members; ++i)
1798 : {
1799 : HeapTuple authmem_tuple;
1800 : Form_pg_auth_members authmem_form;
1801 :
1802 168 : authmem_tuple = &memlist->members[i]->tuple;
1803 168 : authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
1804 :
1805 168 : if (actions[i] == RRG_NOOP &&
1806 156 : authmem_form->member == grantorId &&
1807 138 : authmem_form->admin_option)
1808 138 : break;
1809 : }
1810 144 : if (i >= memlist->n_members)
1811 6 : ereport(ERROR,
1812 : (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1813 : errmsg("%s option cannot be granted back to your own grantor",
1814 : "ADMIN")));
1815 :
1816 138 : ReleaseSysCacheList(memlist);
1817 : }
1818 :
1819 : /* Now perform the catalog updates. */
1820 4950 : forboth(specitem, memberSpecs, iditem, memberIds)
1821 : {
1822 916 : RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
1823 916 : Oid memberid = lfirst_oid(iditem);
1824 : HeapTuple authmem_tuple;
1825 : HeapTuple tuple;
1826 916 : Datum new_record[Natts_pg_auth_members] = {0};
1827 916 : bool new_record_nulls[Natts_pg_auth_members] = {0};
1828 916 : bool new_record_repl[Natts_pg_auth_members] = {0};
1829 :
1830 : /* Common initialization for possible insert or update */
1831 916 : new_record[Anum_pg_auth_members_roleid - 1] =
1832 916 : ObjectIdGetDatum(roleid);
1833 916 : new_record[Anum_pg_auth_members_member - 1] =
1834 916 : ObjectIdGetDatum(memberid);
1835 916 : new_record[Anum_pg_auth_members_grantor - 1] =
1836 916 : ObjectIdGetDatum(grantorId);
1837 :
1838 : /* Find any existing tuple */
1839 916 : authmem_tuple = SearchSysCache3(AUTHMEMROLEMEM,
1840 : ObjectIdGetDatum(roleid),
1841 : ObjectIdGetDatum(memberid),
1842 : ObjectIdGetDatum(grantorId));
1843 :
1844 : /*
1845 : * If we found a tuple, update it with new option values, unless there
1846 : * are no changes, in which case issue a WARNING.
1847 : *
1848 : * If we didn't find a tuple, just insert one.
1849 : */
1850 916 : if (HeapTupleIsValid(authmem_tuple))
1851 : {
1852 : Form_pg_auth_members authmem_form;
1853 34 : bool at_least_one_change = false;
1854 :
1855 34 : authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
1856 :
1857 34 : if ((popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0
1858 0 : && authmem_form->admin_option != popt->admin)
1859 : {
1860 0 : new_record[Anum_pg_auth_members_admin_option - 1] =
1861 0 : BoolGetDatum(popt->admin);
1862 0 : new_record_repl[Anum_pg_auth_members_admin_option - 1] =
1863 : true;
1864 0 : at_least_one_change = true;
1865 : }
1866 :
1867 34 : if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0
1868 16 : && authmem_form->inherit_option != popt->inherit)
1869 : {
1870 16 : new_record[Anum_pg_auth_members_inherit_option - 1] =
1871 16 : BoolGetDatum(popt->inherit);
1872 16 : new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
1873 : true;
1874 16 : at_least_one_change = true;
1875 : }
1876 :
1877 34 : if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0
1878 10 : && authmem_form->set_option != popt->set)
1879 : {
1880 10 : new_record[Anum_pg_auth_members_set_option - 1] =
1881 10 : BoolGetDatum(popt->set);
1882 10 : new_record_repl[Anum_pg_auth_members_set_option - 1] =
1883 : true;
1884 10 : at_least_one_change = true;
1885 : }
1886 :
1887 34 : if (!at_least_one_change)
1888 : {
1889 18 : ereport(NOTICE,
1890 : (errmsg("role \"%s\" has already been granted membership in role \"%s\" by role \"%s\"",
1891 : get_rolespec_name(memberRole), rolename,
1892 : GetUserNameFromId(grantorId, false))));
1893 18 : ReleaseSysCache(authmem_tuple);
1894 18 : continue;
1895 : }
1896 :
1897 16 : tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1898 : new_record,
1899 : new_record_nulls, new_record_repl);
1900 16 : CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
1901 :
1902 16 : ReleaseSysCache(authmem_tuple);
1903 : }
1904 : else
1905 : {
1906 : Oid objectId;
1907 882 : Oid *newmembers = palloc(sizeof(Oid));
1908 :
1909 : /*
1910 : * The values for these options can be taken directly from 'popt'.
1911 : * Either they were specified, or the defaults as set by
1912 : * InitGrantRoleOptions are correct.
1913 : */
1914 882 : new_record[Anum_pg_auth_members_admin_option - 1] =
1915 882 : BoolGetDatum(popt->admin);
1916 882 : new_record[Anum_pg_auth_members_set_option - 1] =
1917 882 : BoolGetDatum(popt->set);
1918 :
1919 : /*
1920 : * If the user specified a value for the inherit option, use
1921 : * whatever was specified. Otherwise, set the default value based
1922 : * on the role-level property.
1923 : */
1924 882 : if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
1925 194 : new_record[Anum_pg_auth_members_inherit_option - 1] =
1926 194 : popt->inherit;
1927 : else
1928 : {
1929 : HeapTuple mrtup;
1930 : Form_pg_authid mrform;
1931 :
1932 688 : mrtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(memberid));
1933 688 : if (!HeapTupleIsValid(mrtup))
1934 0 : elog(ERROR, "cache lookup failed for role %u", memberid);
1935 688 : mrform = (Form_pg_authid) GETSTRUCT(mrtup);
1936 688 : new_record[Anum_pg_auth_members_inherit_option - 1] =
1937 688 : mrform->rolinherit;
1938 688 : ReleaseSysCache(mrtup);
1939 : }
1940 :
1941 : /* get an OID for the new row and insert it */
1942 882 : objectId = GetNewOidWithIndex(pg_authmem_rel, AuthMemOidIndexId,
1943 : Anum_pg_auth_members_oid);
1944 882 : new_record[Anum_pg_auth_members_oid - 1] = objectId;
1945 882 : tuple = heap_form_tuple(pg_authmem_dsc,
1946 : new_record, new_record_nulls);
1947 882 : CatalogTupleInsert(pg_authmem_rel, tuple);
1948 :
1949 : /* updateAclDependencies wants to pfree array inputs */
1950 882 : newmembers[0] = grantorId;
1951 882 : updateAclDependencies(AuthMemRelationId, objectId,
1952 : 0, InvalidOid,
1953 : 0, NULL,
1954 : 1, newmembers);
1955 : }
1956 :
1957 : /* CCI after each change, in case there are duplicates in list */
1958 898 : CommandCounterIncrement();
1959 : }
1960 :
1961 : /*
1962 : * Close pg_authmem, but keep lock till commit.
1963 : */
1964 4034 : table_close(pg_authmem_rel, NoLock);
1965 4034 : }
1966 :
1967 : /*
1968 : * DelRoleMems -- Remove given members from the specified role
1969 : *
1970 : * rolename: name of role to del from (used only for error messages)
1971 : * roleid: OID of role to del from
1972 : * memberSpecs: list of RoleSpec of roles to del (used only for error messages)
1973 : * memberIds: OIDs of roles to del
1974 : * grantorId: who is revoking the membership
1975 : * popt: information about grant options
1976 : * behavior: RESTRICT or CASCADE behavior for recursive removal
1977 : */
1978 : static void
1979 162 : DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
1980 : List *memberSpecs, List *memberIds,
1981 : Oid grantorId, GrantRoleOptions *popt, DropBehavior behavior)
1982 : {
1983 : Relation pg_authmem_rel;
1984 : TupleDesc pg_authmem_dsc;
1985 : ListCell *specitem;
1986 : ListCell *iditem;
1987 : CatCList *memlist;
1988 : RevokeRoleGrantAction *actions;
1989 : int i;
1990 :
1991 : Assert(list_length(memberSpecs) == list_length(memberIds));
1992 :
1993 : /* Validate grantor (and resolve implicit grantor if not specified). */
1994 162 : grantorId = check_role_grantor(currentUserId, roleid, grantorId, false);
1995 :
1996 162 : pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1997 162 : pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1998 :
1999 : /*
2000 : * Only allow changes to this role by one backend at a time, so that we
2001 : * can check for things like dependent privileges without fear of race
2002 : * conditions.
2003 : */
2004 162 : LockSharedObject(AuthIdRelationId, roleid, 0,
2005 : ShareUpdateExclusiveLock);
2006 :
2007 162 : memlist = SearchSysCacheList1(AUTHMEMROLEMEM, ObjectIdGetDatum(roleid));
2008 162 : actions = initialize_revoke_actions(memlist);
2009 :
2010 : /*
2011 : * We may need to recurse to dependent privileges if DROP_CASCADE was
2012 : * specified, or refuse to perform the operation if dependent privileges
2013 : * exist and DROP_RESTRICT was specified. plan_single_revoke() will figure
2014 : * out what to do with each catalog tuple.
2015 : */
2016 312 : forboth(specitem, memberSpecs, iditem, memberIds)
2017 : {
2018 162 : RoleSpec *memberRole = lfirst(specitem);
2019 162 : Oid memberid = lfirst_oid(iditem);
2020 :
2021 162 : if (!plan_single_revoke(memlist, actions, memberid, grantorId,
2022 : popt, behavior))
2023 : {
2024 6 : ereport(WARNING,
2025 : (errmsg("role \"%s\" has not been granted membership in role \"%s\" by role \"%s\"",
2026 : get_rolespec_name(memberRole), rolename,
2027 : GetUserNameFromId(grantorId, false))));
2028 6 : continue;
2029 : }
2030 : }
2031 :
2032 : /*
2033 : * We now know what to do with each catalog tuple: it should either be
2034 : * left alone, deleted, or just have the admin_option flag cleared.
2035 : * Perform the appropriate action in each case.
2036 : */
2037 436 : for (i = 0; i < memlist->n_members; ++i)
2038 : {
2039 : HeapTuple authmem_tuple;
2040 : Form_pg_auth_members authmem_form;
2041 :
2042 286 : if (actions[i] == RRG_NOOP)
2043 124 : continue;
2044 :
2045 162 : authmem_tuple = &memlist->members[i]->tuple;
2046 162 : authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
2047 :
2048 162 : if (actions[i] == RRG_DELETE_GRANT)
2049 : {
2050 : /*
2051 : * Remove the entry altogether, after first removing its
2052 : * dependencies
2053 : */
2054 114 : deleteSharedDependencyRecordsFor(AuthMemRelationId,
2055 : authmem_form->oid, 0);
2056 114 : CatalogTupleDelete(pg_authmem_rel, &authmem_tuple->t_self);
2057 : }
2058 : else
2059 : {
2060 : /* Just turn off the specified option */
2061 : HeapTuple tuple;
2062 48 : Datum new_record[Natts_pg_auth_members] = {0};
2063 48 : bool new_record_nulls[Natts_pg_auth_members] = {0};
2064 48 : bool new_record_repl[Natts_pg_auth_members] = {0};
2065 :
2066 : /* Build a tuple to update with */
2067 48 : if (actions[i] == RRG_REMOVE_ADMIN_OPTION)
2068 : {
2069 30 : new_record[Anum_pg_auth_members_admin_option - 1] =
2070 30 : BoolGetDatum(false);
2071 30 : new_record_repl[Anum_pg_auth_members_admin_option - 1] =
2072 : true;
2073 : }
2074 18 : else if (actions[i] == RRG_REMOVE_INHERIT_OPTION)
2075 : {
2076 12 : new_record[Anum_pg_auth_members_inherit_option - 1] =
2077 12 : BoolGetDatum(false);
2078 12 : new_record_repl[Anum_pg_auth_members_inherit_option - 1] =
2079 : true;
2080 : }
2081 6 : else if (actions[i] == RRG_REMOVE_SET_OPTION)
2082 : {
2083 6 : new_record[Anum_pg_auth_members_set_option - 1] =
2084 6 : BoolGetDatum(false);
2085 6 : new_record_repl[Anum_pg_auth_members_set_option - 1] =
2086 : true;
2087 : }
2088 : else
2089 0 : elog(ERROR, "unknown role revoke action");
2090 :
2091 48 : tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
2092 : new_record,
2093 : new_record_nulls, new_record_repl);
2094 48 : CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
2095 : }
2096 : }
2097 :
2098 150 : ReleaseSysCacheList(memlist);
2099 :
2100 : /*
2101 : * Close pg_authmem, but keep lock till commit.
2102 : */
2103 150 : table_close(pg_authmem_rel, NoLock);
2104 150 : }
2105 :
2106 : /*
2107 : * Check that currentUserId has permission to modify the membership list for
2108 : * roleid. Throw an error if not.
2109 : */
2110 : static void
2111 982 : check_role_membership_authorization(Oid currentUserId, Oid roleid,
2112 : bool is_grant)
2113 : {
2114 : /*
2115 : * The charter of pg_database_owner is to have exactly one, implicit,
2116 : * situation-dependent member. There's no technical need for this
2117 : * restriction. (One could lift it and take the further step of making
2118 : * object_ownercheck(DatabaseRelationId, ...) equivalent to
2119 : * has_privs_of_role(roleid, ROLE_PG_DATABASE_OWNER), in which case
2120 : * explicit, situation-independent members could act as the owner of any
2121 : * database.)
2122 : */
2123 982 : if (is_grant && roleid == ROLE_PG_DATABASE_OWNER)
2124 12 : ereport(ERROR,
2125 : errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2126 : errmsg("role \"%s\" cannot have explicit members",
2127 : GetUserNameFromId(roleid, false)));
2128 :
2129 : /* To mess with a superuser role, you gotta be superuser. */
2130 970 : if (superuser_arg(roleid))
2131 : {
2132 16 : if (!superuser_arg(currentUserId))
2133 : {
2134 6 : if (is_grant)
2135 6 : ereport(ERROR,
2136 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2137 : errmsg("permission denied to grant role \"%s\"",
2138 : GetUserNameFromId(roleid, false)),
2139 : errdetail("Only roles with the %s attribute may grant roles with the %s attribute.",
2140 : "SUPERUSER", "SUPERUSER")));
2141 : else
2142 0 : ereport(ERROR,
2143 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2144 : errmsg("permission denied to revoke role \"%s\"",
2145 : GetUserNameFromId(roleid, false)),
2146 : errdetail("Only roles with the %s attribute may revoke roles with the %s attribute.",
2147 : "SUPERUSER", "SUPERUSER")));
2148 : }
2149 : }
2150 : else
2151 : {
2152 : /*
2153 : * Otherwise, must have admin option on the role to be changed.
2154 : */
2155 954 : if (!is_admin_of_role(currentUserId, roleid))
2156 : {
2157 144 : if (is_grant)
2158 144 : ereport(ERROR,
2159 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2160 : errmsg("permission denied to grant role \"%s\"",
2161 : GetUserNameFromId(roleid, false)),
2162 : errdetail("Only roles with the %s option on role \"%s\" may grant this role.",
2163 : "ADMIN", GetUserNameFromId(roleid, false))));
2164 : else
2165 0 : ereport(ERROR,
2166 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2167 : errmsg("permission denied to revoke role \"%s\"",
2168 : GetUserNameFromId(roleid, false)),
2169 : errdetail("Only roles with the %s option on role \"%s\" may revoke this role.",
2170 : "ADMIN", GetUserNameFromId(roleid, false))));
2171 : }
2172 : }
2173 820 : }
2174 :
2175 : /*
2176 : * Sanity-check, or infer, the grantor for a GRANT or REVOKE statement
2177 : * targeting a role.
2178 : *
2179 : * The grantor must always be either a role with ADMIN OPTION on the role in
2180 : * which membership is being granted, or the bootstrap superuser. This is
2181 : * similar to the restriction enforced by select_best_grantor, except that
2182 : * roles don't have owners, so we regard the bootstrap superuser as the
2183 : * implicit owner.
2184 : *
2185 : * If the grantor was not explicitly specified by the user, grantorId should
2186 : * be passed as InvalidOid, and this function will infer the user to be
2187 : * recorded as the grantor. In many cases, this will be the current user, but
2188 : * things get more complicated when the current user doesn't possess ADMIN
2189 : * OPTION on the role but rather relies on having SUPERUSER privileges, or
2190 : * on inheriting the privileges of a role which does have ADMIN OPTION. See
2191 : * below for details.
2192 : *
2193 : * If the grantor was specified by the user, then it must be a user that
2194 : * can legally be recorded as the grantor, as per the rule stated above.
2195 : * This is an integrity constraint, not a permissions check, and thus even
2196 : * superusers are subject to this restriction. However, there is also a
2197 : * permissions check: to specify a role as the grantor, the current user
2198 : * must possess the privileges of that role. Superusers will always pass
2199 : * this check, but for non-superusers it may lead to an error.
2200 : *
2201 : * The return value is the OID to be regarded as the grantor when executing
2202 : * the operation.
2203 : */
2204 : static Oid
2205 4226 : check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
2206 : {
2207 : /* If the grantor ID was not specified, pick one to use. */
2208 4226 : if (!OidIsValid(grantorId))
2209 : {
2210 : /*
2211 : * Grants where the grantor is recorded as the bootstrap superuser do
2212 : * not depend on any other existing grants, so always default to this
2213 : * interpretation when possible.
2214 : */
2215 3986 : if (superuser_arg(currentUserId))
2216 3650 : return BOOTSTRAP_SUPERUSERID;
2217 :
2218 : /*
2219 : * Otherwise, the grantor must either have ADMIN OPTION on the role or
2220 : * inherit the privileges of a role which does. In the former case,
2221 : * record the grantor as the current user; in the latter, pick one of
2222 : * the roles that is "most directly" inherited by the current role
2223 : * (i.e. fewest "hops").
2224 : *
2225 : * (We shouldn't fail to find a best grantor, because we've already
2226 : * established that the current user has permission to perform the
2227 : * operation.)
2228 : */
2229 336 : grantorId = select_best_admin(currentUserId, roleid);
2230 336 : if (!OidIsValid(grantorId))
2231 0 : elog(ERROR, "no possible grantors");
2232 336 : return grantorId;
2233 : }
2234 :
2235 : /*
2236 : * If an explicit grantor is specified, it must be a role whose privileges
2237 : * the current user possesses.
2238 : *
2239 : * It should also be a role that has ADMIN OPTION on the target role, but
2240 : * we check this condition only in case of GRANT. For REVOKE, no matching
2241 : * grant should exist anyway, but if it somehow does, let the user get rid
2242 : * of it.
2243 : */
2244 240 : if (is_grant)
2245 : {
2246 216 : if (!has_privs_of_role(currentUserId, grantorId))
2247 0 : ereport(ERROR,
2248 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2249 : errmsg("permission denied to grant privileges as role \"%s\"",
2250 : GetUserNameFromId(grantorId, false)),
2251 : errdetail("Only roles with privileges of role \"%s\" may grant privileges as this role.",
2252 : GetUserNameFromId(grantorId, false))));
2253 :
2254 306 : if (grantorId != BOOTSTRAP_SUPERUSERID &&
2255 90 : select_best_admin(grantorId, roleid) != grantorId)
2256 6 : ereport(ERROR,
2257 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2258 : errmsg("permission denied to grant privileges as role \"%s\"",
2259 : GetUserNameFromId(grantorId, false)),
2260 : errdetail("The grantor must have the %s option on role \"%s\".",
2261 : "ADMIN", GetUserNameFromId(roleid, false))));
2262 : }
2263 : else
2264 : {
2265 24 : if (!has_privs_of_role(currentUserId, grantorId))
2266 0 : ereport(ERROR,
2267 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2268 : errmsg("permission denied to revoke privileges granted by role \"%s\"",
2269 : GetUserNameFromId(grantorId, false)),
2270 : errdetail("Only roles with privileges of role \"%s\" may revoke privileges granted by this role.",
2271 : GetUserNameFromId(grantorId, false))));
2272 : }
2273 :
2274 : /*
2275 : * If a grantor was specified explicitly, always attribute the grant to
2276 : * that role (unless we error out above).
2277 : */
2278 234 : return grantorId;
2279 : }
2280 :
2281 : /*
2282 : * Initialize an array of RevokeRoleGrantAction objects.
2283 : *
2284 : * 'memlist' should be a list of all grants for the target role.
2285 : *
2286 : * This constructs an array indicating that no actions are to be performed;
2287 : * that is, every element is initially RRG_NOOP.
2288 : */
2289 : static RevokeRoleGrantAction *
2290 306 : initialize_revoke_actions(CatCList *memlist)
2291 : {
2292 : RevokeRoleGrantAction *result;
2293 : int i;
2294 :
2295 306 : if (memlist->n_members == 0)
2296 0 : return NULL;
2297 :
2298 306 : result = palloc(sizeof(RevokeRoleGrantAction) * memlist->n_members);
2299 832 : for (i = 0; i < memlist->n_members; i++)
2300 526 : result[i] = RRG_NOOP;
2301 306 : return result;
2302 : }
2303 :
2304 : /*
2305 : * Figure out what we would need to do in order to revoke a grant, or just the
2306 : * admin option on a grant, given that there might be dependent privileges.
2307 : *
2308 : * 'memlist' should be a list of all grants for the target role.
2309 : *
2310 : * Whatever actions prove to be necessary will be signalled by updating
2311 : * 'actions'.
2312 : *
2313 : * If behavior is DROP_RESTRICT, an error will occur if there are dependent
2314 : * role membership grants; if DROP_CASCADE, those grants will be scheduled
2315 : * for deletion.
2316 : *
2317 : * The return value is true if the matching grant was found in the list,
2318 : * and false if not.
2319 : */
2320 : static bool
2321 162 : plan_single_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
2322 : Oid member, Oid grantor, GrantRoleOptions *popt,
2323 : DropBehavior behavior)
2324 : {
2325 : int i;
2326 :
2327 : /*
2328 : * If popt.specified == 0, we're revoking the grant entirely; otherwise,
2329 : * we expect just one bit to be set, and we're revoking the corresponding
2330 : * option. As of this writing, there's no syntax that would allow for an
2331 : * attempt to revoke multiple options at once, and the logic below
2332 : * wouldn't work properly if such syntax were added, so assert that our
2333 : * caller isn't trying to do that.
2334 : */
2335 : Assert(pg_popcount32(popt->specified) <= 1);
2336 :
2337 280 : for (i = 0; i < memlist->n_members; ++i)
2338 : {
2339 : HeapTuple authmem_tuple;
2340 : Form_pg_auth_members authmem_form;
2341 :
2342 274 : authmem_tuple = &memlist->members[i]->tuple;
2343 274 : authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
2344 :
2345 274 : if (authmem_form->member == member &&
2346 174 : authmem_form->grantor == grantor)
2347 : {
2348 156 : if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
2349 : {
2350 : /*
2351 : * Revoking the INHERIT option doesn't change anything for
2352 : * dependent privileges, so we don't need to recurse.
2353 : */
2354 12 : actions[i] = RRG_REMOVE_INHERIT_OPTION;
2355 : }
2356 144 : else if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0)
2357 : {
2358 : /* Here too, no need to recurse. */
2359 6 : actions[i] = RRG_REMOVE_SET_OPTION;
2360 : }
2361 : else
2362 : {
2363 : bool revoke_admin_option_only;
2364 :
2365 : /*
2366 : * Revoking the grant entirely, or ADMIN option on a grant,
2367 : * implicates dependent privileges, so we may need to recurse.
2368 : */
2369 138 : revoke_admin_option_only =
2370 138 : (popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0;
2371 138 : plan_recursive_revoke(memlist, actions, i,
2372 : revoke_admin_option_only, behavior);
2373 : }
2374 144 : return true;
2375 : }
2376 : }
2377 :
2378 6 : return false;
2379 : }
2380 :
2381 : /*
2382 : * Figure out what we would need to do in order to revoke all grants to
2383 : * a given member, given that there might be dependent privileges.
2384 : *
2385 : * 'memlist' should be a list of all grants for the target role.
2386 : *
2387 : * Whatever actions prove to be necessary will be signalled by updating
2388 : * 'actions'.
2389 : */
2390 : static void
2391 84 : plan_member_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
2392 : Oid member)
2393 : {
2394 : int i;
2395 :
2396 186 : for (i = 0; i < memlist->n_members; ++i)
2397 : {
2398 : HeapTuple authmem_tuple;
2399 : Form_pg_auth_members authmem_form;
2400 :
2401 102 : authmem_tuple = &memlist->members[i]->tuple;
2402 102 : authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
2403 :
2404 102 : if (authmem_form->member == member)
2405 6 : plan_recursive_revoke(memlist, actions, i, false, DROP_CASCADE);
2406 : }
2407 84 : }
2408 :
2409 : /*
2410 : * Workhorse for figuring out recursive revocation of role grants.
2411 : *
2412 : * This is similar to what recursive_revoke() does for ACLs.
2413 : */
2414 : static void
2415 168 : plan_recursive_revoke(CatCList *memlist, RevokeRoleGrantAction *actions,
2416 : int index,
2417 : bool revoke_admin_option_only, DropBehavior behavior)
2418 : {
2419 168 : bool would_still_have_admin_option = false;
2420 : HeapTuple authmem_tuple;
2421 : Form_pg_auth_members authmem_form;
2422 : int i;
2423 :
2424 : /* If it's already been done, we can just return. */
2425 168 : if (actions[index] == RRG_DELETE_GRANT)
2426 0 : return;
2427 168 : if (actions[index] == RRG_REMOVE_ADMIN_OPTION &&
2428 : revoke_admin_option_only)
2429 0 : return;
2430 :
2431 : /* Locate tuple data. */
2432 168 : authmem_tuple = &memlist->members[index]->tuple;
2433 168 : authmem_form = (Form_pg_auth_members) GETSTRUCT(authmem_tuple);
2434 :
2435 : /*
2436 : * If the existing tuple does not have admin_option set, then we do not
2437 : * need to recurse. If we're just supposed to clear that bit we don't need
2438 : * to do anything at all; if we're supposed to remove the grant, we need
2439 : * to do something, but only to the tuple, and not any others.
2440 : */
2441 168 : if (!revoke_admin_option_only)
2442 : {
2443 132 : actions[index] = RRG_DELETE_GRANT;
2444 132 : if (!authmem_form->admin_option)
2445 90 : return;
2446 : }
2447 : else
2448 : {
2449 36 : if (!authmem_form->admin_option)
2450 0 : return;
2451 36 : actions[index] = RRG_REMOVE_ADMIN_OPTION;
2452 : }
2453 :
2454 : /* Determine whether the member would still have ADMIN OPTION. */
2455 228 : for (i = 0; i < memlist->n_members; ++i)
2456 : {
2457 : HeapTuple am_cascade_tuple;
2458 : Form_pg_auth_members am_cascade_form;
2459 :
2460 150 : am_cascade_tuple = &memlist->members[i]->tuple;
2461 150 : am_cascade_form = (Form_pg_auth_members) GETSTRUCT(am_cascade_tuple);
2462 :
2463 150 : if (am_cascade_form->member == authmem_form->member &&
2464 78 : am_cascade_form->admin_option && actions[i] == RRG_NOOP)
2465 : {
2466 0 : would_still_have_admin_option = true;
2467 0 : break;
2468 : }
2469 : }
2470 :
2471 : /* If the member would still have ADMIN OPTION, we need not recurse. */
2472 78 : if (would_still_have_admin_option)
2473 0 : return;
2474 :
2475 : /*
2476 : * Recurse to grants that are not yet slated for deletion which have this
2477 : * member as the grantor.
2478 : */
2479 216 : for (i = 0; i < memlist->n_members; ++i)
2480 : {
2481 : HeapTuple am_cascade_tuple;
2482 : Form_pg_auth_members am_cascade_form;
2483 :
2484 150 : am_cascade_tuple = &memlist->members[i]->tuple;
2485 150 : am_cascade_form = (Form_pg_auth_members) GETSTRUCT(am_cascade_tuple);
2486 :
2487 150 : if (am_cascade_form->grantor == authmem_form->member &&
2488 36 : actions[i] != RRG_DELETE_GRANT)
2489 : {
2490 36 : if (behavior == DROP_RESTRICT)
2491 12 : ereport(ERROR,
2492 : (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
2493 : errmsg("dependent privileges exist"),
2494 : errhint("Use CASCADE to revoke them too.")));
2495 :
2496 24 : plan_recursive_revoke(memlist, actions, i, false, behavior);
2497 : }
2498 : }
2499 : }
2500 :
2501 : /*
2502 : * Initialize a GrantRoleOptions object with default values.
2503 : */
2504 : static void
2505 2938 : InitGrantRoleOptions(GrantRoleOptions *popt)
2506 : {
2507 2938 : popt->specified = 0;
2508 2938 : popt->admin = false;
2509 2938 : popt->inherit = false;
2510 2938 : popt->set = true;
2511 2938 : }
2512 :
2513 : /*
2514 : * GUC check_hook for createrole_self_grant
2515 : */
2516 : bool
2517 1972 : check_createrole_self_grant(char **newval, void **extra, GucSource source)
2518 : {
2519 : char *rawstring;
2520 : List *elemlist;
2521 : ListCell *l;
2522 1972 : unsigned options = 0;
2523 : unsigned *result;
2524 :
2525 : /* Need a modifiable copy of string */
2526 1972 : rawstring = pstrdup(*newval);
2527 :
2528 1972 : if (!SplitIdentifierString(rawstring, ',', &elemlist))
2529 : {
2530 : /* syntax error in list */
2531 0 : GUC_check_errdetail("List syntax is invalid.");
2532 0 : pfree(rawstring);
2533 0 : list_free(elemlist);
2534 0 : return false;
2535 : }
2536 :
2537 1984 : foreach(l, elemlist)
2538 : {
2539 12 : char *tok = (char *) lfirst(l);
2540 :
2541 12 : if (pg_strcasecmp(tok, "SET") == 0)
2542 6 : options |= GRANT_ROLE_SPECIFIED_SET;
2543 6 : else if (pg_strcasecmp(tok, "INHERIT") == 0)
2544 6 : options |= GRANT_ROLE_SPECIFIED_INHERIT;
2545 : else
2546 : {
2547 0 : GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
2548 0 : pfree(rawstring);
2549 0 : list_free(elemlist);
2550 0 : return false;
2551 : }
2552 : }
2553 :
2554 1972 : pfree(rawstring);
2555 1972 : list_free(elemlist);
2556 :
2557 1972 : result = (unsigned *) guc_malloc(LOG, sizeof(unsigned));
2558 1972 : *result = options;
2559 1972 : *extra = result;
2560 :
2561 1972 : return true;
2562 : }
2563 :
2564 : /*
2565 : * GUC assign_hook for createrole_self_grant
2566 : */
2567 : void
2568 1972 : assign_createrole_self_grant(const char *newval, void *extra)
2569 : {
2570 1972 : unsigned options = *(unsigned *) extra;
2571 :
2572 1972 : createrole_self_grant_enabled = (options != 0);
2573 1972 : createrole_self_grant_options.specified = GRANT_ROLE_SPECIFIED_ADMIN
2574 : | GRANT_ROLE_SPECIFIED_INHERIT
2575 : | GRANT_ROLE_SPECIFIED_SET;
2576 1972 : createrole_self_grant_options.admin = false;
2577 1972 : createrole_self_grant_options.inherit =
2578 1972 : (options & GRANT_ROLE_SPECIFIED_INHERIT) != 0;
2579 1972 : createrole_self_grant_options.set =
2580 1972 : (options & GRANT_ROLE_SPECIFIED_SET) != 0;
2581 1972 : }
|