1 /*-------------------------------------------------------------------------
4 * Commands for manipulating roles (formerly called users).
6 * Portions Copyright (c) 1996-2011, 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 bool isreplication = false; /* Is this a replication role? */
98 int connlimit = -1; /* maximum connections allowed */
99 List *addroleto = NIL; /* roles to make this a member of */
100 List *rolemembers = NIL; /* roles to be members of this role */
101 List *adminmembers = NIL; /* roles to be admins of this role */
102 char *validUntil = NULL; /* time the login is valid until */
103 Datum validUntil_datum; /* same, as timestamptz Datum */
104 bool validUntil_null;
105 DefElem *dpassword = NULL;
106 DefElem *dissuper = NULL;
107 DefElem *dinherit = NULL;
108 DefElem *dcreaterole = NULL;
109 DefElem *dcreatedb = NULL;
110 DefElem *dcanlogin = NULL;
111 DefElem *disreplication = NULL;
112 DefElem *dconnlimit = NULL;
113 DefElem *daddroleto = NULL;
114 DefElem *drolemembers = NULL;
115 DefElem *dadminmembers = NULL;
116 DefElem *dvalidUntil = NULL;
118 /* The defaults can vary depending on the original statement type */
119 switch (stmt->stmt_type)
125 /* may eventually want inherit to default to false here */
131 /* Extract options from the statement node tree */
132 foreach(option, stmt->options)
134 DefElem *defel = (DefElem *) lfirst(option);
136 if (strcmp(defel->defname, "password") == 0 ||
137 strcmp(defel->defname, "encryptedPassword") == 0 ||
138 strcmp(defel->defname, "unencryptedPassword") == 0)
142 (errcode(ERRCODE_SYNTAX_ERROR),
143 errmsg("conflicting or redundant options")));
145 if (strcmp(defel->defname, "encryptedPassword") == 0)
146 encrypt_password = true;
147 else if (strcmp(defel->defname, "unencryptedPassword") == 0)
148 encrypt_password = false;
150 else if (strcmp(defel->defname, "sysid") == 0)
153 (errmsg("SYSID can no longer be specified")));
155 else if (strcmp(defel->defname, "superuser") == 0)
159 (errcode(ERRCODE_SYNTAX_ERROR),
160 errmsg("conflicting or redundant options")));
163 else if (strcmp(defel->defname, "inherit") == 0)
167 (errcode(ERRCODE_SYNTAX_ERROR),
168 errmsg("conflicting or redundant options")));
171 else if (strcmp(defel->defname, "createrole") == 0)
175 (errcode(ERRCODE_SYNTAX_ERROR),
176 errmsg("conflicting or redundant options")));
179 else if (strcmp(defel->defname, "createdb") == 0)
183 (errcode(ERRCODE_SYNTAX_ERROR),
184 errmsg("conflicting or redundant options")));
187 else if (strcmp(defel->defname, "canlogin") == 0)
191 (errcode(ERRCODE_SYNTAX_ERROR),
192 errmsg("conflicting or redundant options")));
195 else if (strcmp(defel->defname, "isreplication") == 0)
199 (errcode(ERRCODE_SYNTAX_ERROR),
200 errmsg("conflicting or redundant options")));
201 disreplication = defel;
203 else if (strcmp(defel->defname, "connectionlimit") == 0)
207 (errcode(ERRCODE_SYNTAX_ERROR),
208 errmsg("conflicting or redundant options")));
211 else if (strcmp(defel->defname, "addroleto") == 0)
215 (errcode(ERRCODE_SYNTAX_ERROR),
216 errmsg("conflicting or redundant options")));
219 else if (strcmp(defel->defname, "rolemembers") == 0)
223 (errcode(ERRCODE_SYNTAX_ERROR),
224 errmsg("conflicting or redundant options")));
225 drolemembers = defel;
227 else if (strcmp(defel->defname, "adminmembers") == 0)
231 (errcode(ERRCODE_SYNTAX_ERROR),
232 errmsg("conflicting or redundant options")));
233 dadminmembers = defel;
235 else if (strcmp(defel->defname, "validUntil") == 0)
239 (errcode(ERRCODE_SYNTAX_ERROR),
240 errmsg("conflicting or redundant options")));
244 elog(ERROR, "option \"%s\" not recognized",
248 if (dpassword && dpassword->arg)
249 password = strVal(dpassword->arg);
251 issuper = intVal(dissuper->arg) != 0;
253 inherit = intVal(dinherit->arg) != 0;
255 createrole = intVal(dcreaterole->arg) != 0;
257 createdb = intVal(dcreatedb->arg) != 0;
259 canlogin = intVal(dcanlogin->arg) != 0;
261 isreplication = intVal(disreplication->arg) != 0;
264 connlimit = intVal(dconnlimit->arg);
267 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
268 errmsg("invalid connection limit: %d", connlimit)));
271 addroleto = (List *) daddroleto->arg;
273 rolemembers = (List *) drolemembers->arg;
275 adminmembers = (List *) dadminmembers->arg;
277 validUntil = strVal(dvalidUntil->arg);
279 /* Check some permissions first */
284 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
285 errmsg("must be superuser to create superusers")));
287 else if (isreplication)
291 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
292 errmsg("must be superuser to create replication users")));
296 if (!have_createrole_privilege())
298 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
299 errmsg("permission denied to create role")));
302 if (strcmp(stmt->role, "public") == 0 ||
303 strcmp(stmt->role, "none") == 0)
305 (errcode(ERRCODE_RESERVED_NAME),
306 errmsg("role name \"%s\" is reserved",
310 * Check the pg_authid relation to be certain the role doesn't already
313 pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
314 pg_authid_dsc = RelationGetDescr(pg_authid_rel);
316 if (OidIsValid(get_role_oid(stmt->role, true)))
318 (errcode(ERRCODE_DUPLICATE_OBJECT),
319 errmsg("role \"%s\" already exists",
322 /* Convert validuntil to internal form */
325 validUntil_datum = DirectFunctionCall3(timestamptz_in,
326 CStringGetDatum(validUntil),
327 ObjectIdGetDatum(InvalidOid),
329 validUntil_null = false;
333 validUntil_datum = (Datum) 0;
334 validUntil_null = true;
338 * Call the password checking hook if there is one defined
340 if (check_password_hook && password)
341 (*check_password_hook) (stmt->role,
343 isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
348 * Build a tuple to insert
350 MemSet(new_record, 0, sizeof(new_record));
351 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
353 new_record[Anum_pg_authid_rolname - 1] =
354 DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
356 new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
357 new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
358 new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
359 new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
360 /* superuser gets catupdate right by default */
361 new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
362 new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
363 new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
364 new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
368 if (!encrypt_password || isMD5(password))
369 new_record[Anum_pg_authid_rolpassword - 1] =
370 CStringGetTextDatum(password);
373 if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
375 elog(ERROR, "password encryption failed");
376 new_record[Anum_pg_authid_rolpassword - 1] =
377 CStringGetTextDatum(encrypted_password);
381 new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
383 new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
384 new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
386 tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
389 * Insert new record in the pg_authid table
391 roleid = simple_heap_insert(pg_authid_rel, tuple);
392 CatalogUpdateIndexes(pg_authid_rel, tuple);
395 * Advance command counter so we can see new record; else tests in
396 * AddRoleMems may fail.
398 if (addroleto || adminmembers || rolemembers)
399 CommandCounterIncrement();
402 * Add the new role to the specified existing roles.
404 foreach(item, addroleto)
406 char *oldrolename = strVal(lfirst(item));
407 Oid oldroleid = get_role_oid(oldrolename, false);
409 AddRoleMems(oldrolename, oldroleid,
410 list_make1(makeString(stmt->role)),
411 list_make1_oid(roleid),
416 * Add the specified members to this new role. adminmembers get the admin
417 * option, rolemembers don't.
419 AddRoleMems(stmt->role, roleid,
420 adminmembers, roleNamesToIds(adminmembers),
422 AddRoleMems(stmt->role, roleid,
423 rolemembers, roleNamesToIds(rolemembers),
426 /* Post creation hook for new role */
427 InvokeObjectAccessHook(OAT_POST_CREATE, AuthIdRelationId, roleid, 0);
430 * Close pg_authid, but keep lock till commit.
432 heap_close(pg_authid_rel, NoLock);
439 * Note: the rolemembers option accepted here is intended to support the
440 * backwards-compatible ALTER GROUP syntax. Although it will work to say
441 * "ALTER ROLE role ROLE rolenames", we don't document it.
444 AlterRole(AlterRoleStmt *stmt)
446 Datum new_record[Natts_pg_authid];
447 bool new_record_nulls[Natts_pg_authid];
448 bool new_record_repl[Natts_pg_authid];
449 Relation pg_authid_rel;
450 TupleDesc pg_authid_dsc;
454 char *password = NULL; /* user password */
455 bool encrypt_password = Password_encryption; /* encrypt password? */
456 char encrypted_password[MD5_PASSWD_LEN + 1];
457 int issuper = -1; /* Make the user a superuser? */
458 int inherit = -1; /* Auto inherit privileges? */
459 int createrole = -1; /* Can this user create roles? */
460 int createdb = -1; /* Can the user create databases? */
461 int canlogin = -1; /* Can this user login? */
462 int isreplication = -1; /* Is this a replication role? */
463 int connlimit = -1; /* maximum connections allowed */
464 List *rolemembers = NIL; /* roles to be added/removed */
465 char *validUntil = NULL; /* time the login is valid until */
466 Datum validUntil_datum; /* same, as timestamptz Datum */
467 bool validUntil_null;
468 DefElem *dpassword = NULL;
469 DefElem *dissuper = NULL;
470 DefElem *dinherit = NULL;
471 DefElem *dcreaterole = NULL;
472 DefElem *dcreatedb = NULL;
473 DefElem *dcanlogin = NULL;
474 DefElem *disreplication = NULL;
475 DefElem *dconnlimit = NULL;
476 DefElem *drolemembers = NULL;
477 DefElem *dvalidUntil = NULL;
480 /* Extract options from the statement node tree */
481 foreach(option, stmt->options)
483 DefElem *defel = (DefElem *) lfirst(option);
485 if (strcmp(defel->defname, "password") == 0 ||
486 strcmp(defel->defname, "encryptedPassword") == 0 ||
487 strcmp(defel->defname, "unencryptedPassword") == 0)
491 (errcode(ERRCODE_SYNTAX_ERROR),
492 errmsg("conflicting or redundant options")));
494 if (strcmp(defel->defname, "encryptedPassword") == 0)
495 encrypt_password = true;
496 else if (strcmp(defel->defname, "unencryptedPassword") == 0)
497 encrypt_password = false;
499 else if (strcmp(defel->defname, "superuser") == 0)
503 (errcode(ERRCODE_SYNTAX_ERROR),
504 errmsg("conflicting or redundant options")));
507 else if (strcmp(defel->defname, "inherit") == 0)
511 (errcode(ERRCODE_SYNTAX_ERROR),
512 errmsg("conflicting or redundant options")));
515 else if (strcmp(defel->defname, "createrole") == 0)
519 (errcode(ERRCODE_SYNTAX_ERROR),
520 errmsg("conflicting or redundant options")));
523 else if (strcmp(defel->defname, "createdb") == 0)
527 (errcode(ERRCODE_SYNTAX_ERROR),
528 errmsg("conflicting or redundant options")));
531 else if (strcmp(defel->defname, "canlogin") == 0)
535 (errcode(ERRCODE_SYNTAX_ERROR),
536 errmsg("conflicting or redundant options")));
539 else if (strcmp(defel->defname, "isreplication") == 0)
543 (errcode(ERRCODE_SYNTAX_ERROR),
544 errmsg("conflicting or redundant options")));
545 disreplication = defel;
547 else if (strcmp(defel->defname, "connectionlimit") == 0)
551 (errcode(ERRCODE_SYNTAX_ERROR),
552 errmsg("conflicting or redundant options")));
555 else if (strcmp(defel->defname, "rolemembers") == 0 &&
560 (errcode(ERRCODE_SYNTAX_ERROR),
561 errmsg("conflicting or redundant options")));
562 drolemembers = defel;
564 else if (strcmp(defel->defname, "validUntil") == 0)
568 (errcode(ERRCODE_SYNTAX_ERROR),
569 errmsg("conflicting or redundant options")));
573 elog(ERROR, "option \"%s\" not recognized",
577 if (dpassword && dpassword->arg)
578 password = strVal(dpassword->arg);
580 issuper = intVal(dissuper->arg);
582 inherit = intVal(dinherit->arg);
584 createrole = intVal(dcreaterole->arg);
586 createdb = intVal(dcreatedb->arg);
588 canlogin = intVal(dcanlogin->arg);
590 isreplication = intVal(disreplication->arg);
593 connlimit = intVal(dconnlimit->arg);
596 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
597 errmsg("invalid connection limit: %d", connlimit)));
600 rolemembers = (List *) drolemembers->arg;
602 validUntil = strVal(dvalidUntil->arg);
605 * Scan the pg_authid relation to be certain the user exists.
607 pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
608 pg_authid_dsc = RelationGetDescr(pg_authid_rel);
610 tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
611 if (!HeapTupleIsValid(tuple))
613 (errcode(ERRCODE_UNDEFINED_OBJECT),
614 errmsg("role \"%s\" does not exist", stmt->role)));
616 roleid = HeapTupleGetOid(tuple);
619 * To mess with a superuser you gotta be superuser; else you need
620 * createrole, or just want to change your own password
622 if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
626 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
627 errmsg("must be superuser to alter superusers")));
629 else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
633 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
634 errmsg("must be superuser to alter replication users")));
636 else if (!have_createrole_privilege())
647 roleid == GetUserId()))
649 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
650 errmsg("permission denied")));
653 /* Convert validuntil to internal form */
656 validUntil_datum = DirectFunctionCall3(timestamptz_in,
657 CStringGetDatum(validUntil),
658 ObjectIdGetDatum(InvalidOid),
660 validUntil_null = false;
664 /* fetch existing setting in case hook needs it */
665 validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
666 Anum_pg_authid_rolvaliduntil,
671 * Call the password checking hook if there is one defined
673 if (check_password_hook && password)
674 (*check_password_hook) (stmt->role,
676 isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
681 * Build an updated tuple, perusing the information just obtained
683 MemSet(new_record, 0, sizeof(new_record));
684 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
685 MemSet(new_record_repl, false, sizeof(new_record_repl));
688 * issuper/createrole/catupdate/etc
690 * XXX It's rather unclear how to handle catupdate. It's probably best to
691 * keep it equal to the superuser status, otherwise you could end up with
692 * a situation where no existing superuser can alter the catalogs,
693 * including pg_authid!
697 new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
698 new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
700 new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);
701 new_record_repl[Anum_pg_authid_rolcatupdate - 1] = true;
706 new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
707 new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
712 new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
713 new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
718 new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
719 new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
724 new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
725 new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
728 if (isreplication >= 0)
730 new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication > 0);
731 new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
736 new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
737 new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
743 if (!encrypt_password || isMD5(password))
744 new_record[Anum_pg_authid_rolpassword - 1] =
745 CStringGetTextDatum(password);
748 if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
750 elog(ERROR, "password encryption failed");
751 new_record[Anum_pg_authid_rolpassword - 1] =
752 CStringGetTextDatum(encrypted_password);
754 new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
758 if (dpassword && dpassword->arg == NULL)
760 new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
761 new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
765 new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
766 new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
767 new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
769 new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
770 new_record_nulls, new_record_repl);
771 simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple);
774 CatalogUpdateIndexes(pg_authid_rel, new_tuple);
776 ReleaseSysCache(tuple);
777 heap_freetuple(new_tuple);
780 * Advance command counter so we can see new record; else tests in
781 * AddRoleMems may fail.
784 CommandCounterIncrement();
786 if (stmt->action == +1) /* add members to role */
787 AddRoleMems(stmt->role, roleid,
788 rolemembers, roleNamesToIds(rolemembers),
790 else if (stmt->action == -1) /* drop members from role */
791 DelRoleMems(stmt->role, roleid,
792 rolemembers, roleNamesToIds(rolemembers),
796 * Close pg_authid, but keep lock till commit.
798 heap_close(pg_authid_rel, NoLock);
806 AlterRoleSet(AlterRoleSetStmt *stmt)
809 Oid databaseid = InvalidOid;
811 roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
813 if (!HeapTupleIsValid(roletuple))
815 (errcode(ERRCODE_UNDEFINED_OBJECT),
816 errmsg("role \"%s\" does not exist", stmt->role)));
819 * Obtain a lock on the role and make sure it didn't go away in the
822 shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple));
825 * To mess with a superuser you gotta be superuser; else you need
826 * createrole, or just want to change your own settings
828 if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
832 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
833 errmsg("must be superuser to alter superusers")));
837 if (!have_createrole_privilege() &&
838 HeapTupleGetOid(roletuple) != GetUserId())
840 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
841 errmsg("permission denied")));
844 /* look up and lock the database, if specified */
845 if (stmt->database != NULL)
847 databaseid = get_database_oid(stmt->database, false);
848 shdepLockAndCheckObject(DatabaseRelationId, databaseid);
851 AlterSetting(databaseid, HeapTupleGetOid(roletuple), stmt->setstmt);
852 ReleaseSysCache(roletuple);
860 DropRole(DropRoleStmt *stmt)
862 Relation pg_authid_rel,
866 if (!have_createrole_privilege())
868 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
869 errmsg("permission denied to drop role")));
872 * Scan the pg_authid relation to find the Oid of the role(s) to be
875 pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
876 pg_auth_members_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
878 foreach(item, stmt->roles)
880 const char *role = strVal(lfirst(item));
889 tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
890 if (!HeapTupleIsValid(tuple))
892 if (!stmt->missing_ok)
895 (errcode(ERRCODE_UNDEFINED_OBJECT),
896 errmsg("role \"%s\" does not exist", role)));
901 (errmsg("role \"%s\" does not exist, skipping",
908 roleid = HeapTupleGetOid(tuple);
910 if (roleid == GetUserId())
912 (errcode(ERRCODE_OBJECT_IN_USE),
913 errmsg("current user cannot be dropped")));
914 if (roleid == GetOuterUserId())
916 (errcode(ERRCODE_OBJECT_IN_USE),
917 errmsg("current user cannot be dropped")));
918 if (roleid == GetSessionUserId())
920 (errcode(ERRCODE_OBJECT_IN_USE),
921 errmsg("session user cannot be dropped")));
924 * For safety's sake, we allow createrole holders to drop ordinary
925 * roles but not superuser roles. This is mainly to avoid the
926 * scenario where you accidentally drop the last superuser.
928 if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper &&
931 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
932 errmsg("must be superuser to drop superusers")));
935 * Lock the role, so nobody can add dependencies to her while we drop
936 * her. We keep the lock until the end of transaction.
938 LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);
940 /* Check for pg_shdepend entries depending on this role */
941 if (checkSharedDependencies(AuthIdRelationId, roleid,
942 &detail, &detail_log))
944 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
945 errmsg("role \"%s\" cannot be dropped because some objects depend on it",
947 errdetail("%s", detail),
948 errdetail_log("%s", detail_log)));
951 * Remove the role from the pg_authid table
953 simple_heap_delete(pg_authid_rel, &tuple->t_self);
955 ReleaseSysCache(tuple);
958 * Remove role from the pg_auth_members table. We have to remove all
959 * tuples that show it as either a role or a member.
961 * XXX what about grantor entries? Maybe we should do one heap scan.
963 ScanKeyInit(&scankey,
964 Anum_pg_auth_members_roleid,
965 BTEqualStrategyNumber, F_OIDEQ,
966 ObjectIdGetDatum(roleid));
968 sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
969 true, SnapshotNow, 1, &scankey);
971 while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
973 simple_heap_delete(pg_auth_members_rel, &tmp_tuple->t_self);
976 systable_endscan(sscan);
978 ScanKeyInit(&scankey,
979 Anum_pg_auth_members_member,
980 BTEqualStrategyNumber, F_OIDEQ,
981 ObjectIdGetDatum(roleid));
983 sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
984 true, SnapshotNow, 1, &scankey);
986 while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
988 simple_heap_delete(pg_auth_members_rel, &tmp_tuple->t_self);
991 systable_endscan(sscan);
994 * Remove any comments on this role.
996 DeleteSharedComments(roleid, AuthIdRelationId);
999 * Remove settings for this role.
1001 DropSetting(InvalidOid, roleid);
1004 * Advance command counter so that later iterations of this loop will
1005 * see the changes already made. This is essential if, for example,
1006 * we are trying to drop both a role and one of its direct members ---
1007 * we'll get an error if we try to delete the linking pg_auth_members
1008 * tuple twice. (We do not need a CCI between the two delete loops
1009 * above, because it's not allowed for a role to directly contain
1012 CommandCounterIncrement();
1016 * Now we can clean up; but keep locks until commit.
1018 heap_close(pg_auth_members_rel, NoLock);
1019 heap_close(pg_authid_rel, NoLock);
1026 RenameRole(const char *oldname, const char *newname)
1034 Datum repl_val[Natts_pg_authid];
1035 bool repl_null[Natts_pg_authid];
1036 bool repl_repl[Natts_pg_authid];
1040 rel = heap_open(AuthIdRelationId, RowExclusiveLock);
1041 dsc = RelationGetDescr(rel);
1043 oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
1044 if (!HeapTupleIsValid(oldtuple))
1046 (errcode(ERRCODE_UNDEFINED_OBJECT),
1047 errmsg("role \"%s\" does not exist", oldname)));
1050 * XXX Client applications probably store the session user somewhere, so
1051 * renaming it could cause confusion. On the other hand, there may not be
1052 * an actual problem besides a little confusion, so think about this and
1053 * decide. Same for SET ROLE ... we don't restrict renaming the current
1054 * effective userid, though.
1057 roleid = HeapTupleGetOid(oldtuple);
1059 if (roleid == GetSessionUserId())
1061 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1062 errmsg("session user cannot be renamed")));
1063 if (roleid == GetOuterUserId())
1065 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1066 errmsg("current user cannot be renamed")));
1068 /* make sure the new name doesn't exist */
1069 if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
1071 (errcode(ERRCODE_DUPLICATE_OBJECT),
1072 errmsg("role \"%s\" already exists", newname)));
1074 if (strcmp(newname, "public") == 0 ||
1075 strcmp(newname, "none") == 0)
1077 (errcode(ERRCODE_RESERVED_NAME),
1078 errmsg("role name \"%s\" is reserved",
1082 * createrole is enough privilege unless you want to mess with a superuser
1084 if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
1088 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1089 errmsg("must be superuser to rename superusers")));
1093 if (!have_createrole_privilege())
1095 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1096 errmsg("permission denied to rename role")));
1099 /* OK, construct the modified tuple */
1100 for (i = 0; i < Natts_pg_authid; i++)
1101 repl_repl[i] = false;
1103 repl_repl[Anum_pg_authid_rolname - 1] = true;
1104 repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
1105 CStringGetDatum(newname));
1106 repl_null[Anum_pg_authid_rolname - 1] = false;
1108 datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
1110 if (!isnull && isMD5(TextDatumGetCString(datum)))
1112 /* MD5 uses the username as salt, so just clear it on a rename */
1113 repl_repl[Anum_pg_authid_rolpassword - 1] = true;
1114 repl_null[Anum_pg_authid_rolpassword - 1] = true;
1117 (errmsg("MD5 password cleared because of role rename")));
1120 newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
1121 simple_heap_update(rel, &oldtuple->t_self, newtuple);
1123 CatalogUpdateIndexes(rel, newtuple);
1125 ReleaseSysCache(oldtuple);
1128 * Close pg_authid, but keep lock till commit.
1130 heap_close(rel, NoLock);
1136 * Grant/Revoke roles to/from roles
1139 GrantRole(GrantRoleStmt *stmt)
1141 Relation pg_authid_rel;
1147 grantor = get_role_oid(stmt->grantor, false);
1149 grantor = GetUserId();
1151 grantee_ids = roleNamesToIds(stmt->grantee_roles);
1153 /* AccessShareLock is enough since we aren't modifying pg_authid */
1154 pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
1157 * Step through all of the granted roles and add/remove entries for the
1158 * grantees, or, if admin_opt is set, then just add/remove the admin
1161 * Note: Permissions checking is done by AddRoleMems/DelRoleMems
1163 foreach(item, stmt->granted_roles)
1165 AccessPriv *priv = (AccessPriv *) lfirst(item);
1166 char *rolename = priv->priv_name;
1169 /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
1170 if (rolename == NULL || priv->cols != NIL)
1172 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1173 errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
1175 roleid = get_role_oid(rolename, false);
1177 AddRoleMems(rolename, roleid,
1178 stmt->grantee_roles, grantee_ids,
1179 grantor, stmt->admin_opt);
1181 DelRoleMems(rolename, roleid,
1182 stmt->grantee_roles, grantee_ids,
1187 * Close pg_authid, but keep lock till commit.
1189 heap_close(pg_authid_rel, NoLock);
1195 * Drop the objects owned by a given list of roles.
1198 DropOwnedObjects(DropOwnedStmt *stmt)
1200 List *role_ids = roleNamesToIds(stmt->roles);
1203 /* Check privileges */
1204 foreach(cell, role_ids)
1206 Oid roleid = lfirst_oid(cell);
1208 if (!has_privs_of_role(GetUserId(), roleid))
1210 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1211 errmsg("permission denied to drop objects")));
1215 shdepDropOwned(role_ids, stmt->behavior);
1219 * ReassignOwnedObjects
1221 * Give the objects owned by a given list of roles away to another user.
1224 ReassignOwnedObjects(ReassignOwnedStmt *stmt)
1226 List *role_ids = roleNamesToIds(stmt->roles);
1230 /* Check privileges */
1231 foreach(cell, role_ids)
1233 Oid roleid = lfirst_oid(cell);
1235 if (!has_privs_of_role(GetUserId(), roleid))
1237 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1238 errmsg("permission denied to reassign objects")));
1241 /* Must have privileges on the receiving side too */
1242 newrole = get_role_oid(stmt->newrole, false);
1244 if (!has_privs_of_role(GetUserId(), newrole))
1246 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1247 errmsg("permission denied to reassign objects")));
1250 shdepReassignOwned(role_ids, newrole);
1256 * Given a list of role names (as String nodes), generate a list of role OIDs
1257 * in the same order.
1260 roleNamesToIds(List *memberNames)
1265 foreach(l, memberNames)
1267 char *rolename = strVal(lfirst(l));
1268 Oid roleid = get_role_oid(rolename, false);
1270 result = lappend_oid(result, roleid);
1276 * AddRoleMems -- Add given members to the specified role
1278 * rolename: name of role to add to (used only for error messages)
1279 * roleid: OID of role to add to
1280 * memberNames: list of names of roles to add (used only for error messages)
1281 * memberIds: OIDs of roles to add
1282 * grantorId: who is granting the membership
1283 * admin_opt: granting admin option?
1285 * Note: caller is responsible for calling auth_file_update_needed().
1288 AddRoleMems(const char *rolename, Oid roleid,
1289 List *memberNames, List *memberIds,
1290 Oid grantorId, bool admin_opt)
1292 Relation pg_authmem_rel;
1293 TupleDesc pg_authmem_dsc;
1297 Assert(list_length(memberNames) == list_length(memberIds));
1299 /* Skip permission check if nothing to do */
1304 * Check permissions: must have createrole or admin option on the role to
1305 * be changed. To mess with a superuser role, you gotta be superuser.
1307 if (superuser_arg(roleid))
1311 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1312 errmsg("must be superuser to alter superusers")));
1316 if (!have_createrole_privilege() &&
1317 !is_admin_of_role(grantorId, roleid))
1319 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1320 errmsg("must have admin option on role \"%s\"",
1324 /* XXX not sure about this check */
1325 if (grantorId != GetUserId() && !superuser())
1327 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1328 errmsg("must be superuser to set grantor")));
1330 pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
1331 pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1333 forboth(nameitem, memberNames, iditem, memberIds)
1335 const char *membername = strVal(lfirst(nameitem));
1336 Oid memberid = lfirst_oid(iditem);
1337 HeapTuple authmem_tuple;
1339 Datum new_record[Natts_pg_auth_members];
1340 bool new_record_nulls[Natts_pg_auth_members];
1341 bool new_record_repl[Natts_pg_auth_members];
1344 * Refuse creation of membership loops, including the trivial case
1345 * where a role is made a member of itself. We do this by checking to
1346 * see if the target role is already a member of the proposed member
1347 * role. We have to ignore possible superuserness, however, else we
1348 * could never grant membership in a superuser-privileged role.
1350 if (is_member_of_role_nosuper(roleid, memberid))
1352 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1353 (errmsg("role \"%s\" is a member of role \"%s\"",
1354 rolename, membername))));
1357 * Check if entry for this role/member already exists; if so, give
1358 * warning unless we are adding admin option.
1360 authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
1361 ObjectIdGetDatum(roleid),
1362 ObjectIdGetDatum(memberid));
1363 if (HeapTupleIsValid(authmem_tuple) &&
1365 ((Form_pg_auth_members) GETSTRUCT(authmem_tuple))->admin_option))
1368 (errmsg("role \"%s\" is already a member of role \"%s\"",
1369 membername, rolename)));
1370 ReleaseSysCache(authmem_tuple);
1374 /* Build a tuple to insert or update */
1375 MemSet(new_record, 0, sizeof(new_record));
1376 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1377 MemSet(new_record_repl, false, sizeof(new_record_repl));
1379 new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid);
1380 new_record[Anum_pg_auth_members_member - 1] = ObjectIdGetDatum(memberid);
1381 new_record[Anum_pg_auth_members_grantor - 1] = ObjectIdGetDatum(grantorId);
1382 new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt);
1384 if (HeapTupleIsValid(authmem_tuple))
1386 new_record_repl[Anum_pg_auth_members_grantor - 1] = true;
1387 new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
1388 tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1390 new_record_nulls, new_record_repl);
1391 simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
1392 CatalogUpdateIndexes(pg_authmem_rel, tuple);
1393 ReleaseSysCache(authmem_tuple);
1397 tuple = heap_form_tuple(pg_authmem_dsc,
1398 new_record, new_record_nulls);
1399 simple_heap_insert(pg_authmem_rel, tuple);
1400 CatalogUpdateIndexes(pg_authmem_rel, tuple);
1403 /* CCI after each change, in case there are duplicates in list */
1404 CommandCounterIncrement();
1408 * Close pg_authmem, but keep lock till commit.
1410 heap_close(pg_authmem_rel, NoLock);
1414 * DelRoleMems -- Remove given members from the specified role
1416 * rolename: name of role to del from (used only for error messages)
1417 * roleid: OID of role to del from
1418 * memberNames: list of names of roles to del (used only for error messages)
1419 * memberIds: OIDs of roles to del
1420 * admin_opt: remove admin option only?
1422 * Note: caller is responsible for calling auth_file_update_needed().
1425 DelRoleMems(const char *rolename, Oid roleid,
1426 List *memberNames, List *memberIds,
1429 Relation pg_authmem_rel;
1430 TupleDesc pg_authmem_dsc;
1434 Assert(list_length(memberNames) == list_length(memberIds));
1436 /* Skip permission check if nothing to do */
1441 * Check permissions: must have createrole or admin option on the role to
1442 * be changed. To mess with a superuser role, you gotta be superuser.
1444 if (superuser_arg(roleid))
1448 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1449 errmsg("must be superuser to alter superusers")));
1453 if (!have_createrole_privilege() &&
1454 !is_admin_of_role(GetUserId(), roleid))
1456 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1457 errmsg("must have admin option on role \"%s\"",
1461 pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
1462 pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1464 forboth(nameitem, memberNames, iditem, memberIds)
1466 const char *membername = strVal(lfirst(nameitem));
1467 Oid memberid = lfirst_oid(iditem);
1468 HeapTuple authmem_tuple;
1471 * Find entry for this role/member
1473 authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
1474 ObjectIdGetDatum(roleid),
1475 ObjectIdGetDatum(memberid));
1476 if (!HeapTupleIsValid(authmem_tuple))
1479 (errmsg("role \"%s\" is not a member of role \"%s\"",
1480 membername, rolename)));
1486 /* Remove the entry altogether */
1487 simple_heap_delete(pg_authmem_rel, &authmem_tuple->t_self);
1491 /* Just turn off the admin option */
1493 Datum new_record[Natts_pg_auth_members];
1494 bool new_record_nulls[Natts_pg_auth_members];
1495 bool new_record_repl[Natts_pg_auth_members];
1497 /* Build a tuple to update with */
1498 MemSet(new_record, 0, sizeof(new_record));
1499 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1500 MemSet(new_record_repl, false, sizeof(new_record_repl));
1502 new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false);
1503 new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
1505 tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1507 new_record_nulls, new_record_repl);
1508 simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
1509 CatalogUpdateIndexes(pg_authmem_rel, tuple);
1512 ReleaseSysCache(authmem_tuple);
1514 /* CCI after each change, in case there are duplicates in list */
1515 CommandCounterIncrement();
1519 * Close pg_authmem, but keep lock till commit.
1521 heap_close(pg_authmem_rel, NoLock);