Update copyright for 2022
[pgsql.git] / src / backend / commands / user.c
blobc79c8d247f017fbf6e2da2eb9d107193388b2bd4
1 /*-------------------------------------------------------------------------
3 * user.c
4 * Commands for manipulating roles (formerly called users).
6 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * src/backend/commands/user.c
11 *-------------------------------------------------------------------------
13 #include "postgres.h"
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/fmgroids.h"
39 #include "utils/syscache.h"
40 #include "utils/timestamp.h"
42 /* Potentially set by pg_upgrade_support functions */
43 Oid binary_upgrade_next_pg_authid_oid = InvalidOid;
46 /* GUC parameter */
47 int Password_encryption = PASSWORD_TYPE_SCRAM_SHA_256;
49 /* Hook to check passwords in CreateRole() and AlterRole() */
50 check_password_hook_type check_password_hook = NULL;
52 static void AddRoleMems(const char *rolename, Oid roleid,
53 List *memberSpecs, List *memberIds,
54 Oid grantorId, bool admin_opt);
55 static void DelRoleMems(const char *rolename, Oid roleid,
56 List *memberSpecs, List *memberIds,
57 bool admin_opt);
60 /* Check if current user has createrole privileges */
61 static bool
62 have_createrole_privilege(void)
64 return has_createrole_privilege(GetUserId());
69 * CREATE ROLE
71 Oid
72 CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
74 Relation pg_authid_rel;
75 TupleDesc pg_authid_dsc;
76 HeapTuple tuple;
77 Datum new_record[Natts_pg_authid];
78 bool new_record_nulls[Natts_pg_authid];
79 Oid roleid;
80 ListCell *item;
81 ListCell *option;
82 char *password = NULL; /* user password */
83 bool issuper = false; /* Make the user a superuser? */
84 bool inherit = true; /* Auto inherit privileges? */
85 bool createrole = false; /* Can this user create roles? */
86 bool createdb = false; /* Can the user create databases? */
87 bool canlogin = false; /* Can this user login? */
88 bool isreplication = false; /* Is this a replication role? */
89 bool bypassrls = false; /* Is this a row security enabled role? */
90 int connlimit = -1; /* maximum connections allowed */
91 List *addroleto = NIL; /* roles to make this a member of */
92 List *rolemembers = NIL; /* roles to be members of this role */
93 List *adminmembers = NIL; /* roles to be admins of this role */
94 char *validUntil = NULL; /* time the login is valid until */
95 Datum validUntil_datum; /* same, as timestamptz Datum */
96 bool validUntil_null;
97 DefElem *dpassword = NULL;
98 DefElem *dissuper = NULL;
99 DefElem *dinherit = NULL;
100 DefElem *dcreaterole = NULL;
101 DefElem *dcreatedb = NULL;
102 DefElem *dcanlogin = NULL;
103 DefElem *disreplication = NULL;
104 DefElem *dconnlimit = NULL;
105 DefElem *daddroleto = NULL;
106 DefElem *drolemembers = NULL;
107 DefElem *dadminmembers = NULL;
108 DefElem *dvalidUntil = NULL;
109 DefElem *dbypassRLS = NULL;
111 /* The defaults can vary depending on the original statement type */
112 switch (stmt->stmt_type)
114 case ROLESTMT_ROLE:
115 break;
116 case ROLESTMT_USER:
117 canlogin = true;
118 /* may eventually want inherit to default to false here */
119 break;
120 case ROLESTMT_GROUP:
121 break;
124 /* Extract options from the statement node tree */
125 foreach(option, stmt->options)
127 DefElem *defel = (DefElem *) lfirst(option);
129 if (strcmp(defel->defname, "password") == 0)
131 if (dpassword)
132 errorConflictingDefElem(defel, pstate);
133 dpassword = defel;
135 else if (strcmp(defel->defname, "sysid") == 0)
137 ereport(NOTICE,
138 (errmsg("SYSID can no longer be specified")));
140 else if (strcmp(defel->defname, "superuser") == 0)
142 if (dissuper)
143 errorConflictingDefElem(defel, pstate);
144 dissuper = defel;
146 else if (strcmp(defel->defname, "inherit") == 0)
148 if (dinherit)
149 errorConflictingDefElem(defel, pstate);
150 dinherit = defel;
152 else if (strcmp(defel->defname, "createrole") == 0)
154 if (dcreaterole)
155 errorConflictingDefElem(defel, pstate);
156 dcreaterole = defel;
158 else if (strcmp(defel->defname, "createdb") == 0)
160 if (dcreatedb)
161 errorConflictingDefElem(defel, pstate);
162 dcreatedb = defel;
164 else if (strcmp(defel->defname, "canlogin") == 0)
166 if (dcanlogin)
167 errorConflictingDefElem(defel, pstate);
168 dcanlogin = defel;
170 else if (strcmp(defel->defname, "isreplication") == 0)
172 if (disreplication)
173 errorConflictingDefElem(defel, pstate);
174 disreplication = defel;
176 else if (strcmp(defel->defname, "connectionlimit") == 0)
178 if (dconnlimit)
179 errorConflictingDefElem(defel, pstate);
180 dconnlimit = defel;
182 else if (strcmp(defel->defname, "addroleto") == 0)
184 if (daddroleto)
185 errorConflictingDefElem(defel, pstate);
186 daddroleto = defel;
188 else if (strcmp(defel->defname, "rolemembers") == 0)
190 if (drolemembers)
191 errorConflictingDefElem(defel, pstate);
192 drolemembers = defel;
194 else if (strcmp(defel->defname, "adminmembers") == 0)
196 if (dadminmembers)
197 errorConflictingDefElem(defel, pstate);
198 dadminmembers = defel;
200 else if (strcmp(defel->defname, "validUntil") == 0)
202 if (dvalidUntil)
203 errorConflictingDefElem(defel, pstate);
204 dvalidUntil = defel;
206 else if (strcmp(defel->defname, "bypassrls") == 0)
208 if (dbypassRLS)
209 errorConflictingDefElem(defel, pstate);
210 dbypassRLS = defel;
212 else
213 elog(ERROR, "option \"%s\" not recognized",
214 defel->defname);
217 if (dpassword && dpassword->arg)
218 password = strVal(dpassword->arg);
219 if (dissuper)
220 issuper = intVal(dissuper->arg) != 0;
221 if (dinherit)
222 inherit = intVal(dinherit->arg) != 0;
223 if (dcreaterole)
224 createrole = intVal(dcreaterole->arg) != 0;
225 if (dcreatedb)
226 createdb = intVal(dcreatedb->arg) != 0;
227 if (dcanlogin)
228 canlogin = intVal(dcanlogin->arg) != 0;
229 if (disreplication)
230 isreplication = intVal(disreplication->arg) != 0;
231 if (dconnlimit)
233 connlimit = intVal(dconnlimit->arg);
234 if (connlimit < -1)
235 ereport(ERROR,
236 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
237 errmsg("invalid connection limit: %d", connlimit)));
239 if (daddroleto)
240 addroleto = (List *) daddroleto->arg;
241 if (drolemembers)
242 rolemembers = (List *) drolemembers->arg;
243 if (dadminmembers)
244 adminmembers = (List *) dadminmembers->arg;
245 if (dvalidUntil)
246 validUntil = strVal(dvalidUntil->arg);
247 if (dbypassRLS)
248 bypassrls = intVal(dbypassRLS->arg) != 0;
250 /* Check some permissions first */
251 if (issuper)
253 if (!superuser())
254 ereport(ERROR,
255 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
256 errmsg("must be superuser to create superusers")));
258 else if (isreplication)
260 if (!superuser())
261 ereport(ERROR,
262 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
263 errmsg("must be superuser to create replication users")));
265 else if (bypassrls)
267 if (!superuser())
268 ereport(ERROR,
269 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
270 errmsg("must be superuser to create bypassrls users")));
272 else
274 if (!have_createrole_privilege())
275 ereport(ERROR,
276 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
277 errmsg("permission denied to create role")));
281 * Check that the user is not trying to create a role in the reserved
282 * "pg_" namespace.
284 if (IsReservedName(stmt->role))
285 ereport(ERROR,
286 (errcode(ERRCODE_RESERVED_NAME),
287 errmsg("role name \"%s\" is reserved",
288 stmt->role),
289 errdetail("Role names starting with \"pg_\" are reserved.")));
292 * If built with appropriate switch, whine when regression-testing
293 * conventions for role names are violated.
295 #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
296 if (strncmp(stmt->role, "regress_", 8) != 0)
297 elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
298 #endif
301 * Check the pg_authid relation to be certain the role doesn't already
302 * exist.
304 pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
305 pg_authid_dsc = RelationGetDescr(pg_authid_rel);
307 if (OidIsValid(get_role_oid(stmt->role, true)))
308 ereport(ERROR,
309 (errcode(ERRCODE_DUPLICATE_OBJECT),
310 errmsg("role \"%s\" already exists",
311 stmt->role)));
313 /* Convert validuntil to internal form */
314 if (validUntil)
316 validUntil_datum = DirectFunctionCall3(timestamptz_in,
317 CStringGetDatum(validUntil),
318 ObjectIdGetDatum(InvalidOid),
319 Int32GetDatum(-1));
320 validUntil_null = false;
322 else
324 validUntil_datum = (Datum) 0;
325 validUntil_null = true;
329 * Call the password checking hook if there is one defined
331 if (check_password_hook && password)
332 (*check_password_hook) (stmt->role,
333 password,
334 get_password_type(password),
335 validUntil_datum,
336 validUntil_null);
339 * Build a tuple to insert
341 MemSet(new_record, 0, sizeof(new_record));
342 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
344 new_record[Anum_pg_authid_rolname - 1] =
345 DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
347 new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
348 new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
349 new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
350 new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
351 new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
352 new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
353 new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
355 if (password)
357 char *shadow_pass;
358 char *logdetail;
361 * Don't allow an empty password. Libpq treats an empty password the
362 * same as no password at all, and won't even try to authenticate. But
363 * other clients might, so allowing it would be confusing. By clearing
364 * the password when an empty string is specified, the account is
365 * consistently locked for all clients.
367 * Note that this only covers passwords stored in the database itself.
368 * There are also checks in the authentication code, to forbid an
369 * empty password from being used with authentication methods that
370 * fetch the password from an external system, like LDAP or PAM.
372 if (password[0] == '\0' ||
373 plain_crypt_verify(stmt->role, password, "", &logdetail) == STATUS_OK)
375 ereport(NOTICE,
376 (errmsg("empty string is not a valid password, clearing password")));
377 new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
379 else
381 /* Encrypt the password to the requested format. */
382 shadow_pass = encrypt_password(Password_encryption, stmt->role,
383 password);
384 new_record[Anum_pg_authid_rolpassword - 1] =
385 CStringGetTextDatum(shadow_pass);
388 else
389 new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
391 new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
392 new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
394 new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
397 * pg_largeobject_metadata contains pg_authid.oid's, so we use the
398 * binary-upgrade override.
400 if (IsBinaryUpgrade)
402 if (!OidIsValid(binary_upgrade_next_pg_authid_oid))
403 ereport(ERROR,
404 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
405 errmsg("pg_authid OID value not set when in binary upgrade mode")));
407 roleid = binary_upgrade_next_pg_authid_oid;
408 binary_upgrade_next_pg_authid_oid = InvalidOid;
410 else
412 roleid = GetNewOidWithIndex(pg_authid_rel, AuthIdOidIndexId,
413 Anum_pg_authid_oid);
416 new_record[Anum_pg_authid_oid - 1] = ObjectIdGetDatum(roleid);
418 tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
421 * Insert new record in the pg_authid table
423 CatalogTupleInsert(pg_authid_rel, tuple);
426 * Advance command counter so we can see new record; else tests in
427 * AddRoleMems may fail.
429 if (addroleto || adminmembers || rolemembers)
430 CommandCounterIncrement();
433 * Add the new role to the specified existing roles.
435 if (addroleto)
437 RoleSpec *thisrole = makeNode(RoleSpec);
438 List *thisrole_list = list_make1(thisrole);
439 List *thisrole_oidlist = list_make1_oid(roleid);
441 thisrole->roletype = ROLESPEC_CSTRING;
442 thisrole->rolename = stmt->role;
443 thisrole->location = -1;
445 foreach(item, addroleto)
447 RoleSpec *oldrole = lfirst(item);
448 HeapTuple oldroletup = get_rolespec_tuple(oldrole);
449 Form_pg_authid oldroleform = (Form_pg_authid) GETSTRUCT(oldroletup);
450 Oid oldroleid = oldroleform->oid;
451 char *oldrolename = NameStr(oldroleform->rolname);
453 AddRoleMems(oldrolename, oldroleid,
454 thisrole_list,
455 thisrole_oidlist,
456 GetUserId(), false);
458 ReleaseSysCache(oldroletup);
463 * Add the specified members to this new role. adminmembers get the admin
464 * option, rolemembers don't.
466 AddRoleMems(stmt->role, roleid,
467 adminmembers, roleSpecsToIds(adminmembers),
468 GetUserId(), true);
469 AddRoleMems(stmt->role, roleid,
470 rolemembers, roleSpecsToIds(rolemembers),
471 GetUserId(), false);
473 /* Post creation hook for new role */
474 InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
477 * Close pg_authid, but keep lock till commit.
479 table_close(pg_authid_rel, NoLock);
481 return roleid;
486 * ALTER ROLE
488 * Note: the rolemembers option accepted here is intended to support the
489 * backwards-compatible ALTER GROUP syntax. Although it will work to say
490 * "ALTER ROLE role ROLE rolenames", we don't document it.
493 AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
495 Datum new_record[Natts_pg_authid];
496 bool new_record_nulls[Natts_pg_authid];
497 bool new_record_repl[Natts_pg_authid];
498 Relation pg_authid_rel;
499 TupleDesc pg_authid_dsc;
500 HeapTuple tuple,
501 new_tuple;
502 Form_pg_authid authform;
503 ListCell *option;
504 char *rolename = NULL;
505 char *password = NULL; /* user password */
506 int issuper = -1; /* Make the user a superuser? */
507 int inherit = -1; /* Auto inherit privileges? */
508 int createrole = -1; /* Can this user create roles? */
509 int createdb = -1; /* Can the user create databases? */
510 int canlogin = -1; /* Can this user login? */
511 int isreplication = -1; /* Is this a replication role? */
512 int connlimit = -1; /* maximum connections allowed */
513 List *rolemembers = NIL; /* roles to be added/removed */
514 char *validUntil = NULL; /* time the login is valid until */
515 Datum validUntil_datum; /* same, as timestamptz Datum */
516 bool validUntil_null;
517 int bypassrls = -1;
518 DefElem *dpassword = NULL;
519 DefElem *dissuper = NULL;
520 DefElem *dinherit = NULL;
521 DefElem *dcreaterole = NULL;
522 DefElem *dcreatedb = NULL;
523 DefElem *dcanlogin = NULL;
524 DefElem *disreplication = NULL;
525 DefElem *dconnlimit = NULL;
526 DefElem *drolemembers = NULL;
527 DefElem *dvalidUntil = NULL;
528 DefElem *dbypassRLS = NULL;
529 Oid roleid;
531 check_rolespec_name(stmt->role,
532 "Cannot alter reserved roles.");
534 /* Extract options from the statement node tree */
535 foreach(option, stmt->options)
537 DefElem *defel = (DefElem *) lfirst(option);
539 if (strcmp(defel->defname, "password") == 0)
541 if (dpassword)
542 errorConflictingDefElem(defel, pstate);
543 dpassword = defel;
545 else if (strcmp(defel->defname, "superuser") == 0)
547 if (dissuper)
548 errorConflictingDefElem(defel, pstate);
549 dissuper = defel;
551 else if (strcmp(defel->defname, "inherit") == 0)
553 if (dinherit)
554 errorConflictingDefElem(defel, pstate);
555 dinherit = defel;
557 else if (strcmp(defel->defname, "createrole") == 0)
559 if (dcreaterole)
560 errorConflictingDefElem(defel, pstate);
561 dcreaterole = defel;
563 else if (strcmp(defel->defname, "createdb") == 0)
565 if (dcreatedb)
566 errorConflictingDefElem(defel, pstate);
567 dcreatedb = defel;
569 else if (strcmp(defel->defname, "canlogin") == 0)
571 if (dcanlogin)
572 errorConflictingDefElem(defel, pstate);
573 dcanlogin = defel;
575 else if (strcmp(defel->defname, "isreplication") == 0)
577 if (disreplication)
578 errorConflictingDefElem(defel, pstate);
579 disreplication = defel;
581 else if (strcmp(defel->defname, "connectionlimit") == 0)
583 if (dconnlimit)
584 errorConflictingDefElem(defel, pstate);
585 dconnlimit = defel;
587 else if (strcmp(defel->defname, "rolemembers") == 0 &&
588 stmt->action != 0)
590 if (drolemembers)
591 errorConflictingDefElem(defel, pstate);
592 drolemembers = defel;
594 else if (strcmp(defel->defname, "validUntil") == 0)
596 if (dvalidUntil)
597 errorConflictingDefElem(defel, pstate);
598 dvalidUntil = defel;
600 else if (strcmp(defel->defname, "bypassrls") == 0)
602 if (dbypassRLS)
603 errorConflictingDefElem(defel, pstate);
604 dbypassRLS = defel;
606 else
607 elog(ERROR, "option \"%s\" not recognized",
608 defel->defname);
611 if (dpassword && dpassword->arg)
612 password = strVal(dpassword->arg);
613 if (dissuper)
614 issuper = intVal(dissuper->arg);
615 if (dinherit)
616 inherit = intVal(dinherit->arg);
617 if (dcreaterole)
618 createrole = intVal(dcreaterole->arg);
619 if (dcreatedb)
620 createdb = intVal(dcreatedb->arg);
621 if (dcanlogin)
622 canlogin = intVal(dcanlogin->arg);
623 if (disreplication)
624 isreplication = intVal(disreplication->arg);
625 if (dconnlimit)
627 connlimit = intVal(dconnlimit->arg);
628 if (connlimit < -1)
629 ereport(ERROR,
630 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
631 errmsg("invalid connection limit: %d", connlimit)));
633 if (drolemembers)
634 rolemembers = (List *) drolemembers->arg;
635 if (dvalidUntil)
636 validUntil = strVal(dvalidUntil->arg);
637 if (dbypassRLS)
638 bypassrls = intVal(dbypassRLS->arg);
641 * Scan the pg_authid relation to be certain the user exists.
643 pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
644 pg_authid_dsc = RelationGetDescr(pg_authid_rel);
646 tuple = get_rolespec_tuple(stmt->role);
647 authform = (Form_pg_authid) GETSTRUCT(tuple);
648 rolename = pstrdup(NameStr(authform->rolname));
649 roleid = authform->oid;
652 * To mess with a superuser or replication role in any way you gotta be
653 * superuser. We also insist on superuser to change the BYPASSRLS
654 * property. Otherwise, if you don't have createrole, you're only allowed
655 * to change your own password.
657 if (authform->rolsuper || issuper >= 0)
659 if (!superuser())
660 ereport(ERROR,
661 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
662 errmsg("must be superuser to alter superuser roles or change superuser attribute")));
664 else if (authform->rolreplication || isreplication >= 0)
666 if (!superuser())
667 ereport(ERROR,
668 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
669 errmsg("must be superuser to alter replication roles or change replication attribute")));
671 else if (bypassrls >= 0)
673 if (!superuser())
674 ereport(ERROR,
675 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
676 errmsg("must be superuser to change bypassrls attribute")));
678 else if (!have_createrole_privilege())
680 /* We already checked issuper, isreplication, and bypassrls */
681 if (!(inherit < 0 &&
682 createrole < 0 &&
683 createdb < 0 &&
684 canlogin < 0 &&
685 !dconnlimit &&
686 !rolemembers &&
687 !validUntil &&
688 dpassword &&
689 roleid == GetUserId()))
690 ereport(ERROR,
691 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
692 errmsg("permission denied")));
695 /* Convert validuntil to internal form */
696 if (validUntil)
698 validUntil_datum = DirectFunctionCall3(timestamptz_in,
699 CStringGetDatum(validUntil),
700 ObjectIdGetDatum(InvalidOid),
701 Int32GetDatum(-1));
702 validUntil_null = false;
704 else
706 /* fetch existing setting in case hook needs it */
707 validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
708 Anum_pg_authid_rolvaliduntil,
709 &validUntil_null);
713 * Call the password checking hook if there is one defined
715 if (check_password_hook && password)
716 (*check_password_hook) (rolename,
717 password,
718 get_password_type(password),
719 validUntil_datum,
720 validUntil_null);
723 * Build an updated tuple, perusing the information just obtained
725 MemSet(new_record, 0, sizeof(new_record));
726 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
727 MemSet(new_record_repl, false, sizeof(new_record_repl));
730 * issuper/createrole/etc
732 if (issuper >= 0)
734 new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
735 new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
738 if (inherit >= 0)
740 new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
741 new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
744 if (createrole >= 0)
746 new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
747 new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
750 if (createdb >= 0)
752 new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
753 new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
756 if (canlogin >= 0)
758 new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
759 new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
762 if (isreplication >= 0)
764 new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication > 0);
765 new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
768 if (dconnlimit)
770 new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
771 new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
774 /* password */
775 if (password)
777 char *shadow_pass;
778 char *logdetail;
780 /* Like in CREATE USER, don't allow an empty password. */
781 if (password[0] == '\0' ||
782 plain_crypt_verify(rolename, password, "", &logdetail) == STATUS_OK)
784 ereport(NOTICE,
785 (errmsg("empty string is not a valid password, clearing password")));
786 new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
788 else
790 /* Encrypt the password to the requested format. */
791 shadow_pass = encrypt_password(Password_encryption, rolename,
792 password);
793 new_record[Anum_pg_authid_rolpassword - 1] =
794 CStringGetTextDatum(shadow_pass);
796 new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
799 /* unset password */
800 if (dpassword && dpassword->arg == NULL)
802 new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
803 new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
806 /* valid until */
807 new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
808 new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
809 new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
811 if (bypassrls >= 0)
813 new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls > 0);
814 new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
817 new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
818 new_record_nulls, new_record_repl);
819 CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple);
821 InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
823 ReleaseSysCache(tuple);
824 heap_freetuple(new_tuple);
827 * Advance command counter so we can see new record; else tests in
828 * AddRoleMems may fail.
830 if (rolemembers)
831 CommandCounterIncrement();
833 if (stmt->action == +1) /* add members to role */
834 AddRoleMems(rolename, roleid,
835 rolemembers, roleSpecsToIds(rolemembers),
836 GetUserId(), false);
837 else if (stmt->action == -1) /* drop members from role */
838 DelRoleMems(rolename, roleid,
839 rolemembers, roleSpecsToIds(rolemembers),
840 false);
843 * Close pg_authid, but keep lock till commit.
845 table_close(pg_authid_rel, NoLock);
847 return roleid;
852 * ALTER ROLE ... SET
855 AlterRoleSet(AlterRoleSetStmt *stmt)
857 HeapTuple roletuple;
858 Form_pg_authid roleform;
859 Oid databaseid = InvalidOid;
860 Oid roleid = InvalidOid;
862 if (stmt->role)
864 check_rolespec_name(stmt->role,
865 "Cannot alter reserved roles.");
867 roletuple = get_rolespec_tuple(stmt->role);
868 roleform = (Form_pg_authid) GETSTRUCT(roletuple);
869 roleid = roleform->oid;
872 * Obtain a lock on the role and make sure it didn't go away in the
873 * meantime.
875 shdepLockAndCheckObject(AuthIdRelationId, roleid);
878 * To mess with a superuser you gotta be superuser; else you need
879 * createrole, or just want to change your own settings
881 if (roleform->rolsuper)
883 if (!superuser())
884 ereport(ERROR,
885 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
886 errmsg("must be superuser to alter superusers")));
888 else
890 if (!have_createrole_privilege() && roleid != GetUserId())
891 ereport(ERROR,
892 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
893 errmsg("permission denied")));
896 ReleaseSysCache(roletuple);
899 /* look up and lock the database, if specified */
900 if (stmt->database != NULL)
902 databaseid = get_database_oid(stmt->database, false);
903 shdepLockAndCheckObject(DatabaseRelationId, databaseid);
905 if (!stmt->role)
908 * If no role is specified, then this is effectively the same as
909 * ALTER DATABASE ... SET, so use the same permission check.
911 if (!pg_database_ownercheck(databaseid, GetUserId()))
912 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
913 stmt->database);
917 if (!stmt->role && !stmt->database)
919 /* Must be superuser to alter settings globally. */
920 if (!superuser())
921 ereport(ERROR,
922 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
923 errmsg("must be superuser to alter settings globally")));
926 AlterSetting(databaseid, roleid, stmt->setstmt);
928 return roleid;
933 * DROP ROLE
935 void
936 DropRole(DropRoleStmt *stmt)
938 Relation pg_authid_rel,
939 pg_auth_members_rel;
940 ListCell *item;
942 if (!have_createrole_privilege())
943 ereport(ERROR,
944 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
945 errmsg("permission denied to drop role")));
948 * Scan the pg_authid relation to find the Oid of the role(s) to be
949 * deleted.
951 pg_authid_rel = table_open(AuthIdRelationId, RowExclusiveLock);
952 pg_auth_members_rel = table_open(AuthMemRelationId, RowExclusiveLock);
954 foreach(item, stmt->roles)
956 RoleSpec *rolspec = lfirst(item);
957 char *role;
958 HeapTuple tuple,
959 tmp_tuple;
960 Form_pg_authid roleform;
961 ScanKeyData scankey;
962 char *detail;
963 char *detail_log;
964 SysScanDesc sscan;
965 Oid roleid;
967 if (rolspec->roletype != ROLESPEC_CSTRING)
968 ereport(ERROR,
969 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
970 errmsg("cannot use special role specifier in DROP ROLE")));
971 role = rolspec->rolename;
973 tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
974 if (!HeapTupleIsValid(tuple))
976 if (!stmt->missing_ok)
978 ereport(ERROR,
979 (errcode(ERRCODE_UNDEFINED_OBJECT),
980 errmsg("role \"%s\" does not exist", role)));
982 else
984 ereport(NOTICE,
985 (errmsg("role \"%s\" does not exist, skipping",
986 role)));
989 continue;
992 roleform = (Form_pg_authid) GETSTRUCT(tuple);
993 roleid = roleform->oid;
995 if (roleid == GetUserId())
996 ereport(ERROR,
997 (errcode(ERRCODE_OBJECT_IN_USE),
998 errmsg("current user cannot be dropped")));
999 if (roleid == GetOuterUserId())
1000 ereport(ERROR,
1001 (errcode(ERRCODE_OBJECT_IN_USE),
1002 errmsg("current user cannot be dropped")));
1003 if (roleid == GetSessionUserId())
1004 ereport(ERROR,
1005 (errcode(ERRCODE_OBJECT_IN_USE),
1006 errmsg("session user cannot be dropped")));
1009 * For safety's sake, we allow createrole holders to drop ordinary
1010 * roles but not superuser roles. This is mainly to avoid the
1011 * scenario where you accidentally drop the last superuser.
1013 if (roleform->rolsuper && !superuser())
1014 ereport(ERROR,
1015 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1016 errmsg("must be superuser to drop superusers")));
1018 /* DROP hook for the role being removed */
1019 InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
1022 * Lock the role, so nobody can add dependencies to her while we drop
1023 * her. We keep the lock until the end of transaction.
1025 LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);
1027 /* Check for pg_shdepend entries depending on this role */
1028 if (checkSharedDependencies(AuthIdRelationId, roleid,
1029 &detail, &detail_log))
1030 ereport(ERROR,
1031 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1032 errmsg("role \"%s\" cannot be dropped because some objects depend on it",
1033 role),
1034 errdetail_internal("%s", detail),
1035 errdetail_log("%s", detail_log)));
1038 * Remove the role from the pg_authid table
1040 CatalogTupleDelete(pg_authid_rel, &tuple->t_self);
1042 ReleaseSysCache(tuple);
1045 * Remove role from the pg_auth_members table. We have to remove all
1046 * tuples that show it as either a role or a member.
1048 * XXX what about grantor entries? Maybe we should do one heap scan.
1050 ScanKeyInit(&scankey,
1051 Anum_pg_auth_members_roleid,
1052 BTEqualStrategyNumber, F_OIDEQ,
1053 ObjectIdGetDatum(roleid));
1055 sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
1056 true, NULL, 1, &scankey);
1058 while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1060 CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1063 systable_endscan(sscan);
1065 ScanKeyInit(&scankey,
1066 Anum_pg_auth_members_member,
1067 BTEqualStrategyNumber, F_OIDEQ,
1068 ObjectIdGetDatum(roleid));
1070 sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
1071 true, NULL, 1, &scankey);
1073 while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1075 CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1078 systable_endscan(sscan);
1081 * Remove any comments or security labels on this role.
1083 DeleteSharedComments(roleid, AuthIdRelationId);
1084 DeleteSharedSecurityLabel(roleid, AuthIdRelationId);
1087 * Remove settings for this role.
1089 DropSetting(InvalidOid, roleid);
1092 * Advance command counter so that later iterations of this loop will
1093 * see the changes already made. This is essential if, for example,
1094 * we are trying to drop both a role and one of its direct members ---
1095 * we'll get an error if we try to delete the linking pg_auth_members
1096 * tuple twice. (We do not need a CCI between the two delete loops
1097 * above, because it's not allowed for a role to directly contain
1098 * itself.)
1100 CommandCounterIncrement();
1104 * Now we can clean up; but keep locks until commit.
1106 table_close(pg_auth_members_rel, NoLock);
1107 table_close(pg_authid_rel, NoLock);
1111 * Rename role
1113 ObjectAddress
1114 RenameRole(const char *oldname, const char *newname)
1116 HeapTuple oldtuple,
1117 newtuple;
1118 TupleDesc dsc;
1119 Relation rel;
1120 Datum datum;
1121 bool isnull;
1122 Datum repl_val[Natts_pg_authid];
1123 bool repl_null[Natts_pg_authid];
1124 bool repl_repl[Natts_pg_authid];
1125 int i;
1126 Oid roleid;
1127 ObjectAddress address;
1128 Form_pg_authid authform;
1130 rel = table_open(AuthIdRelationId, RowExclusiveLock);
1131 dsc = RelationGetDescr(rel);
1133 oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
1134 if (!HeapTupleIsValid(oldtuple))
1135 ereport(ERROR,
1136 (errcode(ERRCODE_UNDEFINED_OBJECT),
1137 errmsg("role \"%s\" does not exist", oldname)));
1140 * XXX Client applications probably store the session user somewhere, so
1141 * renaming it could cause confusion. On the other hand, there may not be
1142 * an actual problem besides a little confusion, so think about this and
1143 * decide. Same for SET ROLE ... we don't restrict renaming the current
1144 * effective userid, though.
1147 authform = (Form_pg_authid) GETSTRUCT(oldtuple);
1148 roleid = authform->oid;
1150 if (roleid == GetSessionUserId())
1151 ereport(ERROR,
1152 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1153 errmsg("session user cannot be renamed")));
1154 if (roleid == GetOuterUserId())
1155 ereport(ERROR,
1156 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1157 errmsg("current user cannot be renamed")));
1160 * Check that the user is not trying to rename a system role and not
1161 * trying to rename a role into the reserved "pg_" namespace.
1163 if (IsReservedName(NameStr(authform->rolname)))
1164 ereport(ERROR,
1165 (errcode(ERRCODE_RESERVED_NAME),
1166 errmsg("role name \"%s\" is reserved",
1167 NameStr(authform->rolname)),
1168 errdetail("Role names starting with \"pg_\" are reserved.")));
1170 if (IsReservedName(newname))
1171 ereport(ERROR,
1172 (errcode(ERRCODE_RESERVED_NAME),
1173 errmsg("role name \"%s\" is reserved",
1174 newname),
1175 errdetail("Role names starting with \"pg_\" are reserved.")));
1178 * If built with appropriate switch, whine when regression-testing
1179 * conventions for role names are violated.
1181 #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
1182 if (strncmp(newname, "regress_", 8) != 0)
1183 elog(WARNING, "roles created by regression test cases should have names starting with \"regress_\"");
1184 #endif
1186 /* make sure the new name doesn't exist */
1187 if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
1188 ereport(ERROR,
1189 (errcode(ERRCODE_DUPLICATE_OBJECT),
1190 errmsg("role \"%s\" already exists", newname)));
1193 * createrole is enough privilege unless you want to mess with a superuser
1195 if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
1197 if (!superuser())
1198 ereport(ERROR,
1199 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1200 errmsg("must be superuser to rename superusers")));
1202 else
1204 if (!have_createrole_privilege())
1205 ereport(ERROR,
1206 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1207 errmsg("permission denied to rename role")));
1210 /* OK, construct the modified tuple */
1211 for (i = 0; i < Natts_pg_authid; i++)
1212 repl_repl[i] = false;
1214 repl_repl[Anum_pg_authid_rolname - 1] = true;
1215 repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
1216 CStringGetDatum(newname));
1217 repl_null[Anum_pg_authid_rolname - 1] = false;
1219 datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
1221 if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
1223 /* MD5 uses the username as salt, so just clear it on a rename */
1224 repl_repl[Anum_pg_authid_rolpassword - 1] = true;
1225 repl_null[Anum_pg_authid_rolpassword - 1] = true;
1227 ereport(NOTICE,
1228 (errmsg("MD5 password cleared because of role rename")));
1231 newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
1232 CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple);
1234 InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
1236 ObjectAddressSet(address, AuthIdRelationId, roleid);
1238 ReleaseSysCache(oldtuple);
1241 * Close pg_authid, but keep lock till commit.
1243 table_close(rel, NoLock);
1245 return address;
1249 * GrantRoleStmt
1251 * Grant/Revoke roles to/from roles
1253 void
1254 GrantRole(GrantRoleStmt *stmt)
1256 Relation pg_authid_rel;
1257 Oid grantor;
1258 List *grantee_ids;
1259 ListCell *item;
1261 if (stmt->grantor)
1262 grantor = get_rolespec_oid(stmt->grantor, false);
1263 else
1264 grantor = GetUserId();
1266 grantee_ids = roleSpecsToIds(stmt->grantee_roles);
1268 /* AccessShareLock is enough since we aren't modifying pg_authid */
1269 pg_authid_rel = table_open(AuthIdRelationId, AccessShareLock);
1272 * Step through all of the granted roles and add/remove entries for the
1273 * grantees, or, if admin_opt is set, then just add/remove the admin
1274 * option.
1276 * Note: Permissions checking is done by AddRoleMems/DelRoleMems
1278 foreach(item, stmt->granted_roles)
1280 AccessPriv *priv = (AccessPriv *) lfirst(item);
1281 char *rolename = priv->priv_name;
1282 Oid roleid;
1284 /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
1285 if (rolename == NULL || priv->cols != NIL)
1286 ereport(ERROR,
1287 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1288 errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
1290 roleid = get_role_oid(rolename, false);
1291 if (stmt->is_grant)
1292 AddRoleMems(rolename, roleid,
1293 stmt->grantee_roles, grantee_ids,
1294 grantor, stmt->admin_opt);
1295 else
1296 DelRoleMems(rolename, roleid,
1297 stmt->grantee_roles, grantee_ids,
1298 stmt->admin_opt);
1302 * Close pg_authid, but keep lock till commit.
1304 table_close(pg_authid_rel, NoLock);
1308 * DropOwnedObjects
1310 * Drop the objects owned by a given list of roles.
1312 void
1313 DropOwnedObjects(DropOwnedStmt *stmt)
1315 List *role_ids = roleSpecsToIds(stmt->roles);
1316 ListCell *cell;
1318 /* Check privileges */
1319 foreach(cell, role_ids)
1321 Oid roleid = lfirst_oid(cell);
1323 if (!has_privs_of_role(GetUserId(), roleid))
1324 ereport(ERROR,
1325 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1326 errmsg("permission denied to drop objects")));
1329 /* Ok, do it */
1330 shdepDropOwned(role_ids, stmt->behavior);
1334 * ReassignOwnedObjects
1336 * Give the objects owned by a given list of roles away to another user.
1338 void
1339 ReassignOwnedObjects(ReassignOwnedStmt *stmt)
1341 List *role_ids = roleSpecsToIds(stmt->roles);
1342 ListCell *cell;
1343 Oid newrole;
1345 /* Check privileges */
1346 foreach(cell, role_ids)
1348 Oid roleid = lfirst_oid(cell);
1350 if (!has_privs_of_role(GetUserId(), roleid))
1351 ereport(ERROR,
1352 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1353 errmsg("permission denied to reassign objects")));
1356 /* Must have privileges on the receiving side too */
1357 newrole = get_rolespec_oid(stmt->newrole, false);
1359 if (!has_privs_of_role(GetUserId(), newrole))
1360 ereport(ERROR,
1361 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1362 errmsg("permission denied to reassign objects")));
1364 /* Ok, do it */
1365 shdepReassignOwned(role_ids, newrole);
1369 * roleSpecsToIds
1371 * Given a list of RoleSpecs, generate a list of role OIDs in the same order.
1373 * ROLESPEC_PUBLIC is not allowed.
1375 List *
1376 roleSpecsToIds(List *memberNames)
1378 List *result = NIL;
1379 ListCell *l;
1381 foreach(l, memberNames)
1383 RoleSpec *rolespec = lfirst_node(RoleSpec, l);
1384 Oid roleid;
1386 roleid = get_rolespec_oid(rolespec, false);
1387 result = lappend_oid(result, roleid);
1389 return result;
1393 * AddRoleMems -- Add given members to the specified role
1395 * rolename: name of role to add to (used only for error messages)
1396 * roleid: OID of role to add to
1397 * memberSpecs: list of RoleSpec of roles to add (used only for error messages)
1398 * memberIds: OIDs of roles to add
1399 * grantorId: who is granting the membership
1400 * admin_opt: granting admin option?
1402 static void
1403 AddRoleMems(const char *rolename, Oid roleid,
1404 List *memberSpecs, List *memberIds,
1405 Oid grantorId, bool admin_opt)
1407 Relation pg_authmem_rel;
1408 TupleDesc pg_authmem_dsc;
1409 ListCell *specitem;
1410 ListCell *iditem;
1412 Assert(list_length(memberSpecs) == list_length(memberIds));
1414 /* Skip permission check if nothing to do */
1415 if (!memberIds)
1416 return;
1419 * Check permissions: must have createrole or admin option on the role to
1420 * be changed. To mess with a superuser role, you gotta be superuser.
1422 if (superuser_arg(roleid))
1424 if (!superuser())
1425 ereport(ERROR,
1426 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1427 errmsg("must be superuser to alter superusers")));
1429 else
1431 if (!have_createrole_privilege() &&
1432 !is_admin_of_role(grantorId, roleid))
1433 ereport(ERROR,
1434 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1435 errmsg("must have admin option on role \"%s\"",
1436 rolename)));
1440 * The charter of pg_database_owner is to have exactly one, implicit,
1441 * situation-dependent member. There's no technical need for this
1442 * restriction. (One could lift it and take the further step of making
1443 * pg_database_ownercheck() equivalent to has_privs_of_role(roleid,
1444 * ROLE_PG_DATABASE_OWNER), in which case explicit, situation-independent
1445 * members could act as the owner of any database.)
1447 if (roleid == ROLE_PG_DATABASE_OWNER)
1448 ereport(ERROR,
1449 errmsg("role \"%s\" cannot have explicit members", rolename));
1452 * The role membership grantor of record has little significance at
1453 * present. Nonetheless, inasmuch as users might look to it for a crude
1454 * audit trail, let only superusers impute the grant to a third party.
1456 * Before lifting this restriction, give the member == role case of
1457 * is_admin_of_role() a fresh look. Ensure that the current role cannot
1458 * use an explicit grantor specification to take advantage of the session
1459 * user's self-admin right.
1461 if (grantorId != GetUserId() && !superuser())
1462 ereport(ERROR,
1463 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1464 errmsg("must be superuser to set grantor")));
1466 pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1467 pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1469 forboth(specitem, memberSpecs, iditem, memberIds)
1471 RoleSpec *memberRole = lfirst_node(RoleSpec, specitem);
1472 Oid memberid = lfirst_oid(iditem);
1473 HeapTuple authmem_tuple;
1474 HeapTuple tuple;
1475 Datum new_record[Natts_pg_auth_members];
1476 bool new_record_nulls[Natts_pg_auth_members];
1477 bool new_record_repl[Natts_pg_auth_members];
1480 * pg_database_owner is never a role member. Lifting this restriction
1481 * would require a policy decision about membership loops. One could
1482 * prevent loops, which would include making "ALTER DATABASE x OWNER
1483 * TO proposed_datdba" fail if is_member_of_role(pg_database_owner,
1484 * proposed_datdba). Hence, gaining a membership could reduce what a
1485 * role could do. Alternately, one could allow these memberships to
1486 * complete loops. A role could then have actual WITH ADMIN OPTION on
1487 * itself, prompting a decision about is_admin_of_role() treatment of
1488 * the case.
1490 * Lifting this restriction also has policy implications for ownership
1491 * of shared objects (databases and tablespaces). We allow such
1492 * ownership, but we might find cause to ban it in the future.
1493 * Designing such a ban would more troublesome if the design had to
1494 * address pg_database_owner being a member of role FOO that owns a
1495 * shared object. (The effect of such ownership is that any owner of
1496 * another database can act as the owner of affected shared objects.)
1498 if (memberid == ROLE_PG_DATABASE_OWNER)
1499 ereport(ERROR,
1500 errmsg("role \"%s\" cannot be a member of any role",
1501 get_rolespec_name(memberRole)));
1504 * Refuse creation of membership loops, including the trivial case
1505 * where a role is made a member of itself. We do this by checking to
1506 * see if the target role is already a member of the proposed member
1507 * role. We have to ignore possible superuserness, however, else we
1508 * could never grant membership in a superuser-privileged role.
1510 if (is_member_of_role_nosuper(roleid, memberid))
1511 ereport(ERROR,
1512 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1513 errmsg("role \"%s\" is a member of role \"%s\"",
1514 rolename, get_rolespec_name(memberRole))));
1517 * Check if entry for this role/member already exists; if so, give
1518 * warning unless we are adding admin option.
1520 authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
1521 ObjectIdGetDatum(roleid),
1522 ObjectIdGetDatum(memberid));
1523 if (HeapTupleIsValid(authmem_tuple) &&
1524 (!admin_opt ||
1525 ((Form_pg_auth_members) GETSTRUCT(authmem_tuple))->admin_option))
1527 ereport(NOTICE,
1528 (errmsg("role \"%s\" is already a member of role \"%s\"",
1529 get_rolespec_name(memberRole), rolename)));
1530 ReleaseSysCache(authmem_tuple);
1531 continue;
1534 /* Build a tuple to insert or update */
1535 MemSet(new_record, 0, sizeof(new_record));
1536 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1537 MemSet(new_record_repl, false, sizeof(new_record_repl));
1539 new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid);
1540 new_record[Anum_pg_auth_members_member - 1] = ObjectIdGetDatum(memberid);
1541 new_record[Anum_pg_auth_members_grantor - 1] = ObjectIdGetDatum(grantorId);
1542 new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt);
1544 if (HeapTupleIsValid(authmem_tuple))
1546 new_record_repl[Anum_pg_auth_members_grantor - 1] = true;
1547 new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
1548 tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1549 new_record,
1550 new_record_nulls, new_record_repl);
1551 CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
1552 ReleaseSysCache(authmem_tuple);
1554 else
1556 tuple = heap_form_tuple(pg_authmem_dsc,
1557 new_record, new_record_nulls);
1558 CatalogTupleInsert(pg_authmem_rel, tuple);
1561 /* CCI after each change, in case there are duplicates in list */
1562 CommandCounterIncrement();
1566 * Close pg_authmem, but keep lock till commit.
1568 table_close(pg_authmem_rel, NoLock);
1572 * DelRoleMems -- Remove given members from the specified role
1574 * rolename: name of role to del from (used only for error messages)
1575 * roleid: OID of role to del from
1576 * memberSpecs: list of RoleSpec of roles to del (used only for error messages)
1577 * memberIds: OIDs of roles to del
1578 * admin_opt: remove admin option only?
1580 static void
1581 DelRoleMems(const char *rolename, Oid roleid,
1582 List *memberSpecs, List *memberIds,
1583 bool admin_opt)
1585 Relation pg_authmem_rel;
1586 TupleDesc pg_authmem_dsc;
1587 ListCell *specitem;
1588 ListCell *iditem;
1590 Assert(list_length(memberSpecs) == list_length(memberIds));
1592 /* Skip permission check if nothing to do */
1593 if (!memberIds)
1594 return;
1597 * Check permissions: must have createrole or admin option on the role to
1598 * be changed. To mess with a superuser role, you gotta be superuser.
1600 if (superuser_arg(roleid))
1602 if (!superuser())
1603 ereport(ERROR,
1604 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1605 errmsg("must be superuser to alter superusers")));
1607 else
1609 if (!have_createrole_privilege() &&
1610 !is_admin_of_role(GetUserId(), roleid))
1611 ereport(ERROR,
1612 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1613 errmsg("must have admin option on role \"%s\"",
1614 rolename)));
1617 pg_authmem_rel = table_open(AuthMemRelationId, RowExclusiveLock);
1618 pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1620 forboth(specitem, memberSpecs, iditem, memberIds)
1622 RoleSpec *memberRole = lfirst(specitem);
1623 Oid memberid = lfirst_oid(iditem);
1624 HeapTuple authmem_tuple;
1627 * Find entry for this role/member
1629 authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
1630 ObjectIdGetDatum(roleid),
1631 ObjectIdGetDatum(memberid));
1632 if (!HeapTupleIsValid(authmem_tuple))
1634 ereport(WARNING,
1635 (errmsg("role \"%s\" is not a member of role \"%s\"",
1636 get_rolespec_name(memberRole), rolename)));
1637 continue;
1640 if (!admin_opt)
1642 /* Remove the entry altogether */
1643 CatalogTupleDelete(pg_authmem_rel, &authmem_tuple->t_self);
1645 else
1647 /* Just turn off the admin option */
1648 HeapTuple tuple;
1649 Datum new_record[Natts_pg_auth_members];
1650 bool new_record_nulls[Natts_pg_auth_members];
1651 bool new_record_repl[Natts_pg_auth_members];
1653 /* Build a tuple to update with */
1654 MemSet(new_record, 0, sizeof(new_record));
1655 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1656 MemSet(new_record_repl, false, sizeof(new_record_repl));
1658 new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false);
1659 new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
1661 tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1662 new_record,
1663 new_record_nulls, new_record_repl);
1664 CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
1667 ReleaseSysCache(authmem_tuple);
1669 /* CCI after each change, in case there are duplicates in list */
1670 CommandCounterIncrement();
1674 * Close pg_authmem, but keep lock till commit.
1676 table_close(pg_authmem_rel, NoLock);