1 /*-------------------------------------------------------------------------
4 * Commands for manipulating roles (formerly called users).
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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/pg_auth_members.h"
21 #include "catalog/pg_authid.h"
22 #include "commands/comment.h"
23 #include "commands/user.h"
24 #include "libpq/md5.h"
25 #include "miscadmin.h"
26 #include "utils/acl.h"
27 #include "utils/builtins.h"
28 #include "utils/flatfiles.h"
29 #include "utils/fmgroids.h"
30 #include "utils/guc.h"
31 #include "utils/lsyscache.h"
32 #include "utils/syscache.h"
33 #include "utils/tqual.h"
36 extern bool Password_encryption
;
38 static List
*roleNamesToIds(List
*memberNames
);
39 static void AddRoleMems(const char *rolename
, Oid roleid
,
40 List
*memberNames
, List
*memberIds
,
41 Oid grantorId
, bool admin_opt
);
42 static void DelRoleMems(const char *rolename
, Oid roleid
,
43 List
*memberNames
, List
*memberIds
,
47 /* Check if current user has createrole privileges */
49 have_createrole_privilege(void)
54 /* Superusers can always do everything */
58 utup
= SearchSysCache(AUTHOID
,
59 ObjectIdGetDatum(GetUserId()),
61 if (HeapTupleIsValid(utup
))
63 result
= ((Form_pg_authid
) GETSTRUCT(utup
))->rolcreaterole
;
64 ReleaseSysCache(utup
);
74 CreateRole(CreateRoleStmt
*stmt
)
76 Relation pg_authid_rel
;
77 TupleDesc pg_authid_dsc
;
79 Datum new_record
[Natts_pg_authid
];
80 char new_record_nulls
[Natts_pg_authid
];
84 char *password
= NULL
; /* user password */
85 bool encrypt_password
= Password_encryption
; /* encrypt password? */
86 char encrypted_password
[MD5_PASSWD_LEN
+ 1];
87 bool issuper
= false; /* Make the user a superuser? */
88 bool inherit
= true; /* Auto inherit privileges? */
89 bool createrole
= false; /* Can this user create roles? */
90 bool createdb
= false; /* Can the user create databases? */
91 bool canlogin
= false; /* Can this user login? */
92 int connlimit
= -1; /* maximum connections allowed */
93 List
*addroleto
= NIL
; /* roles to make this a member of */
94 List
*rolemembers
= NIL
; /* roles to be members of this role */
95 List
*adminmembers
= NIL
; /* roles to be admins of this role */
96 char *validUntil
= NULL
; /* time the login is valid until */
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
*dconnlimit
= NULL
;
104 DefElem
*daddroleto
= NULL
;
105 DefElem
*drolemembers
= NULL
;
106 DefElem
*dadminmembers
= NULL
;
107 DefElem
*dvalidUntil
= NULL
;
109 /* The defaults can vary depending on the original statement type */
110 switch (stmt
->stmt_type
)
116 /* may eventually want inherit to default to false here */
122 /* Extract options from the statement node tree */
123 foreach(option
, stmt
->options
)
125 DefElem
*defel
= (DefElem
*) lfirst(option
);
127 if (strcmp(defel
->defname
, "password") == 0 ||
128 strcmp(defel
->defname
, "encryptedPassword") == 0 ||
129 strcmp(defel
->defname
, "unencryptedPassword") == 0)
133 (errcode(ERRCODE_SYNTAX_ERROR
),
134 errmsg("conflicting or redundant options")));
136 if (strcmp(defel
->defname
, "encryptedPassword") == 0)
137 encrypt_password
= true;
138 else if (strcmp(defel
->defname
, "unencryptedPassword") == 0)
139 encrypt_password
= false;
141 else if (strcmp(defel
->defname
, "sysid") == 0)
144 (errmsg("SYSID can no longer be specified")));
146 else if (strcmp(defel
->defname
, "superuser") == 0)
150 (errcode(ERRCODE_SYNTAX_ERROR
),
151 errmsg("conflicting or redundant options")));
154 else if (strcmp(defel
->defname
, "inherit") == 0)
158 (errcode(ERRCODE_SYNTAX_ERROR
),
159 errmsg("conflicting or redundant options")));
162 else if (strcmp(defel
->defname
, "createrole") == 0)
166 (errcode(ERRCODE_SYNTAX_ERROR
),
167 errmsg("conflicting or redundant options")));
170 else if (strcmp(defel
->defname
, "createdb") == 0)
174 (errcode(ERRCODE_SYNTAX_ERROR
),
175 errmsg("conflicting or redundant options")));
178 else if (strcmp(defel
->defname
, "canlogin") == 0)
182 (errcode(ERRCODE_SYNTAX_ERROR
),
183 errmsg("conflicting or redundant options")));
186 else if (strcmp(defel
->defname
, "connectionlimit") == 0)
190 (errcode(ERRCODE_SYNTAX_ERROR
),
191 errmsg("conflicting or redundant options")));
194 else if (strcmp(defel
->defname
, "addroleto") == 0)
198 (errcode(ERRCODE_SYNTAX_ERROR
),
199 errmsg("conflicting or redundant options")));
202 else if (strcmp(defel
->defname
, "rolemembers") == 0)
206 (errcode(ERRCODE_SYNTAX_ERROR
),
207 errmsg("conflicting or redundant options")));
208 drolemembers
= defel
;
210 else if (strcmp(defel
->defname
, "adminmembers") == 0)
214 (errcode(ERRCODE_SYNTAX_ERROR
),
215 errmsg("conflicting or redundant options")));
216 dadminmembers
= defel
;
218 else if (strcmp(defel
->defname
, "validUntil") == 0)
222 (errcode(ERRCODE_SYNTAX_ERROR
),
223 errmsg("conflicting or redundant options")));
227 elog(ERROR
, "option \"%s\" not recognized",
231 if (dpassword
&& dpassword
->arg
)
232 password
= strVal(dpassword
->arg
);
234 issuper
= intVal(dissuper
->arg
) != 0;
236 inherit
= intVal(dinherit
->arg
) != 0;
238 createrole
= intVal(dcreaterole
->arg
) != 0;
240 createdb
= intVal(dcreatedb
->arg
) != 0;
242 canlogin
= intVal(dcanlogin
->arg
) != 0;
244 connlimit
= intVal(dconnlimit
->arg
);
246 addroleto
= (List
*) daddroleto
->arg
;
248 rolemembers
= (List
*) drolemembers
->arg
;
250 adminmembers
= (List
*) dadminmembers
->arg
;
252 validUntil
= strVal(dvalidUntil
->arg
);
254 /* Check some permissions first */
259 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
260 errmsg("must be superuser to create superusers")));
264 if (!have_createrole_privilege())
266 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
267 errmsg("permission denied to create role")));
270 if (strcmp(stmt
->role
, "public") == 0 ||
271 strcmp(stmt
->role
, "none") == 0)
273 (errcode(ERRCODE_RESERVED_NAME
),
274 errmsg("role name \"%s\" is reserved",
278 * Check the pg_authid relation to be certain the role doesn't already
281 pg_authid_rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
282 pg_authid_dsc
= RelationGetDescr(pg_authid_rel
);
284 tuple
= SearchSysCache(AUTHNAME
,
285 PointerGetDatum(stmt
->role
),
287 if (HeapTupleIsValid(tuple
))
289 (errcode(ERRCODE_DUPLICATE_OBJECT
),
290 errmsg("role \"%s\" already exists",
294 * Build a tuple to insert
296 MemSet(new_record
, 0, sizeof(new_record
));
297 MemSet(new_record_nulls
, ' ', sizeof(new_record_nulls
));
299 new_record
[Anum_pg_authid_rolname
- 1] =
300 DirectFunctionCall1(namein
, CStringGetDatum(stmt
->role
));
302 new_record
[Anum_pg_authid_rolsuper
- 1] = BoolGetDatum(issuper
);
303 new_record
[Anum_pg_authid_rolinherit
- 1] = BoolGetDatum(inherit
);
304 new_record
[Anum_pg_authid_rolcreaterole
- 1] = BoolGetDatum(createrole
);
305 new_record
[Anum_pg_authid_rolcreatedb
- 1] = BoolGetDatum(createdb
);
306 /* superuser gets catupdate right by default */
307 new_record
[Anum_pg_authid_rolcatupdate
- 1] = BoolGetDatum(issuper
);
308 new_record
[Anum_pg_authid_rolcanlogin
- 1] = BoolGetDatum(canlogin
);
309 new_record
[Anum_pg_authid_rolconnlimit
- 1] = Int32GetDatum(connlimit
);
313 if (!encrypt_password
|| isMD5(password
))
314 new_record
[Anum_pg_authid_rolpassword
- 1] =
315 CStringGetTextDatum(password
);
318 if (!pg_md5_encrypt(password
, stmt
->role
, strlen(stmt
->role
),
320 elog(ERROR
, "password encryption failed");
321 new_record
[Anum_pg_authid_rolpassword
- 1] =
322 CStringGetTextDatum(encrypted_password
);
326 new_record_nulls
[Anum_pg_authid_rolpassword
- 1] = 'n';
329 new_record
[Anum_pg_authid_rolvaliduntil
- 1] =
330 DirectFunctionCall3(timestamptz_in
,
331 CStringGetDatum(validUntil
),
332 ObjectIdGetDatum(InvalidOid
),
336 new_record_nulls
[Anum_pg_authid_rolvaliduntil
- 1] = 'n';
338 new_record_nulls
[Anum_pg_authid_rolconfig
- 1] = 'n';
340 tuple
= heap_formtuple(pg_authid_dsc
, new_record
, new_record_nulls
);
343 * Insert new record in the pg_authid table
345 roleid
= simple_heap_insert(pg_authid_rel
, tuple
);
346 CatalogUpdateIndexes(pg_authid_rel
, tuple
);
349 * Advance command counter so we can see new record; else tests in
350 * AddRoleMems may fail.
352 if (addroleto
|| adminmembers
|| rolemembers
)
353 CommandCounterIncrement();
356 * Add the new role to the specified existing roles.
358 foreach(item
, addroleto
)
360 char *oldrolename
= strVal(lfirst(item
));
361 Oid oldroleid
= get_roleid_checked(oldrolename
);
363 AddRoleMems(oldrolename
, oldroleid
,
364 list_make1(makeString(stmt
->role
)),
365 list_make1_oid(roleid
),
370 * Add the specified members to this new role. adminmembers get the admin
371 * option, rolemembers don't.
373 AddRoleMems(stmt
->role
, roleid
,
374 adminmembers
, roleNamesToIds(adminmembers
),
376 AddRoleMems(stmt
->role
, roleid
,
377 rolemembers
, roleNamesToIds(rolemembers
),
381 * Close pg_authid, but keep lock till commit (this is important to
382 * prevent any risk of deadlock failure while updating flat file)
384 heap_close(pg_authid_rel
, NoLock
);
387 * Set flag to update flat auth file at commit.
389 auth_file_update_needed();
396 * Note: the rolemembers option accepted here is intended to support the
397 * backwards-compatible ALTER GROUP syntax. Although it will work to say
398 * "ALTER ROLE role ROLE rolenames", we don't document it.
401 AlterRole(AlterRoleStmt
*stmt
)
403 Datum new_record
[Natts_pg_authid
];
404 char new_record_nulls
[Natts_pg_authid
];
405 char new_record_repl
[Natts_pg_authid
];
406 Relation pg_authid_rel
;
407 TupleDesc pg_authid_dsc
;
411 char *password
= NULL
; /* user password */
412 bool encrypt_password
= Password_encryption
; /* encrypt password? */
413 char encrypted_password
[MD5_PASSWD_LEN
+ 1];
414 int issuper
= -1; /* Make the user a superuser? */
415 int inherit
= -1; /* Auto inherit privileges? */
416 int createrole
= -1; /* Can this user create roles? */
417 int createdb
= -1; /* Can the user create databases? */
418 int canlogin
= -1; /* Can this user login? */
419 int connlimit
= -1; /* maximum connections allowed */
420 List
*rolemembers
= NIL
; /* roles to be added/removed */
421 char *validUntil
= NULL
; /* time the login is valid until */
422 DefElem
*dpassword
= NULL
;
423 DefElem
*dissuper
= NULL
;
424 DefElem
*dinherit
= NULL
;
425 DefElem
*dcreaterole
= NULL
;
426 DefElem
*dcreatedb
= NULL
;
427 DefElem
*dcanlogin
= NULL
;
428 DefElem
*dconnlimit
= NULL
;
429 DefElem
*drolemembers
= NULL
;
430 DefElem
*dvalidUntil
= NULL
;
433 /* Extract options from the statement node tree */
434 foreach(option
, stmt
->options
)
436 DefElem
*defel
= (DefElem
*) lfirst(option
);
438 if (strcmp(defel
->defname
, "password") == 0 ||
439 strcmp(defel
->defname
, "encryptedPassword") == 0 ||
440 strcmp(defel
->defname
, "unencryptedPassword") == 0)
444 (errcode(ERRCODE_SYNTAX_ERROR
),
445 errmsg("conflicting or redundant options")));
447 if (strcmp(defel
->defname
, "encryptedPassword") == 0)
448 encrypt_password
= true;
449 else if (strcmp(defel
->defname
, "unencryptedPassword") == 0)
450 encrypt_password
= false;
452 else if (strcmp(defel
->defname
, "superuser") == 0)
456 (errcode(ERRCODE_SYNTAX_ERROR
),
457 errmsg("conflicting or redundant options")));
460 else if (strcmp(defel
->defname
, "inherit") == 0)
464 (errcode(ERRCODE_SYNTAX_ERROR
),
465 errmsg("conflicting or redundant options")));
468 else if (strcmp(defel
->defname
, "createrole") == 0)
472 (errcode(ERRCODE_SYNTAX_ERROR
),
473 errmsg("conflicting or redundant options")));
476 else if (strcmp(defel
->defname
, "createdb") == 0)
480 (errcode(ERRCODE_SYNTAX_ERROR
),
481 errmsg("conflicting or redundant options")));
484 else if (strcmp(defel
->defname
, "canlogin") == 0)
488 (errcode(ERRCODE_SYNTAX_ERROR
),
489 errmsg("conflicting or redundant options")));
492 else if (strcmp(defel
->defname
, "connectionlimit") == 0)
496 (errcode(ERRCODE_SYNTAX_ERROR
),
497 errmsg("conflicting or redundant options")));
500 else if (strcmp(defel
->defname
, "rolemembers") == 0 &&
505 (errcode(ERRCODE_SYNTAX_ERROR
),
506 errmsg("conflicting or redundant options")));
507 drolemembers
= defel
;
509 else if (strcmp(defel
->defname
, "validUntil") == 0)
513 (errcode(ERRCODE_SYNTAX_ERROR
),
514 errmsg("conflicting or redundant options")));
518 elog(ERROR
, "option \"%s\" not recognized",
522 if (dpassword
&& dpassword
->arg
)
523 password
= strVal(dpassword
->arg
);
525 issuper
= intVal(dissuper
->arg
);
527 inherit
= intVal(dinherit
->arg
);
529 createrole
= intVal(dcreaterole
->arg
);
531 createdb
= intVal(dcreatedb
->arg
);
533 canlogin
= intVal(dcanlogin
->arg
);
535 connlimit
= intVal(dconnlimit
->arg
);
537 rolemembers
= (List
*) drolemembers
->arg
;
539 validUntil
= strVal(dvalidUntil
->arg
);
542 * Scan the pg_authid relation to be certain the user exists.
544 pg_authid_rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
545 pg_authid_dsc
= RelationGetDescr(pg_authid_rel
);
547 tuple
= SearchSysCache(AUTHNAME
,
548 PointerGetDatum(stmt
->role
),
550 if (!HeapTupleIsValid(tuple
))
552 (errcode(ERRCODE_UNDEFINED_OBJECT
),
553 errmsg("role \"%s\" does not exist", stmt
->role
)));
555 roleid
= HeapTupleGetOid(tuple
);
558 * To mess with a superuser you gotta be superuser; else you need
559 * createrole, or just want to change your own password
561 if (((Form_pg_authid
) GETSTRUCT(tuple
))->rolsuper
|| issuper
>= 0)
565 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
566 errmsg("must be superuser to alter superusers")));
568 else if (!have_createrole_privilege())
578 roleid
== GetUserId()))
580 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
581 errmsg("permission denied")));
585 * Build an updated tuple, perusing the information just obtained
587 MemSet(new_record
, 0, sizeof(new_record
));
588 MemSet(new_record_nulls
, ' ', sizeof(new_record_nulls
));
589 MemSet(new_record_repl
, ' ', sizeof(new_record_repl
));
592 * issuper/createrole/catupdate/etc
594 * XXX It's rather unclear how to handle catupdate. It's probably best to
595 * keep it equal to the superuser status, otherwise you could end up with
596 * a situation where no existing superuser can alter the catalogs,
597 * including pg_authid!
601 new_record
[Anum_pg_authid_rolsuper
- 1] = BoolGetDatum(issuper
> 0);
602 new_record_repl
[Anum_pg_authid_rolsuper
- 1] = 'r';
604 new_record
[Anum_pg_authid_rolcatupdate
- 1] = BoolGetDatum(issuper
> 0);
605 new_record_repl
[Anum_pg_authid_rolcatupdate
- 1] = 'r';
610 new_record
[Anum_pg_authid_rolinherit
- 1] = BoolGetDatum(inherit
> 0);
611 new_record_repl
[Anum_pg_authid_rolinherit
- 1] = 'r';
616 new_record
[Anum_pg_authid_rolcreaterole
- 1] = BoolGetDatum(createrole
> 0);
617 new_record_repl
[Anum_pg_authid_rolcreaterole
- 1] = 'r';
622 new_record
[Anum_pg_authid_rolcreatedb
- 1] = BoolGetDatum(createdb
> 0);
623 new_record_repl
[Anum_pg_authid_rolcreatedb
- 1] = 'r';
628 new_record
[Anum_pg_authid_rolcanlogin
- 1] = BoolGetDatum(canlogin
> 0);
629 new_record_repl
[Anum_pg_authid_rolcanlogin
- 1] = 'r';
634 new_record
[Anum_pg_authid_rolconnlimit
- 1] = Int32GetDatum(connlimit
);
635 new_record_repl
[Anum_pg_authid_rolconnlimit
- 1] = 'r';
641 if (!encrypt_password
|| isMD5(password
))
642 new_record
[Anum_pg_authid_rolpassword
- 1] =
643 CStringGetTextDatum(password
);
646 if (!pg_md5_encrypt(password
, stmt
->role
, strlen(stmt
->role
),
648 elog(ERROR
, "password encryption failed");
649 new_record
[Anum_pg_authid_rolpassword
- 1] =
650 CStringGetTextDatum(encrypted_password
);
652 new_record_repl
[Anum_pg_authid_rolpassword
- 1] = 'r';
656 if (dpassword
&& dpassword
->arg
== NULL
)
658 new_record_repl
[Anum_pg_authid_rolpassword
- 1] = 'r';
659 new_record_nulls
[Anum_pg_authid_rolpassword
- 1] = 'n';
665 new_record
[Anum_pg_authid_rolvaliduntil
- 1] =
666 DirectFunctionCall3(timestamptz_in
,
667 CStringGetDatum(validUntil
),
668 ObjectIdGetDatum(InvalidOid
),
670 new_record_repl
[Anum_pg_authid_rolvaliduntil
- 1] = 'r';
673 new_tuple
= heap_modifytuple(tuple
, pg_authid_dsc
, new_record
,
674 new_record_nulls
, new_record_repl
);
675 simple_heap_update(pg_authid_rel
, &tuple
->t_self
, new_tuple
);
678 CatalogUpdateIndexes(pg_authid_rel
, new_tuple
);
680 ReleaseSysCache(tuple
);
681 heap_freetuple(new_tuple
);
684 * Advance command counter so we can see new record; else tests in
685 * AddRoleMems may fail.
688 CommandCounterIncrement();
690 if (stmt
->action
== +1) /* add members to role */
691 AddRoleMems(stmt
->role
, roleid
,
692 rolemembers
, roleNamesToIds(rolemembers
),
694 else if (stmt
->action
== -1) /* drop members from role */
695 DelRoleMems(stmt
->role
, roleid
,
696 rolemembers
, roleNamesToIds(rolemembers
),
700 * Close pg_authid, but keep lock till commit (this is important to
701 * prevent any risk of deadlock failure while updating flat file)
703 heap_close(pg_authid_rel
, NoLock
);
706 * Set flag to update flat auth file at commit.
708 auth_file_update_needed();
716 AlterRoleSet(AlterRoleSetStmt
*stmt
)
722 Datum repl_val
[Natts_pg_authid
];
723 char repl_null
[Natts_pg_authid
];
724 char repl_repl
[Natts_pg_authid
];
726 valuestr
= ExtractSetVariableArgs(stmt
->setstmt
);
728 rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
729 oldtuple
= SearchSysCache(AUTHNAME
,
730 PointerGetDatum(stmt
->role
),
732 if (!HeapTupleIsValid(oldtuple
))
734 (errcode(ERRCODE_UNDEFINED_OBJECT
),
735 errmsg("role \"%s\" does not exist", stmt
->role
)));
738 * To mess with a superuser you gotta be superuser; else you need
739 * createrole, or just want to change your own settings
741 if (((Form_pg_authid
) GETSTRUCT(oldtuple
))->rolsuper
)
745 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
746 errmsg("must be superuser to alter superusers")));
750 if (!have_createrole_privilege() &&
751 HeapTupleGetOid(oldtuple
) != GetUserId())
753 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
754 errmsg("permission denied")));
757 memset(repl_repl
, ' ', sizeof(repl_repl
));
758 repl_repl
[Anum_pg_authid_rolconfig
- 1] = 'r';
760 if (stmt
->setstmt
->kind
== VAR_RESET_ALL
)
762 /* RESET ALL, so just set rolconfig to null */
763 repl_null
[Anum_pg_authid_rolconfig
- 1] = 'n';
764 repl_val
[Anum_pg_authid_rolconfig
- 1] = (Datum
) 0;
772 repl_null
[Anum_pg_authid_rolconfig
- 1] = ' ';
774 /* Extract old value of rolconfig */
775 datum
= SysCacheGetAttr(AUTHNAME
, oldtuple
,
776 Anum_pg_authid_rolconfig
, &isnull
);
777 array
= isnull
? NULL
: DatumGetArrayTypeP(datum
);
779 /* Update (valuestr is NULL in RESET cases) */
781 array
= GUCArrayAdd(array
, stmt
->setstmt
->name
, valuestr
);
783 array
= GUCArrayDelete(array
, stmt
->setstmt
->name
);
786 repl_val
[Anum_pg_authid_rolconfig
- 1] = PointerGetDatum(array
);
788 repl_null
[Anum_pg_authid_rolconfig
- 1] = 'n';
791 newtuple
= heap_modifytuple(oldtuple
, RelationGetDescr(rel
),
792 repl_val
, repl_null
, repl_repl
);
794 simple_heap_update(rel
, &oldtuple
->t_self
, newtuple
);
795 CatalogUpdateIndexes(rel
, newtuple
);
797 ReleaseSysCache(oldtuple
);
798 /* needn't keep lock since we won't be updating the flat file */
799 heap_close(rel
, RowExclusiveLock
);
807 DropRole(DropRoleStmt
*stmt
)
809 Relation pg_authid_rel
,
813 if (!have_createrole_privilege())
815 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
816 errmsg("permission denied to drop role")));
819 * Scan the pg_authid relation to find the Oid of the role(s) to be
822 pg_authid_rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
823 pg_auth_members_rel
= heap_open(AuthMemRelationId
, RowExclusiveLock
);
825 foreach(item
, stmt
->roles
)
827 const char *role
= strVal(lfirst(item
));
836 tuple
= SearchSysCache(AUTHNAME
,
837 PointerGetDatum(role
),
839 if (!HeapTupleIsValid(tuple
))
841 if (!stmt
->missing_ok
)
844 (errcode(ERRCODE_UNDEFINED_OBJECT
),
845 errmsg("role \"%s\" does not exist", role
)));
850 (errmsg("role \"%s\" does not exist, skipping",
857 roleid
= HeapTupleGetOid(tuple
);
859 if (roleid
== GetUserId())
861 (errcode(ERRCODE_OBJECT_IN_USE
),
862 errmsg("current user cannot be dropped")));
863 if (roleid
== GetOuterUserId())
865 (errcode(ERRCODE_OBJECT_IN_USE
),
866 errmsg("current user cannot be dropped")));
867 if (roleid
== GetSessionUserId())
869 (errcode(ERRCODE_OBJECT_IN_USE
),
870 errmsg("session user cannot be dropped")));
873 * For safety's sake, we allow createrole holders to drop ordinary
874 * roles but not superuser roles. This is mainly to avoid the
875 * scenario where you accidentally drop the last superuser.
877 if (((Form_pg_authid
) GETSTRUCT(tuple
))->rolsuper
&&
880 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
881 errmsg("must be superuser to drop superusers")));
884 * Lock the role, so nobody can add dependencies to her while we drop
885 * her. We keep the lock until the end of transaction.
887 LockSharedObject(AuthIdRelationId
, roleid
, 0, AccessExclusiveLock
);
889 /* Check for pg_shdepend entries depending on this role */
890 if (checkSharedDependencies(AuthIdRelationId
, roleid
,
891 &detail
, &detail_log
))
893 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST
),
894 errmsg("role \"%s\" cannot be dropped because some objects depend on it",
896 errdetail("%s", detail
),
897 errdetail_log("%s", detail_log
)));
900 * Remove the role from the pg_authid table
902 simple_heap_delete(pg_authid_rel
, &tuple
->t_self
);
904 ReleaseSysCache(tuple
);
907 * Remove role from the pg_auth_members table. We have to remove all
908 * tuples that show it as either a role or a member.
910 * XXX what about grantor entries? Maybe we should do one heap scan.
912 ScanKeyInit(&scankey
,
913 Anum_pg_auth_members_roleid
,
914 BTEqualStrategyNumber
, F_OIDEQ
,
915 ObjectIdGetDatum(roleid
));
917 sscan
= systable_beginscan(pg_auth_members_rel
, AuthMemRoleMemIndexId
,
918 true, SnapshotNow
, 1, &scankey
);
920 while (HeapTupleIsValid(tmp_tuple
= systable_getnext(sscan
)))
922 simple_heap_delete(pg_auth_members_rel
, &tmp_tuple
->t_self
);
925 systable_endscan(sscan
);
927 ScanKeyInit(&scankey
,
928 Anum_pg_auth_members_member
,
929 BTEqualStrategyNumber
, F_OIDEQ
,
930 ObjectIdGetDatum(roleid
));
932 sscan
= systable_beginscan(pg_auth_members_rel
, AuthMemMemRoleIndexId
,
933 true, SnapshotNow
, 1, &scankey
);
935 while (HeapTupleIsValid(tmp_tuple
= systable_getnext(sscan
)))
937 simple_heap_delete(pg_auth_members_rel
, &tmp_tuple
->t_self
);
940 systable_endscan(sscan
);
943 * Remove any comments on this role.
945 DeleteSharedComments(roleid
, AuthIdRelationId
);
948 * Advance command counter so that later iterations of this loop will
949 * see the changes already made. This is essential if, for example,
950 * we are trying to drop both a role and one of its direct members ---
951 * we'll get an error if we try to delete the linking pg_auth_members
952 * tuple twice. (We do not need a CCI between the two delete loops
953 * above, because it's not allowed for a role to directly contain
956 CommandCounterIncrement();
960 * Now we can clean up; but keep locks until commit (to avoid possible
961 * deadlock failure while updating flat file)
963 heap_close(pg_auth_members_rel
, NoLock
);
964 heap_close(pg_authid_rel
, NoLock
);
967 * Set flag to update flat auth file at commit.
969 auth_file_update_needed();
976 RenameRole(const char *oldname
, const char *newname
)
984 Datum repl_val
[Natts_pg_authid
];
985 char repl_null
[Natts_pg_authid
];
986 char repl_repl
[Natts_pg_authid
];
990 rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
991 dsc
= RelationGetDescr(rel
);
993 oldtuple
= SearchSysCache(AUTHNAME
,
994 CStringGetDatum(oldname
),
996 if (!HeapTupleIsValid(oldtuple
))
998 (errcode(ERRCODE_UNDEFINED_OBJECT
),
999 errmsg("role \"%s\" does not exist", oldname
)));
1002 * XXX Client applications probably store the session user somewhere, so
1003 * renaming it could cause confusion. On the other hand, there may not be
1004 * an actual problem besides a little confusion, so think about this and
1005 * decide. Same for SET ROLE ... we don't restrict renaming the current
1006 * effective userid, though.
1009 roleid
= HeapTupleGetOid(oldtuple
);
1011 if (roleid
== GetSessionUserId())
1013 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
1014 errmsg("session user cannot be renamed")));
1015 if (roleid
== GetOuterUserId())
1017 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
1018 errmsg("current user cannot be renamed")));
1020 /* make sure the new name doesn't exist */
1021 if (SearchSysCacheExists(AUTHNAME
,
1022 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
++)
1057 repl_repl
[Anum_pg_authid_rolname
- 1] = 'r';
1058 repl_val
[Anum_pg_authid_rolname
- 1] = DirectFunctionCall1(namein
,
1059 CStringGetDatum(newname
));
1060 repl_null
[Anum_pg_authid_rolname
- 1] = ' ';
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] = 'r';
1068 repl_null
[Anum_pg_authid_rolpassword
- 1] = 'n';
1071 (errmsg("MD5 password cleared because of role rename")));
1074 newtuple
= heap_modifytuple(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 (this is important to
1083 * prevent any risk of deadlock failure while updating flat file)
1085 heap_close(rel
, NoLock
);
1088 * Set flag to update flat auth file at commit.
1090 auth_file_update_needed();
1096 * Grant/Revoke roles to/from roles
1099 GrantRole(GrantRoleStmt
*stmt
)
1101 Relation pg_authid_rel
;
1107 grantor
= get_roleid_checked(stmt
->grantor
);
1109 grantor
= GetUserId();
1111 grantee_ids
= roleNamesToIds(stmt
->grantee_roles
);
1113 /* AccessShareLock is enough since we aren't modifying pg_authid */
1114 pg_authid_rel
= heap_open(AuthIdRelationId
, AccessShareLock
);
1117 * Step through all of the granted roles and add/remove entries for the
1118 * grantees, or, if admin_opt is set, then just add/remove the admin
1121 * Note: Permissions checking is done by AddRoleMems/DelRoleMems
1123 foreach(item
, stmt
->granted_roles
)
1125 char *rolename
= strVal(lfirst(item
));
1126 Oid roleid
= get_roleid_checked(rolename
);
1129 AddRoleMems(rolename
, roleid
,
1130 stmt
->grantee_roles
, grantee_ids
,
1131 grantor
, stmt
->admin_opt
);
1133 DelRoleMems(rolename
, roleid
,
1134 stmt
->grantee_roles
, grantee_ids
,
1139 * Close pg_authid, but keep lock till commit (this is important to
1140 * prevent any risk of deadlock failure while updating flat file)
1142 heap_close(pg_authid_rel
, NoLock
);
1145 * Set flag to update flat auth file at commit.
1147 auth_file_update_needed();
1153 * Drop the objects owned by a given list of roles.
1156 DropOwnedObjects(DropOwnedStmt
*stmt
)
1158 List
*role_ids
= roleNamesToIds(stmt
->roles
);
1161 /* Check privileges */
1162 foreach(cell
, role_ids
)
1164 Oid roleid
= lfirst_oid(cell
);
1166 if (!has_privs_of_role(GetUserId(), roleid
))
1168 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1169 errmsg("permission denied to drop objects")));
1173 shdepDropOwned(role_ids
, stmt
->behavior
);
1177 * ReassignOwnedObjects
1179 * Give the objects owned by a given list of roles away to another user.
1182 ReassignOwnedObjects(ReassignOwnedStmt
*stmt
)
1184 List
*role_ids
= roleNamesToIds(stmt
->roles
);
1188 /* Check privileges */
1189 foreach(cell
, role_ids
)
1191 Oid roleid
= lfirst_oid(cell
);
1193 if (!has_privs_of_role(GetUserId(), roleid
))
1195 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1196 errmsg("permission denied to reassign objects")));
1199 /* Must have privileges on the receiving side too */
1200 newrole
= get_roleid_checked(stmt
->newrole
);
1202 if (!has_privs_of_role(GetUserId(), newrole
))
1204 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1205 errmsg("permission denied to reassign objects")));
1208 shdepReassignOwned(role_ids
, newrole
);
1214 * Given a list of role names (as String nodes), generate a list of role OIDs
1215 * in the same order.
1218 roleNamesToIds(List
*memberNames
)
1223 foreach(l
, memberNames
)
1225 char *rolename
= strVal(lfirst(l
));
1226 Oid roleid
= get_roleid_checked(rolename
);
1228 result
= lappend_oid(result
, roleid
);
1234 * AddRoleMems -- Add given members to the specified role
1236 * rolename: name of role to add to (used only for error messages)
1237 * roleid: OID of role to add to
1238 * memberNames: list of names of roles to add (used only for error messages)
1239 * memberIds: OIDs of roles to add
1240 * grantorId: who is granting the membership
1241 * admin_opt: granting admin option?
1243 * Note: caller is responsible for calling auth_file_update_needed().
1246 AddRoleMems(const char *rolename
, Oid roleid
,
1247 List
*memberNames
, List
*memberIds
,
1248 Oid grantorId
, bool admin_opt
)
1250 Relation pg_authmem_rel
;
1251 TupleDesc pg_authmem_dsc
;
1255 Assert(list_length(memberNames
) == list_length(memberIds
));
1257 /* Skip permission check if nothing to do */
1262 * Check permissions: must have createrole or admin option on the role to
1263 * be changed. To mess with a superuser role, you gotta be superuser.
1265 if (superuser_arg(roleid
))
1269 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1270 errmsg("must be superuser to alter superusers")));
1274 if (!have_createrole_privilege() &&
1275 !is_admin_of_role(grantorId
, roleid
))
1277 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1278 errmsg("must have admin option on role \"%s\"",
1282 /* XXX not sure about this check */
1283 if (grantorId
!= GetUserId() && !superuser())
1285 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1286 errmsg("must be superuser to set grantor")));
1288 pg_authmem_rel
= heap_open(AuthMemRelationId
, RowExclusiveLock
);
1289 pg_authmem_dsc
= RelationGetDescr(pg_authmem_rel
);
1291 forboth(nameitem
, memberNames
, iditem
, memberIds
)
1293 const char *membername
= strVal(lfirst(nameitem
));
1294 Oid memberid
= lfirst_oid(iditem
);
1295 HeapTuple authmem_tuple
;
1297 Datum new_record
[Natts_pg_auth_members
];
1298 char new_record_nulls
[Natts_pg_auth_members
];
1299 char new_record_repl
[Natts_pg_auth_members
];
1302 * Refuse creation of membership loops, including the trivial case
1303 * where a role is made a member of itself. We do this by checking to
1304 * see if the target role is already a member of the proposed member
1305 * role. We have to ignore possible superuserness, however, else we
1306 * could never grant membership in a superuser-privileged role.
1308 if (is_member_of_role_nosuper(roleid
, memberid
))
1310 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1311 (errmsg("role \"%s\" is a member of role \"%s\"",
1312 rolename
, membername
))));
1315 * Check if entry for this role/member already exists; if so, give
1316 * warning unless we are adding admin option.
1318 authmem_tuple
= SearchSysCache(AUTHMEMROLEMEM
,
1319 ObjectIdGetDatum(roleid
),
1320 ObjectIdGetDatum(memberid
),
1322 if (HeapTupleIsValid(authmem_tuple
) &&
1324 ((Form_pg_auth_members
) GETSTRUCT(authmem_tuple
))->admin_option
))
1327 (errmsg("role \"%s\" is already a member of role \"%s\"",
1328 membername
, rolename
)));
1329 ReleaseSysCache(authmem_tuple
);
1333 /* Build a tuple to insert or update */
1334 MemSet(new_record
, 0, sizeof(new_record
));
1335 MemSet(new_record_nulls
, ' ', sizeof(new_record_nulls
));
1336 MemSet(new_record_repl
, ' ', sizeof(new_record_repl
));
1338 new_record
[Anum_pg_auth_members_roleid
- 1] = ObjectIdGetDatum(roleid
);
1339 new_record
[Anum_pg_auth_members_member
- 1] = ObjectIdGetDatum(memberid
);
1340 new_record
[Anum_pg_auth_members_grantor
- 1] = ObjectIdGetDatum(grantorId
);
1341 new_record
[Anum_pg_auth_members_admin_option
- 1] = BoolGetDatum(admin_opt
);
1343 if (HeapTupleIsValid(authmem_tuple
))
1345 new_record_repl
[Anum_pg_auth_members_grantor
- 1] = 'r';
1346 new_record_repl
[Anum_pg_auth_members_admin_option
- 1] = 'r';
1347 tuple
= heap_modifytuple(authmem_tuple
, pg_authmem_dsc
,
1349 new_record_nulls
, new_record_repl
);
1350 simple_heap_update(pg_authmem_rel
, &tuple
->t_self
, tuple
);
1351 CatalogUpdateIndexes(pg_authmem_rel
, tuple
);
1352 ReleaseSysCache(authmem_tuple
);
1356 tuple
= heap_formtuple(pg_authmem_dsc
,
1357 new_record
, new_record_nulls
);
1358 simple_heap_insert(pg_authmem_rel
, tuple
);
1359 CatalogUpdateIndexes(pg_authmem_rel
, tuple
);
1362 /* CCI after each change, in case there are duplicates in list */
1363 CommandCounterIncrement();
1367 * Close pg_authmem, but keep lock till commit (this is important to
1368 * prevent any risk of deadlock failure while updating flat file)
1370 heap_close(pg_authmem_rel
, NoLock
);
1374 * DelRoleMems -- Remove given members from the specified role
1376 * rolename: name of role to del from (used only for error messages)
1377 * roleid: OID of role to del from
1378 * memberNames: list of names of roles to del (used only for error messages)
1379 * memberIds: OIDs of roles to del
1380 * admin_opt: remove admin option only?
1382 * Note: caller is responsible for calling auth_file_update_needed().
1385 DelRoleMems(const char *rolename
, Oid roleid
,
1386 List
*memberNames
, List
*memberIds
,
1389 Relation pg_authmem_rel
;
1390 TupleDesc pg_authmem_dsc
;
1394 Assert(list_length(memberNames
) == list_length(memberIds
));
1396 /* Skip permission check if nothing to do */
1401 * Check permissions: must have createrole or admin option on the role to
1402 * be changed. To mess with a superuser role, you gotta be superuser.
1404 if (superuser_arg(roleid
))
1408 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1409 errmsg("must be superuser to alter superusers")));
1413 if (!have_createrole_privilege() &&
1414 !is_admin_of_role(GetUserId(), roleid
))
1416 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1417 errmsg("must have admin option on role \"%s\"",
1421 pg_authmem_rel
= heap_open(AuthMemRelationId
, RowExclusiveLock
);
1422 pg_authmem_dsc
= RelationGetDescr(pg_authmem_rel
);
1424 forboth(nameitem
, memberNames
, iditem
, memberIds
)
1426 const char *membername
= strVal(lfirst(nameitem
));
1427 Oid memberid
= lfirst_oid(iditem
);
1428 HeapTuple authmem_tuple
;
1431 * Find entry for this role/member
1433 authmem_tuple
= SearchSysCache(AUTHMEMROLEMEM
,
1434 ObjectIdGetDatum(roleid
),
1435 ObjectIdGetDatum(memberid
),
1437 if (!HeapTupleIsValid(authmem_tuple
))
1440 (errmsg("role \"%s\" is not a member of role \"%s\"",
1441 membername
, rolename
)));
1447 /* Remove the entry altogether */
1448 simple_heap_delete(pg_authmem_rel
, &authmem_tuple
->t_self
);
1452 /* Just turn off the admin option */
1454 Datum new_record
[Natts_pg_auth_members
];
1455 char new_record_nulls
[Natts_pg_auth_members
];
1456 char new_record_repl
[Natts_pg_auth_members
];
1458 /* Build a tuple to update with */
1459 MemSet(new_record
, 0, sizeof(new_record
));
1460 MemSet(new_record_nulls
, ' ', sizeof(new_record_nulls
));
1461 MemSet(new_record_repl
, ' ', sizeof(new_record_repl
));
1463 new_record
[Anum_pg_auth_members_admin_option
- 1] = BoolGetDatum(false);
1464 new_record_repl
[Anum_pg_auth_members_admin_option
- 1] = 'r';
1466 tuple
= heap_modifytuple(authmem_tuple
, pg_authmem_dsc
,
1468 new_record_nulls
, new_record_repl
);
1469 simple_heap_update(pg_authmem_rel
, &tuple
->t_self
, tuple
);
1470 CatalogUpdateIndexes(pg_authmem_rel
, tuple
);
1473 ReleaseSysCache(authmem_tuple
);
1475 /* CCI after each change, in case there are duplicates in list */
1476 CommandCounterIncrement();
1480 * Close pg_authmem, but keep lock till commit (this is important to
1481 * prevent any risk of deadlock failure while updating flat file)
1483 heap_close(pg_authmem_rel
, NoLock
);