@@ -94,6 +94,8 @@ static void DelRoleMems(const char *rolename, Oid roleid,
94
94
List * memberSpecs , List * memberIds ,
95
95
Oid grantorId , GrantRoleOptions * popt ,
96
96
DropBehavior behavior );
97
+ static void check_role_membership_authorization (Oid currentUserId , Oid roleid ,
98
+ bool is_grant );
97
99
static Oid check_role_grantor (Oid currentUserId , Oid roleid , Oid grantorId ,
98
100
bool is_grant );
99
101
static RevokeRoleGrantAction * initialize_revoke_actions (CatCList * memlist );
@@ -505,6 +507,8 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
505
507
Oid oldroleid = oldroleform -> oid ;
506
508
char * oldrolename = NameStr (oldroleform -> rolname );
507
509
510
+ /* can only add this role to roles for which you have rights */
511
+ check_role_membership_authorization (GetUserId (), oldroleid , true);
508
512
AddRoleMems (oldrolename , oldroleid ,
509
513
thisrole_list ,
510
514
thisrole_oidlist ,
@@ -517,6 +521,9 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
517
521
/*
518
522
* Add the specified members to this new role. adminmembers get the admin
519
523
* option, rolemembers don't.
524
+ *
525
+ * NB: No permissions check is required here. If you have enough rights
526
+ * to create a role, you can add any members you like.
520
527
*/
521
528
AddRoleMems (stmt -> role , roleid ,
522
529
rolemembers , roleSpecsToIds (rolemembers ),
@@ -1442,6 +1449,8 @@ GrantRole(ParseState *pstate, GrantRoleStmt *stmt)
1442
1449
errmsg ("column names cannot be included in GRANT/REVOKE ROLE" )));
1443
1450
1444
1451
roleid = get_role_oid (rolename , false);
1452
+ check_role_membership_authorization (GetUserId (), roleid ,
1453
+ stmt -> is_grant );
1445
1454
if (stmt -> is_grant )
1446
1455
AddRoleMems (rolename , roleid ,
1447
1456
stmt -> grantee_roles , grantee_ids ,
@@ -1566,43 +1575,6 @@ AddRoleMems(const char *rolename, Oid roleid,
1566
1575
1567
1576
Assert (list_length (memberSpecs ) == list_length (memberIds ));
1568
1577
1569
- /* Skip permission check if nothing to do */
1570
- if (!memberIds )
1571
- return ;
1572
-
1573
- /*
1574
- * Check permissions: must have createrole or admin option on the role to
1575
- * be changed. To mess with a superuser role, you gotta be superuser.
1576
- */
1577
- if (superuser_arg (roleid ))
1578
- {
1579
- if (!superuser ())
1580
- ereport (ERROR ,
1581
- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1582
- errmsg ("must be superuser to alter superusers" )));
1583
- }
1584
- else
1585
- {
1586
- if (!have_createrole_privilege () &&
1587
- !is_admin_of_role (currentUserId , roleid ))
1588
- ereport (ERROR ,
1589
- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1590
- errmsg ("must have admin option on role \"%s\"" ,
1591
- rolename )));
1592
- }
1593
-
1594
- /*
1595
- * The charter of pg_database_owner is to have exactly one, implicit,
1596
- * situation-dependent member. There's no technical need for this
1597
- * restriction. (One could lift it and take the further step of making
1598
- * object_ownercheck(DatabaseRelationId, ...) equivalent to has_privs_of_role(roleid,
1599
- * ROLE_PG_DATABASE_OWNER), in which case explicit, situation-independent
1600
- * members could act as the owner of any database.)
1601
- */
1602
- if (roleid == ROLE_PG_DATABASE_OWNER )
1603
- ereport (ERROR ,
1604
- errmsg ("role \"%s\" cannot have explicit members" , rolename ));
1605
-
1606
1578
/* Validate grantor (and resolve implicit grantor if not specified). */
1607
1579
grantorId = check_role_grantor (currentUserId , roleid , grantorId , true);
1608
1580
@@ -1902,31 +1874,6 @@ DelRoleMems(const char *rolename, Oid roleid,
1902
1874
1903
1875
Assert (list_length (memberSpecs ) == list_length (memberIds ));
1904
1876
1905
- /* Skip permission check if nothing to do */
1906
- if (!memberIds )
1907
- return ;
1908
-
1909
- /*
1910
- * Check permissions: must have createrole or admin option on the role to
1911
- * be changed. To mess with a superuser role, you gotta be superuser.
1912
- */
1913
- if (superuser_arg (roleid ))
1914
- {
1915
- if (!superuser ())
1916
- ereport (ERROR ,
1917
- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1918
- errmsg ("must be superuser to alter superusers" )));
1919
- }
1920
- else
1921
- {
1922
- if (!have_createrole_privilege () &&
1923
- !is_admin_of_role (currentUserId , roleid ))
1924
- ereport (ERROR ,
1925
- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1926
- errmsg ("must have admin option on role \"%s\"" ,
1927
- rolename )));
1928
- }
1929
-
1930
1877
/* Validate grantor (and resolve implicit grantor if not specified). */
1931
1878
grantorId = check_role_grantor (currentUserId , roleid , grantorId , false);
1932
1879
@@ -2040,6 +1987,51 @@ DelRoleMems(const char *rolename, Oid roleid,
2040
1987
table_close (pg_authmem_rel , NoLock );
2041
1988
}
2042
1989
1990
+ /*
1991
+ * Check that currentUserId has permission to modify the membership list for
1992
+ * roleid. Throw an error if not.
1993
+ */
1994
+ static void
1995
+ check_role_membership_authorization (Oid currentUserId , Oid roleid ,
1996
+ bool is_grant )
1997
+ {
1998
+ /*
1999
+ * The charter of pg_database_owner is to have exactly one, implicit,
2000
+ * situation-dependent member. There's no technical need for this
2001
+ * restriction. (One could lift it and take the further step of making
2002
+ * object_ownercheck(DatabaseRelationId, ...) equivalent to
2003
+ * has_privs_of_role(roleid, ROLE_PG_DATABASE_OWNER), in which case
2004
+ * explicit, situation-independent members could act as the owner of any
2005
+ * database.)
2006
+ */
2007
+ if (is_grant && roleid == ROLE_PG_DATABASE_OWNER )
2008
+ ereport (ERROR ,
2009
+ errmsg ("role \"%s\" cannot have explicit members" ,
2010
+ GetUserNameFromId (roleid , false)));
2011
+
2012
+ /* To mess with a superuser role, you gotta be superuser. */
2013
+ if (superuser_arg (roleid ))
2014
+ {
2015
+ if (!superuser_arg (currentUserId ))
2016
+ ereport (ERROR ,
2017
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
2018
+ errmsg ("must be superuser to alter superusers" )));
2019
+ }
2020
+ else
2021
+ {
2022
+ /*
2023
+ * Otherwise, must have createrole or admin option on the role to be
2024
+ * changed.
2025
+ */
2026
+ if (!has_createrole_privilege (currentUserId ) &&
2027
+ !is_admin_of_role (currentUserId , roleid ))
2028
+ ereport (ERROR ,
2029
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
2030
+ errmsg ("must have admin option on role \"%s\"" ,
2031
+ GetUserNameFromId (roleid , false))));
2032
+ }
2033
+ }
2034
+
2043
2035
/*
2044
2036
* Sanity-check, or infer, the grantor for a GRANT or REVOKE statement
2045
2037
* targeting a role.
0 commit comments