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