@@ -116,6 +116,7 @@ static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
116116
117117static void RoleMembershipCacheCallback (Datum arg , int cacheid , uint32 hashvalue );
118118
119+ static bool has_privs_of_unwanted_system_role (Oid role );
119120
120121/*
121122 * getid
@@ -4991,9 +4992,65 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type,
49914992 * set; for such roles, membership implies the ability to do SET ROLE, but
49924993 * the privileges are not available until you've done so.
49934994 */
4995+
4996+ /*
4997+ * This is basically original postgresql privs-check function
4998+ */
4999+
5000+ // -- mdb_superuser patch
5001+
5002+ bool
5003+ has_privs_of_role_strict (Oid member , Oid role )
5004+ {
5005+ /* Fast path for simple case */
5006+ if (member == role )
5007+ return true;
5008+
5009+ /* Superusers have every privilege, so are part of every role */
5010+ if (superuser_arg (member ))
5011+ return true;
5012+
5013+ /*
5014+ * Find all the roles that member has the privileges of, including
5015+ * multi-level recursion, then see if target role is any one of them.
5016+ */
5017+ return list_member_oid (roles_is_member_of (member , ROLERECURSE_PRIVS ,
5018+ InvalidOid , NULL ),
5019+ role );
5020+ }
5021+
5022+ /*
5023+ * Check that role is either one of "dangerous" system role
5024+ * or has "strict" (not through mdb_admin or mdb_superuser)
5025+ * privs of this role
5026+ */
5027+
5028+ static bool
5029+ has_privs_of_unwanted_system_role (Oid role ) {
5030+ if (has_privs_of_role_strict (role , ROLE_PG_READ_SERVER_FILES )) {
5031+ return true;
5032+ }
5033+ if (has_privs_of_role_strict (role , ROLE_PG_WRITE_SERVER_FILES )) {
5034+ return true;
5035+ }
5036+ if (has_privs_of_role_strict (role , ROLE_PG_EXECUTE_SERVER_PROGRAM )) {
5037+ return true;
5038+ }
5039+ if (has_privs_of_role_strict (role , ROLE_PG_READ_ALL_DATA )) {
5040+ return true;
5041+ }
5042+ if (has_privs_of_role_strict (role , ROLE_PG_WRITE_ALL_DATA )) {
5043+ return true;
5044+ }
5045+
5046+ return false;
5047+ }
5048+
49945049bool
49955050has_privs_of_role (Oid member , Oid role )
49965051{
5052+ Oid mdb_superuser_roleoid ;
5053+
49975054 /* Fast path for simple case */
49985055 if (member == role )
49995056 return true;
@@ -5002,6 +5059,23 @@ has_privs_of_role(Oid member, Oid role)
50025059 if (superuser_arg (member ))
50035060 return true;
50045061
5062+ mdb_superuser_roleoid = get_role_oid ("mdb_superuser" , true /*if nodoby created mdb_superuser role in this database*/ );
5063+
5064+ if (is_member_of_role (member , mdb_superuser_roleoid )) {
5065+ /* if target role is superuser, disallow */
5066+ if (!superuser_arg (role )) {
5067+ /* we want mdb_roles_admin to bypass
5068+ * has_priv_of_roles test
5069+ * if target role is neither superuser nor
5070+ * some dangerous system role
5071+ */
5072+ if (!has_privs_of_unwanted_system_role (role )) {
5073+ return true;
5074+ }
5075+ }
5076+ }
5077+
5078+
50055079 /*
50065080 * Find all the roles that member has the privileges of, including
50075081 * multi-level recursion, then see if target role is any one of them.
@@ -5011,6 +5085,7 @@ has_privs_of_role(Oid member, Oid role)
50115085 role );
50125086}
50135087
5088+ // -- mdb_superuser patch
50145089
50155090// -- non-upstream patch begin
50165091/*
@@ -5032,7 +5107,7 @@ mdb_admin_allow_bypass_owner_checks(Oid userId, Oid ownerId)
50325107 return false;
50335108 }
50345109
5035- mdb_admin_roleoid = get_role_oid ("mdb_admin" , true /* superuser suggested to be mdb_admin */ );
5110+ mdb_admin_roleoid = get_role_oid ("mdb_admin" , true /*if nodoby created mdb_admin role in this database */ );
50365111 /* Is userId actually member of mdb admin? */
50375112 if (!is_member_of_role (userId , mdb_admin_roleoid )) {
50385113 /* if no, disallow. */
@@ -5045,23 +5120,11 @@ mdb_admin_allow_bypass_owner_checks(Oid userId, Oid ownerId)
50455120 *
50465121 * For now, we check that ownerId does not have
50475122 * priviledge to execute server program or/and
5048- * read/write server files.
5123+ * read/write server files, or/and pg read/write all data
50495124 */
50505125
5051- if (has_privs_of_role (ownerId , ROLE_PG_READ_SERVER_FILES )) {
5052- return false;
5053- }
5054-
5055- if (has_privs_of_role (ownerId , ROLE_PG_WRITE_SERVER_FILES )) {
5056- return false;
5057- }
5058-
5059- if (has_privs_of_role (ownerId , ROLE_PG_EXECUTE_SERVER_PROGRAM )) {
5060- return false;
5061- }
5062-
50635126 /* All checks passed, hope will not be hacked here (again) */
5064- return true ;
5127+ return ! has_privs_of_unwanted_system_role ( ownerId ) ;
50655128}
50665129
50675130// -- non-upstream patch end
@@ -5110,7 +5173,7 @@ check_is_member_of_role(Oid member, Oid role)
51105173 * check_mdb_admin_is_member_of_role
51115174 * is_member_of_role with a standard permission-violation error if not in usual case
51125175 * Is case `member` in mdb_admin we check that role is neither of superuser, pg_read/write
5113- * server files nor pg_execute_server_program
5176+ * server files nor pg_execute_server_program or pg_read/write all data
51145177 */
51155178void
51165179check_mdb_admin_is_member_of_role (Oid member , Oid role )
@@ -5121,9 +5184,10 @@ check_mdb_admin_is_member_of_role(Oid member, Oid role)
51215184 return ;
51225185 }
51235186
5124- mdb_admin_roleoid = get_role_oid ("mdb_admin" , true /* superuser suggested to be mdb_admin */ );
5187+ mdb_admin_roleoid = get_role_oid ("mdb_admin" , true /*if nodoby created mdb_admin role in this database */ );
51255188 /* Is userId actually member of mdb admin? */
51265189 if (is_member_of_role (member , mdb_admin_roleoid )) {
5190+
51275191 /* role is mdb admin */
51285192 if (superuser_arg (role )) {
51295193 ereport (ERROR ,
@@ -5132,22 +5196,10 @@ check_mdb_admin_is_member_of_role(Oid member, Oid role)
51325196 GetUserNameFromId (role , false))));
51335197 }
51345198
5135- if (has_privs_of_role (role , ROLE_PG_READ_SERVER_FILES )) {
5199+ if (has_privs_of_unwanted_system_role (role )) {
51365200 ereport (ERROR ,
51375201 (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
5138- errmsg ("cannot transfer ownership to pg_read_server_files role in Cloud" )));
5139- }
5140-
5141- if (has_privs_of_role (role , ROLE_PG_WRITE_SERVER_FILES )) {
5142- ereport (ERROR ,
5143- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
5144- errmsg ("cannot transfer ownership to pg_write_server_files role in Cloud" )));
5145- }
5146-
5147- if (has_privs_of_role (role , ROLE_PG_EXECUTE_SERVER_PROGRAM )) {
5148- ereport (ERROR ,
5149- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
5150- errmsg ("cannot transfer ownership to pg_execute_server_program role in Cloud" )));
5202+ errmsg ("forbidden to transfer ownership to this system role in Cloud" )));
51515203 }
51525204 } else {
51535205 /* if no, check membership transfer in usual way. */
@@ -5287,6 +5339,7 @@ select_best_grantor(Oid roleId, AclMode privileges,
52875339 List * roles_list ;
52885340 int nrights ;
52895341 ListCell * l ;
5342+ Oid mdb_superuser_roleoid ;
52905343
52915344 /*
52925345 * The object owner is always treated as having all grant options, so if
@@ -5301,6 +5354,16 @@ select_best_grantor(Oid roleId, AclMode privileges,
53015354 return ;
53025355 }
53035356
5357+ mdb_superuser_roleoid = get_role_oid ("mdb_superuser" , true /*if nodoby created mdb_superuser role in this database*/ );
5358+
5359+ if (is_member_of_role (GetUserId (), mdb_superuser_roleoid )
5360+ && has_privs_of_role (GetUserId (), ownerId )) {
5361+ * grantorId = mdb_superuser_roleoid ;
5362+ AclMode mdb_superuser_allowed_privs = needed_goptions ;
5363+ * grantOptions = mdb_superuser_allowed_privs ;
5364+ return ;
5365+ }
5366+
53045367 /*
53055368 * Otherwise we have to do a careful search to see if roleId has the
53065369 * privileges of any suitable role. Note: we can hang onto the result of
@@ -5309,7 +5372,6 @@ select_best_grantor(Oid roleId, AclMode privileges,
53095372 */
53105373 roles_list = roles_is_member_of (roleId , ROLERECURSE_PRIVS ,
53115374 InvalidOid , NULL );
5312-
53135375 /* initialize candidate result as default */
53145376 * grantorId = roleId ;
53155377 * grantOptions = ACL_NO_RIGHTS ;
0 commit comments