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 "storage/lmgr.h"
27 #include "utils/acl.h"
28 #include "utils/builtins.h"
29 #include "utils/flatfiles.h"
30 #include "utils/fmgroids.h"
31 #include "utils/guc.h"
32 #include "utils/lsyscache.h"
33 #include "utils/syscache.h"
34 #include "utils/tqual.h"
37 extern bool Password_encryption
;
39 static List
*roleNamesToIds(List
*memberNames
);
40 static void AddRoleMems(const char *rolename
, Oid roleid
,
41 List
*memberNames
, List
*memberIds
,
42 Oid grantorId
, bool admin_opt
);
43 static void DelRoleMems(const char *rolename
, Oid roleid
,
44 List
*memberNames
, List
*memberIds
,
48 /* Check if current user has createrole privileges */
50 have_createrole_privilege(void)
55 /* Superusers can always do everything */
59 utup
= SearchSysCache(AUTHOID
,
60 ObjectIdGetDatum(GetUserId()),
62 if (HeapTupleIsValid(utup
))
64 result
= ((Form_pg_authid
) GETSTRUCT(utup
))->rolcreaterole
;
65 ReleaseSysCache(utup
);
75 CreateRole(CreateRoleStmt
*stmt
)
77 Relation pg_authid_rel
;
78 TupleDesc pg_authid_dsc
;
80 Datum new_record
[Natts_pg_authid
];
81 bool new_record_nulls
[Natts_pg_authid
];
85 char *password
= NULL
; /* user password */
86 bool encrypt_password
= Password_encryption
; /* encrypt password? */
87 char encrypted_password
[MD5_PASSWD_LEN
+ 1];
88 bool issuper
= false; /* Make the user a superuser? */
89 bool inherit
= true; /* Auto inherit privileges? */
90 bool createrole
= false; /* Can this user create roles? */
91 bool createdb
= false; /* Can the user create databases? */
92 bool canlogin
= false; /* Can this user login? */
93 int connlimit
= -1; /* maximum connections allowed */
94 List
*addroleto
= NIL
; /* roles to make this a member of */
95 List
*rolemembers
= NIL
; /* roles to be members of this role */
96 List
*adminmembers
= NIL
; /* roles to be admins of this role */
97 char *validUntil
= NULL
; /* time the login is valid until */
98 DefElem
*dpassword
= NULL
;
99 DefElem
*dissuper
= NULL
;
100 DefElem
*dinherit
= NULL
;
101 DefElem
*dcreaterole
= NULL
;
102 DefElem
*dcreatedb
= NULL
;
103 DefElem
*dcanlogin
= NULL
;
104 DefElem
*dconnlimit
= NULL
;
105 DefElem
*daddroleto
= NULL
;
106 DefElem
*drolemembers
= NULL
;
107 DefElem
*dadminmembers
= NULL
;
108 DefElem
*dvalidUntil
= NULL
;
110 /* The defaults can vary depending on the original statement type */
111 switch (stmt
->stmt_type
)
117 /* may eventually want inherit to default to false here */
123 /* Extract options from the statement node tree */
124 foreach(option
, stmt
->options
)
126 DefElem
*defel
= (DefElem
*) lfirst(option
);
128 if (strcmp(defel
->defname
, "password") == 0 ||
129 strcmp(defel
->defname
, "encryptedPassword") == 0 ||
130 strcmp(defel
->defname
, "unencryptedPassword") == 0)
134 (errcode(ERRCODE_SYNTAX_ERROR
),
135 errmsg("conflicting or redundant options")));
137 if (strcmp(defel
->defname
, "encryptedPassword") == 0)
138 encrypt_password
= true;
139 else if (strcmp(defel
->defname
, "unencryptedPassword") == 0)
140 encrypt_password
= false;
142 else if (strcmp(defel
->defname
, "sysid") == 0)
145 (errmsg("SYSID can no longer be specified")));
147 else if (strcmp(defel
->defname
, "superuser") == 0)
151 (errcode(ERRCODE_SYNTAX_ERROR
),
152 errmsg("conflicting or redundant options")));
155 else if (strcmp(defel
->defname
, "inherit") == 0)
159 (errcode(ERRCODE_SYNTAX_ERROR
),
160 errmsg("conflicting or redundant options")));
163 else if (strcmp(defel
->defname
, "createrole") == 0)
167 (errcode(ERRCODE_SYNTAX_ERROR
),
168 errmsg("conflicting or redundant options")));
171 else if (strcmp(defel
->defname
, "createdb") == 0)
175 (errcode(ERRCODE_SYNTAX_ERROR
),
176 errmsg("conflicting or redundant options")));
179 else if (strcmp(defel
->defname
, "canlogin") == 0)
183 (errcode(ERRCODE_SYNTAX_ERROR
),
184 errmsg("conflicting or redundant options")));
187 else if (strcmp(defel
->defname
, "connectionlimit") == 0)
191 (errcode(ERRCODE_SYNTAX_ERROR
),
192 errmsg("conflicting or redundant options")));
195 else if (strcmp(defel
->defname
, "addroleto") == 0)
199 (errcode(ERRCODE_SYNTAX_ERROR
),
200 errmsg("conflicting or redundant options")));
203 else if (strcmp(defel
->defname
, "rolemembers") == 0)
207 (errcode(ERRCODE_SYNTAX_ERROR
),
208 errmsg("conflicting or redundant options")));
209 drolemembers
= defel
;
211 else if (strcmp(defel
->defname
, "adminmembers") == 0)
215 (errcode(ERRCODE_SYNTAX_ERROR
),
216 errmsg("conflicting or redundant options")));
217 dadminmembers
= defel
;
219 else if (strcmp(defel
->defname
, "validUntil") == 0)
223 (errcode(ERRCODE_SYNTAX_ERROR
),
224 errmsg("conflicting or redundant options")));
228 elog(ERROR
, "option \"%s\" not recognized",
232 if (dpassword
&& dpassword
->arg
)
233 password
= strVal(dpassword
->arg
);
235 issuper
= intVal(dissuper
->arg
) != 0;
237 inherit
= intVal(dinherit
->arg
) != 0;
239 createrole
= intVal(dcreaterole
->arg
) != 0;
241 createdb
= intVal(dcreatedb
->arg
) != 0;
243 canlogin
= intVal(dcanlogin
->arg
) != 0;
245 connlimit
= intVal(dconnlimit
->arg
);
247 addroleto
= (List
*) daddroleto
->arg
;
249 rolemembers
= (List
*) drolemembers
->arg
;
251 adminmembers
= (List
*) dadminmembers
->arg
;
253 validUntil
= strVal(dvalidUntil
->arg
);
255 /* Check some permissions first */
260 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
261 errmsg("must be superuser to create superusers")));
265 if (!have_createrole_privilege())
267 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
268 errmsg("permission denied to create role")));
271 if (strcmp(stmt
->role
, "public") == 0 ||
272 strcmp(stmt
->role
, "none") == 0)
274 (errcode(ERRCODE_RESERVED_NAME
),
275 errmsg("role name \"%s\" is reserved",
279 * Check the pg_authid relation to be certain the role doesn't already
282 pg_authid_rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
283 pg_authid_dsc
= RelationGetDescr(pg_authid_rel
);
285 tuple
= SearchSysCache(AUTHNAME
,
286 PointerGetDatum(stmt
->role
),
288 if (HeapTupleIsValid(tuple
))
290 (errcode(ERRCODE_DUPLICATE_OBJECT
),
291 errmsg("role \"%s\" already exists",
295 * Build a tuple to insert
297 MemSet(new_record
, 0, sizeof(new_record
));
298 MemSet(new_record_nulls
, false, sizeof(new_record_nulls
));
300 new_record
[Anum_pg_authid_rolname
- 1] =
301 DirectFunctionCall1(namein
, CStringGetDatum(stmt
->role
));
303 new_record
[Anum_pg_authid_rolsuper
- 1] = BoolGetDatum(issuper
);
304 new_record
[Anum_pg_authid_rolinherit
- 1] = BoolGetDatum(inherit
);
305 new_record
[Anum_pg_authid_rolcreaterole
- 1] = BoolGetDatum(createrole
);
306 new_record
[Anum_pg_authid_rolcreatedb
- 1] = BoolGetDatum(createdb
);
307 /* superuser gets catupdate right by default */
308 new_record
[Anum_pg_authid_rolcatupdate
- 1] = BoolGetDatum(issuper
);
309 new_record
[Anum_pg_authid_rolcanlogin
- 1] = BoolGetDatum(canlogin
);
310 new_record
[Anum_pg_authid_rolconnlimit
- 1] = Int32GetDatum(connlimit
);
314 if (!encrypt_password
|| isMD5(password
))
315 new_record
[Anum_pg_authid_rolpassword
- 1] =
316 CStringGetTextDatum(password
);
319 if (!pg_md5_encrypt(password
, stmt
->role
, strlen(stmt
->role
),
321 elog(ERROR
, "password encryption failed");
322 new_record
[Anum_pg_authid_rolpassword
- 1] =
323 CStringGetTextDatum(encrypted_password
);
327 new_record_nulls
[Anum_pg_authid_rolpassword
- 1] = true;
330 new_record
[Anum_pg_authid_rolvaliduntil
- 1] =
331 DirectFunctionCall3(timestamptz_in
,
332 CStringGetDatum(validUntil
),
333 ObjectIdGetDatum(InvalidOid
),
337 new_record_nulls
[Anum_pg_authid_rolvaliduntil
- 1] = true;
339 new_record_nulls
[Anum_pg_authid_rolconfig
- 1] = true;
341 tuple
= heap_form_tuple(pg_authid_dsc
, new_record
, new_record_nulls
);
344 * Insert new record in the pg_authid table
346 roleid
= simple_heap_insert(pg_authid_rel
, tuple
);
347 CatalogUpdateIndexes(pg_authid_rel
, tuple
);
350 * Advance command counter so we can see new record; else tests in
351 * AddRoleMems may fail.
353 if (addroleto
|| adminmembers
|| rolemembers
)
354 CommandCounterIncrement();
357 * Add the new role to the specified existing roles.
359 foreach(item
, addroleto
)
361 char *oldrolename
= strVal(lfirst(item
));
362 Oid oldroleid
= get_roleid_checked(oldrolename
);
364 AddRoleMems(oldrolename
, oldroleid
,
365 list_make1(makeString(stmt
->role
)),
366 list_make1_oid(roleid
),
371 * Add the specified members to this new role. adminmembers get the admin
372 * option, rolemembers don't.
374 AddRoleMems(stmt
->role
, roleid
,
375 adminmembers
, roleNamesToIds(adminmembers
),
377 AddRoleMems(stmt
->role
, roleid
,
378 rolemembers
, roleNamesToIds(rolemembers
),
382 * Close pg_authid, but keep lock till commit (this is important to
383 * prevent any risk of deadlock failure while updating flat file)
385 heap_close(pg_authid_rel
, NoLock
);
388 * Set flag to update flat auth file at commit.
390 auth_file_update_needed();
397 * Note: the rolemembers option accepted here is intended to support the
398 * backwards-compatible ALTER GROUP syntax. Although it will work to say
399 * "ALTER ROLE role ROLE rolenames", we don't document it.
402 AlterRole(AlterRoleStmt
*stmt
)
404 Datum new_record
[Natts_pg_authid
];
405 bool new_record_nulls
[Natts_pg_authid
];
406 bool new_record_repl
[Natts_pg_authid
];
407 Relation pg_authid_rel
;
408 TupleDesc pg_authid_dsc
;
412 char *password
= NULL
; /* user password */
413 bool encrypt_password
= Password_encryption
; /* encrypt password? */
414 char encrypted_password
[MD5_PASSWD_LEN
+ 1];
415 int issuper
= -1; /* Make the user a superuser? */
416 int inherit
= -1; /* Auto inherit privileges? */
417 int createrole
= -1; /* Can this user create roles? */
418 int createdb
= -1; /* Can the user create databases? */
419 int canlogin
= -1; /* Can this user login? */
420 int connlimit
= -1; /* maximum connections allowed */
421 List
*rolemembers
= NIL
; /* roles to be added/removed */
422 char *validUntil
= NULL
; /* time the login is valid until */
423 DefElem
*dpassword
= NULL
;
424 DefElem
*dissuper
= NULL
;
425 DefElem
*dinherit
= NULL
;
426 DefElem
*dcreaterole
= NULL
;
427 DefElem
*dcreatedb
= NULL
;
428 DefElem
*dcanlogin
= NULL
;
429 DefElem
*dconnlimit
= NULL
;
430 DefElem
*drolemembers
= NULL
;
431 DefElem
*dvalidUntil
= NULL
;
434 /* Extract options from the statement node tree */
435 foreach(option
, stmt
->options
)
437 DefElem
*defel
= (DefElem
*) lfirst(option
);
439 if (strcmp(defel
->defname
, "password") == 0 ||
440 strcmp(defel
->defname
, "encryptedPassword") == 0 ||
441 strcmp(defel
->defname
, "unencryptedPassword") == 0)
445 (errcode(ERRCODE_SYNTAX_ERROR
),
446 errmsg("conflicting or redundant options")));
448 if (strcmp(defel
->defname
, "encryptedPassword") == 0)
449 encrypt_password
= true;
450 else if (strcmp(defel
->defname
, "unencryptedPassword") == 0)
451 encrypt_password
= false;
453 else if (strcmp(defel
->defname
, "superuser") == 0)
457 (errcode(ERRCODE_SYNTAX_ERROR
),
458 errmsg("conflicting or redundant options")));
461 else if (strcmp(defel
->defname
, "inherit") == 0)
465 (errcode(ERRCODE_SYNTAX_ERROR
),
466 errmsg("conflicting or redundant options")));
469 else if (strcmp(defel
->defname
, "createrole") == 0)
473 (errcode(ERRCODE_SYNTAX_ERROR
),
474 errmsg("conflicting or redundant options")));
477 else if (strcmp(defel
->defname
, "createdb") == 0)
481 (errcode(ERRCODE_SYNTAX_ERROR
),
482 errmsg("conflicting or redundant options")));
485 else if (strcmp(defel
->defname
, "canlogin") == 0)
489 (errcode(ERRCODE_SYNTAX_ERROR
),
490 errmsg("conflicting or redundant options")));
493 else if (strcmp(defel
->defname
, "connectionlimit") == 0)
497 (errcode(ERRCODE_SYNTAX_ERROR
),
498 errmsg("conflicting or redundant options")));
501 else if (strcmp(defel
->defname
, "rolemembers") == 0 &&
506 (errcode(ERRCODE_SYNTAX_ERROR
),
507 errmsg("conflicting or redundant options")));
508 drolemembers
= defel
;
510 else if (strcmp(defel
->defname
, "validUntil") == 0)
514 (errcode(ERRCODE_SYNTAX_ERROR
),
515 errmsg("conflicting or redundant options")));
519 elog(ERROR
, "option \"%s\" not recognized",
523 if (dpassword
&& dpassword
->arg
)
524 password
= strVal(dpassword
->arg
);
526 issuper
= intVal(dissuper
->arg
);
528 inherit
= intVal(dinherit
->arg
);
530 createrole
= intVal(dcreaterole
->arg
);
532 createdb
= intVal(dcreatedb
->arg
);
534 canlogin
= intVal(dcanlogin
->arg
);
536 connlimit
= intVal(dconnlimit
->arg
);
538 rolemembers
= (List
*) drolemembers
->arg
;
540 validUntil
= strVal(dvalidUntil
->arg
);
543 * Scan the pg_authid relation to be certain the user exists.
545 pg_authid_rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
546 pg_authid_dsc
= RelationGetDescr(pg_authid_rel
);
548 tuple
= SearchSysCache(AUTHNAME
,
549 PointerGetDatum(stmt
->role
),
551 if (!HeapTupleIsValid(tuple
))
553 (errcode(ERRCODE_UNDEFINED_OBJECT
),
554 errmsg("role \"%s\" does not exist", stmt
->role
)));
556 roleid
= HeapTupleGetOid(tuple
);
559 * To mess with a superuser you gotta be superuser; else you need
560 * createrole, or just want to change your own password
562 if (((Form_pg_authid
) GETSTRUCT(tuple
))->rolsuper
|| issuper
>= 0)
566 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
567 errmsg("must be superuser to alter superusers")));
569 else if (!have_createrole_privilege())
579 roleid
== GetUserId()))
581 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
582 errmsg("permission denied")));
586 * Build an updated tuple, perusing the information just obtained
588 MemSet(new_record
, 0, sizeof(new_record
));
589 MemSet(new_record_nulls
, false, sizeof(new_record_nulls
));
590 MemSet(new_record_repl
, false, sizeof(new_record_repl
));
593 * issuper/createrole/catupdate/etc
595 * XXX It's rather unclear how to handle catupdate. It's probably best to
596 * keep it equal to the superuser status, otherwise you could end up with
597 * a situation where no existing superuser can alter the catalogs,
598 * including pg_authid!
602 new_record
[Anum_pg_authid_rolsuper
- 1] = BoolGetDatum(issuper
> 0);
603 new_record_repl
[Anum_pg_authid_rolsuper
- 1] = true;
605 new_record
[Anum_pg_authid_rolcatupdate
- 1] = BoolGetDatum(issuper
> 0);
606 new_record_repl
[Anum_pg_authid_rolcatupdate
- 1] = true;
611 new_record
[Anum_pg_authid_rolinherit
- 1] = BoolGetDatum(inherit
> 0);
612 new_record_repl
[Anum_pg_authid_rolinherit
- 1] = true;
617 new_record
[Anum_pg_authid_rolcreaterole
- 1] = BoolGetDatum(createrole
> 0);
618 new_record_repl
[Anum_pg_authid_rolcreaterole
- 1] = true;
623 new_record
[Anum_pg_authid_rolcreatedb
- 1] = BoolGetDatum(createdb
> 0);
624 new_record_repl
[Anum_pg_authid_rolcreatedb
- 1] = true;
629 new_record
[Anum_pg_authid_rolcanlogin
- 1] = BoolGetDatum(canlogin
> 0);
630 new_record_repl
[Anum_pg_authid_rolcanlogin
- 1] = true;
635 new_record
[Anum_pg_authid_rolconnlimit
- 1] = Int32GetDatum(connlimit
);
636 new_record_repl
[Anum_pg_authid_rolconnlimit
- 1] = true;
642 if (!encrypt_password
|| isMD5(password
))
643 new_record
[Anum_pg_authid_rolpassword
- 1] =
644 CStringGetTextDatum(password
);
647 if (!pg_md5_encrypt(password
, stmt
->role
, strlen(stmt
->role
),
649 elog(ERROR
, "password encryption failed");
650 new_record
[Anum_pg_authid_rolpassword
- 1] =
651 CStringGetTextDatum(encrypted_password
);
653 new_record_repl
[Anum_pg_authid_rolpassword
- 1] = true;
657 if (dpassword
&& dpassword
->arg
== NULL
)
659 new_record_repl
[Anum_pg_authid_rolpassword
- 1] = true;
660 new_record_nulls
[Anum_pg_authid_rolpassword
- 1] = true;
666 new_record
[Anum_pg_authid_rolvaliduntil
- 1] =
667 DirectFunctionCall3(timestamptz_in
,
668 CStringGetDatum(validUntil
),
669 ObjectIdGetDatum(InvalidOid
),
671 new_record_repl
[Anum_pg_authid_rolvaliduntil
- 1] = true;
674 new_tuple
= heap_modify_tuple(tuple
, pg_authid_dsc
, new_record
,
675 new_record_nulls
, new_record_repl
);
676 simple_heap_update(pg_authid_rel
, &tuple
->t_self
, new_tuple
);
679 CatalogUpdateIndexes(pg_authid_rel
, new_tuple
);
681 ReleaseSysCache(tuple
);
682 heap_freetuple(new_tuple
);
685 * Advance command counter so we can see new record; else tests in
686 * AddRoleMems may fail.
689 CommandCounterIncrement();
691 if (stmt
->action
== +1) /* add members to role */
692 AddRoleMems(stmt
->role
, roleid
,
693 rolemembers
, roleNamesToIds(rolemembers
),
695 else if (stmt
->action
== -1) /* drop members from role */
696 DelRoleMems(stmt
->role
, roleid
,
697 rolemembers
, roleNamesToIds(rolemembers
),
701 * Close pg_authid, but keep lock till commit (this is important to
702 * prevent any risk of deadlock failure while updating flat file)
704 heap_close(pg_authid_rel
, NoLock
);
707 * Set flag to update flat auth file at commit.
709 auth_file_update_needed();
717 AlterRoleSet(AlterRoleSetStmt
*stmt
)
723 Datum repl_val
[Natts_pg_authid
];
724 bool repl_null
[Natts_pg_authid
];
725 bool repl_repl
[Natts_pg_authid
];
727 valuestr
= ExtractSetVariableArgs(stmt
->setstmt
);
729 rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
730 oldtuple
= SearchSysCache(AUTHNAME
,
731 PointerGetDatum(stmt
->role
),
733 if (!HeapTupleIsValid(oldtuple
))
735 (errcode(ERRCODE_UNDEFINED_OBJECT
),
736 errmsg("role \"%s\" does not exist", stmt
->role
)));
739 * To mess with a superuser you gotta be superuser; else you need
740 * createrole, or just want to change your own settings
742 if (((Form_pg_authid
) GETSTRUCT(oldtuple
))->rolsuper
)
746 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
747 errmsg("must be superuser to alter superusers")));
751 if (!have_createrole_privilege() &&
752 HeapTupleGetOid(oldtuple
) != GetUserId())
754 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
755 errmsg("permission denied")));
758 memset(repl_repl
, false, sizeof(repl_repl
));
759 repl_repl
[Anum_pg_authid_rolconfig
- 1] = true;
761 if (stmt
->setstmt
->kind
== VAR_RESET_ALL
)
763 /* RESET ALL, so just set rolconfig to null */
764 repl_null
[Anum_pg_authid_rolconfig
- 1] = true;
765 repl_val
[Anum_pg_authid_rolconfig
- 1] = (Datum
) 0;
773 repl_null
[Anum_pg_authid_rolconfig
- 1] = false;
775 /* Extract old value of rolconfig */
776 datum
= SysCacheGetAttr(AUTHNAME
, oldtuple
,
777 Anum_pg_authid_rolconfig
, &isnull
);
778 array
= isnull
? NULL
: DatumGetArrayTypeP(datum
);
780 /* Update (valuestr is NULL in RESET cases) */
782 array
= GUCArrayAdd(array
, stmt
->setstmt
->name
, valuestr
);
784 array
= GUCArrayDelete(array
, stmt
->setstmt
->name
);
787 repl_val
[Anum_pg_authid_rolconfig
- 1] = PointerGetDatum(array
);
789 repl_null
[Anum_pg_authid_rolconfig
- 1] = true;
792 newtuple
= heap_modify_tuple(oldtuple
, RelationGetDescr(rel
),
793 repl_val
, repl_null
, repl_repl
);
795 simple_heap_update(rel
, &oldtuple
->t_self
, newtuple
);
796 CatalogUpdateIndexes(rel
, newtuple
);
798 ReleaseSysCache(oldtuple
);
799 /* needn't keep lock since we won't be updating the flat file */
800 heap_close(rel
, RowExclusiveLock
);
808 DropRole(DropRoleStmt
*stmt
)
810 Relation pg_authid_rel
,
814 if (!have_createrole_privilege())
816 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
817 errmsg("permission denied to drop role")));
820 * Scan the pg_authid relation to find the Oid of the role(s) to be
823 pg_authid_rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
824 pg_auth_members_rel
= heap_open(AuthMemRelationId
, RowExclusiveLock
);
826 foreach(item
, stmt
->roles
)
828 const char *role
= strVal(lfirst(item
));
837 tuple
= SearchSysCache(AUTHNAME
,
838 PointerGetDatum(role
),
840 if (!HeapTupleIsValid(tuple
))
842 if (!stmt
->missing_ok
)
845 (errcode(ERRCODE_UNDEFINED_OBJECT
),
846 errmsg("role \"%s\" does not exist", role
)));
851 (errmsg("role \"%s\" does not exist, skipping",
858 roleid
= HeapTupleGetOid(tuple
);
860 if (roleid
== GetUserId())
862 (errcode(ERRCODE_OBJECT_IN_USE
),
863 errmsg("current user cannot be dropped")));
864 if (roleid
== GetOuterUserId())
866 (errcode(ERRCODE_OBJECT_IN_USE
),
867 errmsg("current user cannot be dropped")));
868 if (roleid
== GetSessionUserId())
870 (errcode(ERRCODE_OBJECT_IN_USE
),
871 errmsg("session user cannot be dropped")));
874 * For safety's sake, we allow createrole holders to drop ordinary
875 * roles but not superuser roles. This is mainly to avoid the
876 * scenario where you accidentally drop the last superuser.
878 if (((Form_pg_authid
) GETSTRUCT(tuple
))->rolsuper
&&
881 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
882 errmsg("must be superuser to drop superusers")));
885 * Lock the role, so nobody can add dependencies to her while we drop
886 * her. We keep the lock until the end of transaction.
888 LockSharedObject(AuthIdRelationId
, roleid
, 0, AccessExclusiveLock
);
890 /* Check for pg_shdepend entries depending on this role */
891 if (checkSharedDependencies(AuthIdRelationId
, roleid
,
892 &detail
, &detail_log
))
894 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST
),
895 errmsg("role \"%s\" cannot be dropped because some objects depend on it",
897 errdetail("%s", detail
),
898 errdetail_log("%s", detail_log
)));
901 * Remove the role from the pg_authid table
903 simple_heap_delete(pg_authid_rel
, &tuple
->t_self
);
905 ReleaseSysCache(tuple
);
908 * Remove role from the pg_auth_members table. We have to remove all
909 * tuples that show it as either a role or a member.
911 * XXX what about grantor entries? Maybe we should do one heap scan.
913 ScanKeyInit(&scankey
,
914 Anum_pg_auth_members_roleid
,
915 BTEqualStrategyNumber
, F_OIDEQ
,
916 ObjectIdGetDatum(roleid
));
918 sscan
= systable_beginscan(pg_auth_members_rel
, AuthMemRoleMemIndexId
,
919 true, SnapshotNow
, 1, &scankey
);
921 while (HeapTupleIsValid(tmp_tuple
= systable_getnext(sscan
)))
923 simple_heap_delete(pg_auth_members_rel
, &tmp_tuple
->t_self
);
926 systable_endscan(sscan
);
928 ScanKeyInit(&scankey
,
929 Anum_pg_auth_members_member
,
930 BTEqualStrategyNumber
, F_OIDEQ
,
931 ObjectIdGetDatum(roleid
));
933 sscan
= systable_beginscan(pg_auth_members_rel
, AuthMemMemRoleIndexId
,
934 true, SnapshotNow
, 1, &scankey
);
936 while (HeapTupleIsValid(tmp_tuple
= systable_getnext(sscan
)))
938 simple_heap_delete(pg_auth_members_rel
, &tmp_tuple
->t_self
);
941 systable_endscan(sscan
);
944 * Remove any comments on this role.
946 DeleteSharedComments(roleid
, AuthIdRelationId
);
949 * Advance command counter so that later iterations of this loop will
950 * see the changes already made. This is essential if, for example,
951 * we are trying to drop both a role and one of its direct members ---
952 * we'll get an error if we try to delete the linking pg_auth_members
953 * tuple twice. (We do not need a CCI between the two delete loops
954 * above, because it's not allowed for a role to directly contain
957 CommandCounterIncrement();
961 * Now we can clean up; but keep locks until commit (to avoid possible
962 * deadlock failure while updating flat file)
964 heap_close(pg_auth_members_rel
, NoLock
);
965 heap_close(pg_authid_rel
, NoLock
);
968 * Set flag to update flat auth file at commit.
970 auth_file_update_needed();
977 RenameRole(const char *oldname
, const char *newname
)
985 Datum repl_val
[Natts_pg_authid
];
986 bool repl_null
[Natts_pg_authid
];
987 bool repl_repl
[Natts_pg_authid
];
991 rel
= heap_open(AuthIdRelationId
, RowExclusiveLock
);
992 dsc
= RelationGetDescr(rel
);
994 oldtuple
= SearchSysCache(AUTHNAME
,
995 CStringGetDatum(oldname
),
997 if (!HeapTupleIsValid(oldtuple
))
999 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1000 errmsg("role \"%s\" does not exist", oldname
)));
1003 * XXX Client applications probably store the session user somewhere, so
1004 * renaming it could cause confusion. On the other hand, there may not be
1005 * an actual problem besides a little confusion, so think about this and
1006 * decide. Same for SET ROLE ... we don't restrict renaming the current
1007 * effective userid, though.
1010 roleid
= HeapTupleGetOid(oldtuple
);
1012 if (roleid
== GetSessionUserId())
1014 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
1015 errmsg("session user cannot be renamed")));
1016 if (roleid
== GetOuterUserId())
1018 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
1019 errmsg("current user cannot be renamed")));
1021 /* make sure the new name doesn't exist */
1022 if (SearchSysCacheExists(AUTHNAME
,
1023 CStringGetDatum(newname
),
1026 (errcode(ERRCODE_DUPLICATE_OBJECT
),
1027 errmsg("role \"%s\" already exists", newname
)));
1029 if (strcmp(newname
, "public") == 0 ||
1030 strcmp(newname
, "none") == 0)
1032 (errcode(ERRCODE_RESERVED_NAME
),
1033 errmsg("role name \"%s\" is reserved",
1037 * createrole is enough privilege unless you want to mess with a superuser
1039 if (((Form_pg_authid
) GETSTRUCT(oldtuple
))->rolsuper
)
1043 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1044 errmsg("must be superuser to rename superusers")));
1048 if (!have_createrole_privilege())
1050 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1051 errmsg("permission denied to rename role")));
1054 /* OK, construct the modified tuple */
1055 for (i
= 0; i
< Natts_pg_authid
; i
++)
1056 repl_repl
[i
] = false;
1058 repl_repl
[Anum_pg_authid_rolname
- 1] = true;
1059 repl_val
[Anum_pg_authid_rolname
- 1] = DirectFunctionCall1(namein
,
1060 CStringGetDatum(newname
));
1061 repl_null
[Anum_pg_authid_rolname
- 1] = false;
1063 datum
= heap_getattr(oldtuple
, Anum_pg_authid_rolpassword
, dsc
, &isnull
);
1065 if (!isnull
&& isMD5(TextDatumGetCString(datum
)))
1067 /* MD5 uses the username as salt, so just clear it on a rename */
1068 repl_repl
[Anum_pg_authid_rolpassword
- 1] = true;
1069 repl_null
[Anum_pg_authid_rolpassword
- 1] = true;
1072 (errmsg("MD5 password cleared because of role rename")));
1075 newtuple
= heap_modify_tuple(oldtuple
, dsc
, repl_val
, repl_null
, repl_repl
);
1076 simple_heap_update(rel
, &oldtuple
->t_self
, newtuple
);
1078 CatalogUpdateIndexes(rel
, newtuple
);
1080 ReleaseSysCache(oldtuple
);
1083 * Close pg_authid, but keep lock till commit (this is important to
1084 * prevent any risk of deadlock failure while updating flat file)
1086 heap_close(rel
, NoLock
);
1089 * Set flag to update flat auth file at commit.
1091 auth_file_update_needed();
1097 * Grant/Revoke roles to/from roles
1100 GrantRole(GrantRoleStmt
*stmt
)
1102 Relation pg_authid_rel
;
1108 grantor
= get_roleid_checked(stmt
->grantor
);
1110 grantor
= GetUserId();
1112 grantee_ids
= roleNamesToIds(stmt
->grantee_roles
);
1114 /* AccessShareLock is enough since we aren't modifying pg_authid */
1115 pg_authid_rel
= heap_open(AuthIdRelationId
, AccessShareLock
);
1118 * Step through all of the granted roles and add/remove entries for the
1119 * grantees, or, if admin_opt is set, then just add/remove the admin
1122 * Note: Permissions checking is done by AddRoleMems/DelRoleMems
1124 foreach(item
, stmt
->granted_roles
)
1126 char *rolename
= strVal(lfirst(item
));
1127 Oid roleid
= get_roleid_checked(rolename
);
1130 AddRoleMems(rolename
, roleid
,
1131 stmt
->grantee_roles
, grantee_ids
,
1132 grantor
, stmt
->admin_opt
);
1134 DelRoleMems(rolename
, roleid
,
1135 stmt
->grantee_roles
, grantee_ids
,
1140 * Close pg_authid, but keep lock till commit (this is important to
1141 * prevent any risk of deadlock failure while updating flat file)
1143 heap_close(pg_authid_rel
, NoLock
);
1146 * Set flag to update flat auth file at commit.
1148 auth_file_update_needed();
1154 * Drop the objects owned by a given list of roles.
1157 DropOwnedObjects(DropOwnedStmt
*stmt
)
1159 List
*role_ids
= roleNamesToIds(stmt
->roles
);
1162 /* Check privileges */
1163 foreach(cell
, role_ids
)
1165 Oid roleid
= lfirst_oid(cell
);
1167 if (!has_privs_of_role(GetUserId(), roleid
))
1169 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1170 errmsg("permission denied to drop objects")));
1174 shdepDropOwned(role_ids
, stmt
->behavior
);
1178 * ReassignOwnedObjects
1180 * Give the objects owned by a given list of roles away to another user.
1183 ReassignOwnedObjects(ReassignOwnedStmt
*stmt
)
1185 List
*role_ids
= roleNamesToIds(stmt
->roles
);
1189 /* Check privileges */
1190 foreach(cell
, role_ids
)
1192 Oid roleid
= lfirst_oid(cell
);
1194 if (!has_privs_of_role(GetUserId(), roleid
))
1196 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1197 errmsg("permission denied to reassign objects")));
1200 /* Must have privileges on the receiving side too */
1201 newrole
= get_roleid_checked(stmt
->newrole
);
1203 if (!has_privs_of_role(GetUserId(), newrole
))
1205 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1206 errmsg("permission denied to reassign objects")));
1209 shdepReassignOwned(role_ids
, newrole
);
1215 * Given a list of role names (as String nodes), generate a list of role OIDs
1216 * in the same order.
1219 roleNamesToIds(List
*memberNames
)
1224 foreach(l
, memberNames
)
1226 char *rolename
= strVal(lfirst(l
));
1227 Oid roleid
= get_roleid_checked(rolename
);
1229 result
= lappend_oid(result
, roleid
);
1235 * AddRoleMems -- Add given members to the specified role
1237 * rolename: name of role to add to (used only for error messages)
1238 * roleid: OID of role to add to
1239 * memberNames: list of names of roles to add (used only for error messages)
1240 * memberIds: OIDs of roles to add
1241 * grantorId: who is granting the membership
1242 * admin_opt: granting admin option?
1244 * Note: caller is responsible for calling auth_file_update_needed().
1247 AddRoleMems(const char *rolename
, Oid roleid
,
1248 List
*memberNames
, List
*memberIds
,
1249 Oid grantorId
, bool admin_opt
)
1251 Relation pg_authmem_rel
;
1252 TupleDesc pg_authmem_dsc
;
1256 Assert(list_length(memberNames
) == list_length(memberIds
));
1258 /* Skip permission check if nothing to do */
1263 * Check permissions: must have createrole or admin option on the role to
1264 * be changed. To mess with a superuser role, you gotta be superuser.
1266 if (superuser_arg(roleid
))
1270 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1271 errmsg("must be superuser to alter superusers")));
1275 if (!have_createrole_privilege() &&
1276 !is_admin_of_role(grantorId
, roleid
))
1278 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1279 errmsg("must have admin option on role \"%s\"",
1283 /* XXX not sure about this check */
1284 if (grantorId
!= GetUserId() && !superuser())
1286 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1287 errmsg("must be superuser to set grantor")));
1289 pg_authmem_rel
= heap_open(AuthMemRelationId
, RowExclusiveLock
);
1290 pg_authmem_dsc
= RelationGetDescr(pg_authmem_rel
);
1292 forboth(nameitem
, memberNames
, iditem
, memberIds
)
1294 const char *membername
= strVal(lfirst(nameitem
));
1295 Oid memberid
= lfirst_oid(iditem
);
1296 HeapTuple authmem_tuple
;
1298 Datum new_record
[Natts_pg_auth_members
];
1299 bool new_record_nulls
[Natts_pg_auth_members
];
1300 bool new_record_repl
[Natts_pg_auth_members
];
1303 * Refuse creation of membership loops, including the trivial case
1304 * where a role is made a member of itself. We do this by checking to
1305 * see if the target role is already a member of the proposed member
1306 * role. We have to ignore possible superuserness, however, else we
1307 * could never grant membership in a superuser-privileged role.
1309 if (is_member_of_role_nosuper(roleid
, memberid
))
1311 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1312 (errmsg("role \"%s\" is a member of role \"%s\"",
1313 rolename
, membername
))));
1316 * Check if entry for this role/member already exists; if so, give
1317 * warning unless we are adding admin option.
1319 authmem_tuple
= SearchSysCache(AUTHMEMROLEMEM
,
1320 ObjectIdGetDatum(roleid
),
1321 ObjectIdGetDatum(memberid
),
1323 if (HeapTupleIsValid(authmem_tuple
) &&
1325 ((Form_pg_auth_members
) GETSTRUCT(authmem_tuple
))->admin_option
))
1328 (errmsg("role \"%s\" is already a member of role \"%s\"",
1329 membername
, rolename
)));
1330 ReleaseSysCache(authmem_tuple
);
1334 /* Build a tuple to insert or update */
1335 MemSet(new_record
, 0, sizeof(new_record
));
1336 MemSet(new_record_nulls
, false, sizeof(new_record_nulls
));
1337 MemSet(new_record_repl
, false, sizeof(new_record_repl
));
1339 new_record
[Anum_pg_auth_members_roleid
- 1] = ObjectIdGetDatum(roleid
);
1340 new_record
[Anum_pg_auth_members_member
- 1] = ObjectIdGetDatum(memberid
);
1341 new_record
[Anum_pg_auth_members_grantor
- 1] = ObjectIdGetDatum(grantorId
);
1342 new_record
[Anum_pg_auth_members_admin_option
- 1] = BoolGetDatum(admin_opt
);
1344 if (HeapTupleIsValid(authmem_tuple
))
1346 new_record_repl
[Anum_pg_auth_members_grantor
- 1] = true;
1347 new_record_repl
[Anum_pg_auth_members_admin_option
- 1] = true;
1348 tuple
= heap_modify_tuple(authmem_tuple
, pg_authmem_dsc
,
1350 new_record_nulls
, new_record_repl
);
1351 simple_heap_update(pg_authmem_rel
, &tuple
->t_self
, tuple
);
1352 CatalogUpdateIndexes(pg_authmem_rel
, tuple
);
1353 ReleaseSysCache(authmem_tuple
);
1357 tuple
= heap_form_tuple(pg_authmem_dsc
,
1358 new_record
, new_record_nulls
);
1359 simple_heap_insert(pg_authmem_rel
, tuple
);
1360 CatalogUpdateIndexes(pg_authmem_rel
, tuple
);
1363 /* CCI after each change, in case there are duplicates in list */
1364 CommandCounterIncrement();
1368 * Close pg_authmem, but keep lock till commit (this is important to
1369 * prevent any risk of deadlock failure while updating flat file)
1371 heap_close(pg_authmem_rel
, NoLock
);
1375 * DelRoleMems -- Remove given members from the specified role
1377 * rolename: name of role to del from (used only for error messages)
1378 * roleid: OID of role to del from
1379 * memberNames: list of names of roles to del (used only for error messages)
1380 * memberIds: OIDs of roles to del
1381 * admin_opt: remove admin option only?
1383 * Note: caller is responsible for calling auth_file_update_needed().
1386 DelRoleMems(const char *rolename
, Oid roleid
,
1387 List
*memberNames
, List
*memberIds
,
1390 Relation pg_authmem_rel
;
1391 TupleDesc pg_authmem_dsc
;
1395 Assert(list_length(memberNames
) == list_length(memberIds
));
1397 /* Skip permission check if nothing to do */
1402 * Check permissions: must have createrole or admin option on the role to
1403 * be changed. To mess with a superuser role, you gotta be superuser.
1405 if (superuser_arg(roleid
))
1409 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1410 errmsg("must be superuser to alter superusers")));
1414 if (!have_createrole_privilege() &&
1415 !is_admin_of_role(GetUserId(), roleid
))
1417 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
1418 errmsg("must have admin option on role \"%s\"",
1422 pg_authmem_rel
= heap_open(AuthMemRelationId
, RowExclusiveLock
);
1423 pg_authmem_dsc
= RelationGetDescr(pg_authmem_rel
);
1425 forboth(nameitem
, memberNames
, iditem
, memberIds
)
1427 const char *membername
= strVal(lfirst(nameitem
));
1428 Oid memberid
= lfirst_oid(iditem
);
1429 HeapTuple authmem_tuple
;
1432 * Find entry for this role/member
1434 authmem_tuple
= SearchSysCache(AUTHMEMROLEMEM
,
1435 ObjectIdGetDatum(roleid
),
1436 ObjectIdGetDatum(memberid
),
1438 if (!HeapTupleIsValid(authmem_tuple
))
1441 (errmsg("role \"%s\" is not a member of role \"%s\"",
1442 membername
, rolename
)));
1448 /* Remove the entry altogether */
1449 simple_heap_delete(pg_authmem_rel
, &authmem_tuple
->t_self
);
1453 /* Just turn off the admin option */
1455 Datum new_record
[Natts_pg_auth_members
];
1456 bool new_record_nulls
[Natts_pg_auth_members
];
1457 bool new_record_repl
[Natts_pg_auth_members
];
1459 /* Build a tuple to update with */
1460 MemSet(new_record
, 0, sizeof(new_record
));
1461 MemSet(new_record_nulls
, false, sizeof(new_record_nulls
));
1462 MemSet(new_record_repl
, false, sizeof(new_record_repl
));
1464 new_record
[Anum_pg_auth_members_admin_option
- 1] = BoolGetDatum(false);
1465 new_record_repl
[Anum_pg_auth_members_admin_option
- 1] = true;
1467 tuple
= heap_modify_tuple(authmem_tuple
, pg_authmem_dsc
,
1469 new_record_nulls
, new_record_repl
);
1470 simple_heap_update(pg_authmem_rel
, &tuple
->t_self
, tuple
);
1471 CatalogUpdateIndexes(pg_authmem_rel
, tuple
);
1474 ReleaseSysCache(authmem_tuple
);
1476 /* CCI after each change, in case there are duplicates in list */
1477 CommandCounterIncrement();
1481 * Close pg_authmem, but keep lock till commit (this is important to
1482 * prevent any risk of deadlock failure while updating flat file)
1484 heap_close(pg_authmem_rel
, NoLock
);