1 /*-------------------------------------------------------------------------
4 * Commands for manipulating roles (formerly called users).
6 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * src/backend/commands/user.c
11 *-------------------------------------------------------------------------
15 #include "access/genam.h"
16 #include "access/heapam.h"
17 #include "access/xact.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/objectaccess.h"
21 #include "catalog/pg_auth_members.h"
22 #include "catalog/pg_authid.h"
23 #include "catalog/pg_database.h"
24 #include "catalog/pg_db_role_setting.h"
25 #include "commands/comment.h"
26 #include "commands/dbcommands.h"
27 #include "commands/user.h"
28 #include "libpq/md5.h"
29 #include "miscadmin.h"
30 #include "storage/lmgr.h"
31 #include "utils/acl.h"
32 #include "utils/builtins.h"
33 #include "utils/fmgroids.h"
34 #include "utils/lsyscache.h"
35 #include "utils/syscache.h"
36 #include "utils/tqual.h"
40 extern bool Password_encryption;
42 /* Hook to check passwords in CreateRole() and AlterRole() */
43 check_password_hook_type check_password_hook = NULL;
45 static List *roleNamesToIds(List *memberNames);
46 static void AddRoleMems(const char *rolename, Oid roleid,
47 List *memberNames, List *memberIds,
48 Oid grantorId, bool admin_opt);
49 static void DelRoleMems(const char *rolename, Oid roleid,
50 List *memberNames, List *memberIds,
54 /* Check if current user has createrole privileges */
56 have_createrole_privilege(void)
61 /* Superusers can always do everything */
65 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
66 if (HeapTupleIsValid(utup))
68 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
69 ReleaseSysCache(utup);
79 CreateRole(CreateRoleStmt *stmt)
81 Relation pg_authid_rel;
82 TupleDesc pg_authid_dsc;
84 Datum new_record[Natts_pg_authid];
85 bool new_record_nulls[Natts_pg_authid];
89 char *password = NULL; /* user password */
90 bool encrypt_password = Password_encryption; /* encrypt password? */
91 char encrypted_password[MD5_PASSWD_LEN + 1];
92 bool issuper = false; /* Make the user a superuser? */
93 bool inherit = true; /* Auto inherit privileges? */
94 bool createrole = false; /* Can this user create roles? */
95 bool createdb = false; /* Can the user create databases? */
96 bool canlogin = false; /* Can this user login? */
97 int connlimit = -1; /* maximum connections allowed */
98 List *addroleto = NIL; /* roles to make this a member of */
99 List *rolemembers = NIL; /* roles to be members of this role */
100 List *adminmembers = NIL; /* roles to be admins of this role */
101 char *validUntil = NULL; /* time the login is valid until */
102 Datum validUntil_datum; /* same, as timestamptz Datum */
103 bool validUntil_null;
104 DefElem *dpassword = NULL;
105 DefElem *dissuper = NULL;
106 DefElem *dinherit = NULL;
107 DefElem *dcreaterole = NULL;
108 DefElem *dcreatedb = NULL;
109 DefElem *dcanlogin = NULL;
110 DefElem *dconnlimit = NULL;
111 DefElem *daddroleto = NULL;
112 DefElem *drolemembers = NULL;
113 DefElem *dadminmembers = NULL;
114 DefElem *dvalidUntil = NULL;
116 /* The defaults can vary depending on the original statement type */
117 switch (stmt->stmt_type)
123 /* may eventually want inherit to default to false here */
129 /* Extract options from the statement node tree */
130 foreach(option, stmt->options)
132 DefElem *defel = (DefElem *) lfirst(option);
134 if (strcmp(defel->defname, "password") == 0 ||
135 strcmp(defel->defname, "encryptedPassword") == 0 ||
136 strcmp(defel->defname, "unencryptedPassword") == 0)
140 (errcode(ERRCODE_SYNTAX_ERROR),
141 errmsg("conflicting or redundant options")));
143 if (strcmp(defel->defname, "encryptedPassword") == 0)
144 encrypt_password = true;
145 else if (strcmp(defel->defname, "unencryptedPassword") == 0)
146 encrypt_password = false;
148 else if (strcmp(defel->defname, "sysid") == 0)
151 (errmsg("SYSID can no longer be specified")));
153 else if (strcmp(defel->defname, "superuser") == 0)
157 (errcode(ERRCODE_SYNTAX_ERROR),
158 errmsg("conflicting or redundant options")));
161 else if (strcmp(defel->defname, "inherit") == 0)
165 (errcode(ERRCODE_SYNTAX_ERROR),
166 errmsg("conflicting or redundant options")));
169 else if (strcmp(defel->defname, "createrole") == 0)
173 (errcode(ERRCODE_SYNTAX_ERROR),
174 errmsg("conflicting or redundant options")));
177 else if (strcmp(defel->defname, "createdb") == 0)
181 (errcode(ERRCODE_SYNTAX_ERROR),
182 errmsg("conflicting or redundant options")));
185 else if (strcmp(defel->defname, "canlogin") == 0)
189 (errcode(ERRCODE_SYNTAX_ERROR),
190 errmsg("conflicting or redundant options")));
193 else if (strcmp(defel->defname, "connectionlimit") == 0)
197 (errcode(ERRCODE_SYNTAX_ERROR),
198 errmsg("conflicting or redundant options")));
201 else if (strcmp(defel->defname, "addroleto") == 0)
205 (errcode(ERRCODE_SYNTAX_ERROR),
206 errmsg("conflicting or redundant options")));
209 else if (strcmp(defel->defname, "rolemembers") == 0)
213 (errcode(ERRCODE_SYNTAX_ERROR),
214 errmsg("conflicting or redundant options")));
215 drolemembers = defel;
217 else if (strcmp(defel->defname, "adminmembers") == 0)
221 (errcode(ERRCODE_SYNTAX_ERROR),
222 errmsg("conflicting or redundant options")));
223 dadminmembers = defel;
225 else if (strcmp(defel->defname, "validUntil") == 0)
229 (errcode(ERRCODE_SYNTAX_ERROR),
230 errmsg("conflicting or redundant options")));
234 elog(ERROR, "option \"%s\" not recognized",
238 if (dpassword && dpassword->arg)
239 password = strVal(dpassword->arg);
241 issuper = intVal(dissuper->arg) != 0;
243 inherit = intVal(dinherit->arg) != 0;
245 createrole = intVal(dcreaterole->arg) != 0;
247 createdb = intVal(dcreatedb->arg) != 0;
249 canlogin = intVal(dcanlogin->arg) != 0;
252 connlimit = intVal(dconnlimit->arg);
255 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
256 errmsg("invalid connection limit: %d", connlimit)));
259 addroleto = (List *) daddroleto->arg;
261 rolemembers = (List *) drolemembers->arg;
263 adminmembers = (List *) dadminmembers->arg;
265 validUntil = strVal(dvalidUntil->arg);
267 /* Check some permissions first */
272 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
273 errmsg("must be superuser to create superusers")));
277 if (!have_createrole_privilege())
279 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
280 errmsg("permission denied to create role")));
283 if (strcmp(stmt->role, "public") == 0 ||
284 strcmp(stmt->role, "none") == 0)
286 (errcode(ERRCODE_RESERVED_NAME),
287 errmsg("role name \"%s\" is reserved",
291 * Check the pg_authid relation to be certain the role doesn't already
294 pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
295 pg_authid_dsc = RelationGetDescr(pg_authid_rel);
297 if (OidIsValid(get_role_oid(stmt->role, true)))
299 (errcode(ERRCODE_DUPLICATE_OBJECT),
300 errmsg("role \"%s\" already exists",
303 /* Convert validuntil to internal form */
306 validUntil_datum = DirectFunctionCall3(timestamptz_in,
307 CStringGetDatum(validUntil),
308 ObjectIdGetDatum(InvalidOid),
310 validUntil_null = false;
314 validUntil_datum = (Datum) 0;
315 validUntil_null = true;
319 * Call the password checking hook if there is one defined
321 if (check_password_hook && password)
322 (*check_password_hook) (stmt->role,
324 isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
329 * Build a tuple to insert
331 MemSet(new_record, 0, sizeof(new_record));
332 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
334 new_record[Anum_pg_authid_rolname - 1] =
335 DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
337 new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
338 new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
339 new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
340 new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
341 /* superuser gets catupdate right by default */
342 new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
343 new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
344 new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
348 if (!encrypt_password || isMD5(password))
349 new_record[Anum_pg_authid_rolpassword - 1] =
350 CStringGetTextDatum(password);
353 if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
355 elog(ERROR, "password encryption failed");
356 new_record[Anum_pg_authid_rolpassword - 1] =
357 CStringGetTextDatum(encrypted_password);
361 new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
363 new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
364 new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
366 tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
369 * Insert new record in the pg_authid table
371 roleid = simple_heap_insert(pg_authid_rel, tuple);
372 CatalogUpdateIndexes(pg_authid_rel, tuple);
375 * Advance command counter so we can see new record; else tests in
376 * AddRoleMems may fail.
378 if (addroleto || adminmembers || rolemembers)
379 CommandCounterIncrement();
382 * Add the new role to the specified existing roles.
384 foreach(item, addroleto)
386 char *oldrolename = strVal(lfirst(item));
387 Oid oldroleid = get_role_oid(oldrolename, false);
389 AddRoleMems(oldrolename, oldroleid,
390 list_make1(makeString(stmt->role)),
391 list_make1_oid(roleid),
396 * Add the specified members to this new role. adminmembers get the admin
397 * option, rolemembers don't.
399 AddRoleMems(stmt->role, roleid,
400 adminmembers, roleNamesToIds(adminmembers),
402 AddRoleMems(stmt->role, roleid,
403 rolemembers, roleNamesToIds(rolemembers),
406 /* Post creation hook for new role */
407 InvokeObjectAccessHook(OAT_POST_CREATE, AuthIdRelationId, roleid, 0);
410 * Close pg_authid, but keep lock till commit.
412 heap_close(pg_authid_rel, NoLock);
419 * Note: the rolemembers option accepted here is intended to support the
420 * backwards-compatible ALTER GROUP syntax. Although it will work to say
421 * "ALTER ROLE role ROLE rolenames", we don't document it.
424 AlterRole(AlterRoleStmt *stmt)
426 Datum new_record[Natts_pg_authid];
427 bool new_record_nulls[Natts_pg_authid];
428 bool new_record_repl[Natts_pg_authid];
429 Relation pg_authid_rel;
430 TupleDesc pg_authid_dsc;
434 char *password = NULL; /* user password */
435 bool encrypt_password = Password_encryption; /* encrypt password? */
436 char encrypted_password[MD5_PASSWD_LEN + 1];
437 int issuper = -1; /* Make the user a superuser? */
438 int inherit = -1; /* Auto inherit privileges? */
439 int createrole = -1; /* Can this user create roles? */
440 int createdb = -1; /* Can the user create databases? */
441 int canlogin = -1; /* Can this user login? */
442 int connlimit = -1; /* maximum connections allowed */
443 List *rolemembers = NIL; /* roles to be added/removed */
444 char *validUntil = NULL; /* time the login is valid until */
445 Datum validUntil_datum; /* same, as timestamptz Datum */
446 bool validUntil_null;
447 DefElem *dpassword = NULL;
448 DefElem *dissuper = NULL;
449 DefElem *dinherit = NULL;
450 DefElem *dcreaterole = NULL;
451 DefElem *dcreatedb = NULL;
452 DefElem *dcanlogin = NULL;
453 DefElem *dconnlimit = NULL;
454 DefElem *drolemembers = NULL;
455 DefElem *dvalidUntil = NULL;
458 /* Extract options from the statement node tree */
459 foreach(option, stmt->options)
461 DefElem *defel = (DefElem *) lfirst(option);
463 if (strcmp(defel->defname, "password") == 0 ||
464 strcmp(defel->defname, "encryptedPassword") == 0 ||
465 strcmp(defel->defname, "unencryptedPassword") == 0)
469 (errcode(ERRCODE_SYNTAX_ERROR),
470 errmsg("conflicting or redundant options")));
472 if (strcmp(defel->defname, "encryptedPassword") == 0)
473 encrypt_password = true;
474 else if (strcmp(defel->defname, "unencryptedPassword") == 0)
475 encrypt_password = false;
477 else if (strcmp(defel->defname, "superuser") == 0)
481 (errcode(ERRCODE_SYNTAX_ERROR),
482 errmsg("conflicting or redundant options")));
485 else if (strcmp(defel->defname, "inherit") == 0)
489 (errcode(ERRCODE_SYNTAX_ERROR),
490 errmsg("conflicting or redundant options")));
493 else if (strcmp(defel->defname, "createrole") == 0)
497 (errcode(ERRCODE_SYNTAX_ERROR),
498 errmsg("conflicting or redundant options")));
501 else if (strcmp(defel->defname, "createdb") == 0)
505 (errcode(ERRCODE_SYNTAX_ERROR),
506 errmsg("conflicting or redundant options")));
509 else if (strcmp(defel->defname, "canlogin") == 0)
513 (errcode(ERRCODE_SYNTAX_ERROR),
514 errmsg("conflicting or redundant options")));
517 else if (strcmp(defel->defname, "connectionlimit") == 0)
521 (errcode(ERRCODE_SYNTAX_ERROR),
522 errmsg("conflicting or redundant options")));
525 else if (strcmp(defel->defname, "rolemembers") == 0 &&
530 (errcode(ERRCODE_SYNTAX_ERROR),
531 errmsg("conflicting or redundant options")));
532 drolemembers = defel;
534 else if (strcmp(defel->defname, "validUntil") == 0)
538 (errcode(ERRCODE_SYNTAX_ERROR),
539 errmsg("conflicting or redundant options")));
543 elog(ERROR, "option \"%s\" not recognized",
547 if (dpassword && dpassword->arg)
548 password = strVal(dpassword->arg);
550 issuper = intVal(dissuper->arg);
552 inherit = intVal(dinherit->arg);
554 createrole = intVal(dcreaterole->arg);
556 createdb = intVal(dcreatedb->arg);
558 canlogin = intVal(dcanlogin->arg);
561 connlimit = intVal(dconnlimit->arg);
564 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
565 errmsg("invalid connection limit: %d", connlimit)));
568 rolemembers = (List *) drolemembers->arg;
570 validUntil = strVal(dvalidUntil->arg);
573 * Scan the pg_authid relation to be certain the user exists.
575 pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
576 pg_authid_dsc = RelationGetDescr(pg_authid_rel);
578 tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
579 if (!HeapTupleIsValid(tuple))
581 (errcode(ERRCODE_UNDEFINED_OBJECT),
582 errmsg("role \"%s\" does not exist", stmt->role)));
584 roleid = HeapTupleGetOid(tuple);
587 * To mess with a superuser you gotta be superuser; else you need
588 * createrole, or just want to change your own password
590 if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
594 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
595 errmsg("must be superuser to alter superusers")));
597 else if (!have_createrole_privilege())
607 roleid == GetUserId()))
609 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
610 errmsg("permission denied")));
613 /* Convert validuntil to internal form */
616 validUntil_datum = DirectFunctionCall3(timestamptz_in,
617 CStringGetDatum(validUntil),
618 ObjectIdGetDatum(InvalidOid),
620 validUntil_null = false;
624 /* fetch existing setting in case hook needs it */
625 validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
626 Anum_pg_authid_rolvaliduntil,
631 * Call the password checking hook if there is one defined
633 if (check_password_hook && password)
634 (*check_password_hook) (stmt->role,
636 isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
641 * Build an updated tuple, perusing the information just obtained
643 MemSet(new_record, 0, sizeof(new_record));
644 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
645 MemSet(new_record_repl, false, sizeof(new_record_repl));
648 * issuper/createrole/catupdate/etc
650 * XXX It's rather unclear how to handle catupdate. It's probably best to
651 * keep it equal to the superuser status, otherwise you could end up with
652 * a situation where no existing superuser can alter the catalogs,
653 * including pg_authid!
657 new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
658 new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
660 new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);
661 new_record_repl[Anum_pg_authid_rolcatupdate - 1] = true;
666 new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
667 new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
672 new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
673 new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
678 new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
679 new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
684 new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
685 new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
690 new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
691 new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
697 if (!encrypt_password || isMD5(password))
698 new_record[Anum_pg_authid_rolpassword - 1] =
699 CStringGetTextDatum(password);
702 if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
704 elog(ERROR, "password encryption failed");
705 new_record[Anum_pg_authid_rolpassword - 1] =
706 CStringGetTextDatum(encrypted_password);
708 new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
712 if (dpassword && dpassword->arg == NULL)
714 new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
715 new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
719 new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
720 new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
721 new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
723 new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
724 new_record_nulls, new_record_repl);
725 simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple);
728 CatalogUpdateIndexes(pg_authid_rel, new_tuple);
730 ReleaseSysCache(tuple);
731 heap_freetuple(new_tuple);
734 * Advance command counter so we can see new record; else tests in
735 * AddRoleMems may fail.
738 CommandCounterIncrement();
740 if (stmt->action == +1) /* add members to role */
741 AddRoleMems(stmt->role, roleid,
742 rolemembers, roleNamesToIds(rolemembers),
744 else if (stmt->action == -1) /* drop members from role */
745 DelRoleMems(stmt->role, roleid,
746 rolemembers, roleNamesToIds(rolemembers),
750 * Close pg_authid, but keep lock till commit.
752 heap_close(pg_authid_rel, NoLock);
760 AlterRoleSet(AlterRoleSetStmt *stmt)
763 Oid databaseid = InvalidOid;
765 roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
767 if (!HeapTupleIsValid(roletuple))
769 (errcode(ERRCODE_UNDEFINED_OBJECT),
770 errmsg("role \"%s\" does not exist", stmt->role)));
773 * Obtain a lock on the role and make sure it didn't go away in the
776 shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple));
779 * To mess with a superuser you gotta be superuser; else you need
780 * createrole, or just want to change your own settings
782 if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
786 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
787 errmsg("must be superuser to alter superusers")));
791 if (!have_createrole_privilege() &&
792 HeapTupleGetOid(roletuple) != GetUserId())
794 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
795 errmsg("permission denied")));
798 /* look up and lock the database, if specified */
799 if (stmt->database != NULL)
801 databaseid = get_database_oid(stmt->database, false);
802 shdepLockAndCheckObject(DatabaseRelationId, databaseid);
805 AlterSetting(databaseid, HeapTupleGetOid(roletuple), stmt->setstmt);
806 ReleaseSysCache(roletuple);
814 DropRole(DropRoleStmt *stmt)
816 Relation pg_authid_rel,
820 if (!have_createrole_privilege())
822 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
823 errmsg("permission denied to drop role")));
826 * Scan the pg_authid relation to find the Oid of the role(s) to be
829 pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
830 pg_auth_members_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
832 foreach(item, stmt->roles)
834 const char *role = strVal(lfirst(item));
843 tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
844 if (!HeapTupleIsValid(tuple))
846 if (!stmt->missing_ok)
849 (errcode(ERRCODE_UNDEFINED_OBJECT),
850 errmsg("role \"%s\" does not exist", role)));
855 (errmsg("role \"%s\" does not exist, skipping",
862 roleid = HeapTupleGetOid(tuple);
864 if (roleid == GetUserId())
866 (errcode(ERRCODE_OBJECT_IN_USE),
867 errmsg("current user cannot be dropped")));
868 if (roleid == GetOuterUserId())
870 (errcode(ERRCODE_OBJECT_IN_USE),
871 errmsg("current user cannot be dropped")));
872 if (roleid == GetSessionUserId())
874 (errcode(ERRCODE_OBJECT_IN_USE),
875 errmsg("session user cannot be dropped")));
878 * For safety's sake, we allow createrole holders to drop ordinary
879 * roles but not superuser roles. This is mainly to avoid the
880 * scenario where you accidentally drop the last superuser.
882 if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper &&
885 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
886 errmsg("must be superuser to drop superusers")));
889 * Lock the role, so nobody can add dependencies to her while we drop
890 * her. We keep the lock until the end of transaction.
892 LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);
894 /* Check for pg_shdepend entries depending on this role */
895 if (checkSharedDependencies(AuthIdRelationId, roleid,
896 &detail, &detail_log))
898 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
899 errmsg("role \"%s\" cannot be dropped because some objects depend on it",
901 errdetail("%s", detail),
902 errdetail_log("%s", detail_log)));
905 * Remove the role from the pg_authid table
907 simple_heap_delete(pg_authid_rel, &tuple->t_self);
909 ReleaseSysCache(tuple);
912 * Remove role from the pg_auth_members table. We have to remove all
913 * tuples that show it as either a role or a member.
915 * XXX what about grantor entries? Maybe we should do one heap scan.
917 ScanKeyInit(&scankey,
918 Anum_pg_auth_members_roleid,
919 BTEqualStrategyNumber, F_OIDEQ,
920 ObjectIdGetDatum(roleid));
922 sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
923 true, SnapshotNow, 1, &scankey);
925 while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
927 simple_heap_delete(pg_auth_members_rel, &tmp_tuple->t_self);
930 systable_endscan(sscan);
932 ScanKeyInit(&scankey,
933 Anum_pg_auth_members_member,
934 BTEqualStrategyNumber, F_OIDEQ,
935 ObjectIdGetDatum(roleid));
937 sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
938 true, SnapshotNow, 1, &scankey);
940 while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
942 simple_heap_delete(pg_auth_members_rel, &tmp_tuple->t_self);
945 systable_endscan(sscan);
948 * Remove any comments on this role.
950 DeleteSharedComments(roleid, AuthIdRelationId);
953 * Remove settings for this role.
955 DropSetting(InvalidOid, roleid);
958 * Advance command counter so that later iterations of this loop will
959 * see the changes already made. This is essential if, for example,
960 * we are trying to drop both a role and one of its direct members ---
961 * we'll get an error if we try to delete the linking pg_auth_members
962 * tuple twice. (We do not need a CCI between the two delete loops
963 * above, because it's not allowed for a role to directly contain
966 CommandCounterIncrement();
970 * Now we can clean up; but keep locks until commit.
972 heap_close(pg_auth_members_rel, NoLock);
973 heap_close(pg_authid_rel, NoLock);
980 RenameRole(const char *oldname, const char *newname)
988 Datum repl_val[Natts_pg_authid];
989 bool repl_null[Natts_pg_authid];
990 bool repl_repl[Natts_pg_authid];
994 rel = heap_open(AuthIdRelationId, RowExclusiveLock);
995 dsc = RelationGetDescr(rel);
997 oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
998 if (!HeapTupleIsValid(oldtuple))
1000 (errcode(ERRCODE_UNDEFINED_OBJECT),
1001 errmsg("role \"%s\" does not exist", oldname)));
1004 * XXX Client applications probably store the session user somewhere, so
1005 * renaming it could cause confusion. On the other hand, there may not be
1006 * an actual problem besides a little confusion, so think about this and
1007 * decide. Same for SET ROLE ... we don't restrict renaming the current
1008 * effective userid, though.
1011 roleid = HeapTupleGetOid(oldtuple);
1013 if (roleid == GetSessionUserId())
1015 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1016 errmsg("session user cannot be renamed")));
1017 if (roleid == GetOuterUserId())
1019 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1020 errmsg("current user cannot be renamed")));
1022 /* make sure the new name doesn't exist */
1023 if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
1025 (errcode(ERRCODE_DUPLICATE_OBJECT),
1026 errmsg("role \"%s\" already exists", newname)));
1028 if (strcmp(newname, "public") == 0 ||
1029 strcmp(newname, "none") == 0)
1031 (errcode(ERRCODE_RESERVED_NAME),
1032 errmsg("role name \"%s\" is reserved",
1036 * createrole is enough privilege unless you want to mess with a superuser
1038 if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
1042 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1043 errmsg("must be superuser to rename superusers")));
1047 if (!have_createrole_privilege())
1049 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1050 errmsg("permission denied to rename role")));
1053 /* OK, construct the modified tuple */
1054 for (i = 0; i < Natts_pg_authid; i++)
1055 repl_repl[i] = false;
1057 repl_repl[Anum_pg_authid_rolname - 1] = true;
1058 repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
1059 CStringGetDatum(newname));
1060 repl_null[Anum_pg_authid_rolname - 1] = false;
1062 datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
1064 if (!isnull && isMD5(TextDatumGetCString(datum)))
1066 /* MD5 uses the username as salt, so just clear it on a rename */
1067 repl_repl[Anum_pg_authid_rolpassword - 1] = true;
1068 repl_null[Anum_pg_authid_rolpassword - 1] = true;
1071 (errmsg("MD5 password cleared because of role rename")));
1074 newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
1075 simple_heap_update(rel, &oldtuple->t_self, newtuple);
1077 CatalogUpdateIndexes(rel, newtuple);
1079 ReleaseSysCache(oldtuple);
1082 * Close pg_authid, but keep lock till commit.
1084 heap_close(rel, NoLock);
1090 * Grant/Revoke roles to/from roles
1093 GrantRole(GrantRoleStmt *stmt)
1095 Relation pg_authid_rel;
1101 grantor = get_role_oid(stmt->grantor, false);
1103 grantor = GetUserId();
1105 grantee_ids = roleNamesToIds(stmt->grantee_roles);
1107 /* AccessShareLock is enough since we aren't modifying pg_authid */
1108 pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
1111 * Step through all of the granted roles and add/remove entries for the
1112 * grantees, or, if admin_opt is set, then just add/remove the admin
1115 * Note: Permissions checking is done by AddRoleMems/DelRoleMems
1117 foreach(item, stmt->granted_roles)
1119 AccessPriv *priv = (AccessPriv *) lfirst(item);
1120 char *rolename = priv->priv_name;
1123 /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
1124 if (rolename == NULL || priv->cols != NIL)
1126 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1127 errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
1129 roleid = get_role_oid(rolename, false);
1131 AddRoleMems(rolename, roleid,
1132 stmt->grantee_roles, grantee_ids,
1133 grantor, stmt->admin_opt);
1135 DelRoleMems(rolename, roleid,
1136 stmt->grantee_roles, grantee_ids,
1141 * Close pg_authid, but keep lock till commit.
1143 heap_close(pg_authid_rel, NoLock);
1149 * Drop the objects owned by a given list of roles.
1152 DropOwnedObjects(DropOwnedStmt *stmt)
1154 List *role_ids = roleNamesToIds(stmt->roles);
1157 /* Check privileges */
1158 foreach(cell, role_ids)
1160 Oid roleid = lfirst_oid(cell);
1162 if (!has_privs_of_role(GetUserId(), roleid))
1164 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1165 errmsg("permission denied to drop objects")));
1169 shdepDropOwned(role_ids, stmt->behavior);
1173 * ReassignOwnedObjects
1175 * Give the objects owned by a given list of roles away to another user.
1178 ReassignOwnedObjects(ReassignOwnedStmt *stmt)
1180 List *role_ids = roleNamesToIds(stmt->roles);
1184 /* Check privileges */
1185 foreach(cell, role_ids)
1187 Oid roleid = lfirst_oid(cell);
1189 if (!has_privs_of_role(GetUserId(), roleid))
1191 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1192 errmsg("permission denied to reassign objects")));
1195 /* Must have privileges on the receiving side too */
1196 newrole = get_role_oid(stmt->newrole, false);
1198 if (!has_privs_of_role(GetUserId(), newrole))
1200 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1201 errmsg("permission denied to reassign objects")));
1204 shdepReassignOwned(role_ids, newrole);
1210 * Given a list of role names (as String nodes), generate a list of role OIDs
1211 * in the same order.
1214 roleNamesToIds(List *memberNames)
1219 foreach(l, memberNames)
1221 char *rolename = strVal(lfirst(l));
1222 Oid roleid = get_role_oid(rolename, false);
1224 result = lappend_oid(result, roleid);
1230 * AddRoleMems -- Add given members to the specified role
1232 * rolename: name of role to add to (used only for error messages)
1233 * roleid: OID of role to add to
1234 * memberNames: list of names of roles to add (used only for error messages)
1235 * memberIds: OIDs of roles to add
1236 * grantorId: who is granting the membership
1237 * admin_opt: granting admin option?
1239 * Note: caller is responsible for calling auth_file_update_needed().
1242 AddRoleMems(const char *rolename, Oid roleid,
1243 List *memberNames, List *memberIds,
1244 Oid grantorId, bool admin_opt)
1246 Relation pg_authmem_rel;
1247 TupleDesc pg_authmem_dsc;
1251 Assert(list_length(memberNames) == list_length(memberIds));
1253 /* Skip permission check if nothing to do */
1258 * Check permissions: must have createrole or admin option on the role to
1259 * be changed. To mess with a superuser role, you gotta be superuser.
1261 if (superuser_arg(roleid))
1265 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1266 errmsg("must be superuser to alter superusers")));
1270 if (!have_createrole_privilege() &&
1271 !is_admin_of_role(grantorId, roleid))
1273 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1274 errmsg("must have admin option on role \"%s\"",
1278 /* XXX not sure about this check */
1279 if (grantorId != GetUserId() && !superuser())
1281 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1282 errmsg("must be superuser to set grantor")));
1284 pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
1285 pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1287 forboth(nameitem, memberNames, iditem, memberIds)
1289 const char *membername = strVal(lfirst(nameitem));
1290 Oid memberid = lfirst_oid(iditem);
1291 HeapTuple authmem_tuple;
1293 Datum new_record[Natts_pg_auth_members];
1294 bool new_record_nulls[Natts_pg_auth_members];
1295 bool new_record_repl[Natts_pg_auth_members];
1298 * Refuse creation of membership loops, including the trivial case
1299 * where a role is made a member of itself. We do this by checking to
1300 * see if the target role is already a member of the proposed member
1301 * role. We have to ignore possible superuserness, however, else we
1302 * could never grant membership in a superuser-privileged role.
1304 if (is_member_of_role_nosuper(roleid, memberid))
1306 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1307 (errmsg("role \"%s\" is a member of role \"%s\"",
1308 rolename, membername))));
1311 * Check if entry for this role/member already exists; if so, give
1312 * warning unless we are adding admin option.
1314 authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
1315 ObjectIdGetDatum(roleid),
1316 ObjectIdGetDatum(memberid));
1317 if (HeapTupleIsValid(authmem_tuple) &&
1319 ((Form_pg_auth_members) GETSTRUCT(authmem_tuple))->admin_option))
1322 (errmsg("role \"%s\" is already a member of role \"%s\"",
1323 membername, rolename)));
1324 ReleaseSysCache(authmem_tuple);
1328 /* Build a tuple to insert or update */
1329 MemSet(new_record, 0, sizeof(new_record));
1330 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1331 MemSet(new_record_repl, false, sizeof(new_record_repl));
1333 new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid);
1334 new_record[Anum_pg_auth_members_member - 1] = ObjectIdGetDatum(memberid);
1335 new_record[Anum_pg_auth_members_grantor - 1] = ObjectIdGetDatum(grantorId);
1336 new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt);
1338 if (HeapTupleIsValid(authmem_tuple))
1340 new_record_repl[Anum_pg_auth_members_grantor - 1] = true;
1341 new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
1342 tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1344 new_record_nulls, new_record_repl);
1345 simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
1346 CatalogUpdateIndexes(pg_authmem_rel, tuple);
1347 ReleaseSysCache(authmem_tuple);
1351 tuple = heap_form_tuple(pg_authmem_dsc,
1352 new_record, new_record_nulls);
1353 simple_heap_insert(pg_authmem_rel, tuple);
1354 CatalogUpdateIndexes(pg_authmem_rel, tuple);
1357 /* CCI after each change, in case there are duplicates in list */
1358 CommandCounterIncrement();
1362 * Close pg_authmem, but keep lock till commit.
1364 heap_close(pg_authmem_rel, NoLock);
1368 * DelRoleMems -- Remove given members from the specified role
1370 * rolename: name of role to del from (used only for error messages)
1371 * roleid: OID of role to del from
1372 * memberNames: list of names of roles to del (used only for error messages)
1373 * memberIds: OIDs of roles to del
1374 * admin_opt: remove admin option only?
1376 * Note: caller is responsible for calling auth_file_update_needed().
1379 DelRoleMems(const char *rolename, Oid roleid,
1380 List *memberNames, List *memberIds,
1383 Relation pg_authmem_rel;
1384 TupleDesc pg_authmem_dsc;
1388 Assert(list_length(memberNames) == list_length(memberIds));
1390 /* Skip permission check if nothing to do */
1395 * Check permissions: must have createrole or admin option on the role to
1396 * be changed. To mess with a superuser role, you gotta be superuser.
1398 if (superuser_arg(roleid))
1402 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1403 errmsg("must be superuser to alter superusers")));
1407 if (!have_createrole_privilege() &&
1408 !is_admin_of_role(GetUserId(), roleid))
1410 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1411 errmsg("must have admin option on role \"%s\"",
1415 pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
1416 pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1418 forboth(nameitem, memberNames, iditem, memberIds)
1420 const char *membername = strVal(lfirst(nameitem));
1421 Oid memberid = lfirst_oid(iditem);
1422 HeapTuple authmem_tuple;
1425 * Find entry for this role/member
1427 authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
1428 ObjectIdGetDatum(roleid),
1429 ObjectIdGetDatum(memberid));
1430 if (!HeapTupleIsValid(authmem_tuple))
1433 (errmsg("role \"%s\" is not a member of role \"%s\"",
1434 membername, rolename)));
1440 /* Remove the entry altogether */
1441 simple_heap_delete(pg_authmem_rel, &authmem_tuple->t_self);
1445 /* Just turn off the admin option */
1447 Datum new_record[Natts_pg_auth_members];
1448 bool new_record_nulls[Natts_pg_auth_members];
1449 bool new_record_repl[Natts_pg_auth_members];
1451 /* Build a tuple to update with */
1452 MemSet(new_record, 0, sizeof(new_record));
1453 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1454 MemSet(new_record_repl, false, sizeof(new_record_repl));
1456 new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false);
1457 new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
1459 tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1461 new_record_nulls, new_record_repl);
1462 simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
1463 CatalogUpdateIndexes(pg_authmem_rel, tuple);
1466 ReleaseSysCache(authmem_tuple);
1468 /* CCI after each change, in case there are duplicates in list */
1469 CommandCounterIncrement();
1473 * Close pg_authmem, but keep lock till commit.
1475 heap_close(pg_authmem_rel, NoLock);