TinyPortal

Development => Block Codes => Topic started by: Thurnok on April 29, 2007, 12:48:20 PM

Title: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Thurnok on April 29, 2007, 12:48:20 PM
This is one I did a long time back, but just updated it.

NOTE: Tested with SMF 1.1 RCx and 1.1.1 only!  But should work on SMF 1.1.2

Well... here's what I did...




First - Settings.php (couldn't really find a better place for it, if you do, go for it)
Find:
# Make sure the paths are correct... at least try to fix them.
if (!file_exists($boarddir) && file_exists(dirname(__FILE__) . '/agreement.txt'))
$boarddir = dirname(__FILE__);
if (!file_exists($sourcedir) && file_exists($boarddir . '/Sources'))
$sourcedir = $boarddir . '/Sources';


Add Before:

#############  Thurnok's Disable Delete Admins Hack  #############
$pu_protected_users = array(1, 2, 31);
$pu_users_can_bypass = array(1);
$pu_bypass_self = 0;
##################################################################

NOTES:
$pu_protected_users is an array of user's IDs you do not want anyone (including other admins) to be able to arbitrarily delete or remove from the Admin group.  Remember to change the array to member IDs you want to protect, the ones shown are examples only!(deletion and removal from admin group now works properly in profile screen!)
$pu_users_can_bypass is an array of users that ignore the protected status of the $pu_protected_users.
$pu_bypass_self is a bool (0 = false, 1 = true) of whether you can bypass protection from deleting your own ID even if you are in the $pu_users_can_bypass array.  In otherwords, leave this set to 0 to protected deleting your ID / removing your own admin access!





Next - /Sources/Subs-Members.php
Find:
// Delete a group of/single member.
function deleteMembers($users)
{
global $db_prefix, $sourcedir, $modSettings, $ID_MEMBER;


Add After:

#############  Thurnok's Disable Delete Admins Hack  #############
global $pu_protected_users, $pu_users_can_bypass, $pu_bypass_self;
##################################################################


Find:
// If it's not an array, make it so!
if (!is_array($users))
$users = array($users);
else
$users = array_unique($users);

// Make sure there's no void user in here.
$users = array_diff($users, array(0));


Add After:

#############  Thurnok's Disable Delete Admins Hack  #############
// if user not allowed to bypass protection
if (!in_array($ID_MEMBER, $pu_users_can_bypass)){
// get the users that won't be deleted of the selected ones
$pu_not_deleted_users = implode(",", array_values(array_intersect($pu_protected_users, $users)));
// remove protected users from the $users array
$users = array_values(array_diff($users, $pu_protected_users));
if (!empty($pu_not_deleted_users)){
echo '
<script type="text/javascript">
<!--
msg = "Could not delete protected user ID(s): '.$pu_not_deleted_users.'";
alert(msg);
// -->
</script>
';
}
} else {
if (in_array($ID_MEMBER, $users) && empty($pu_bypass_self)){
// remove self from deletion array
$users = array_values(array_diff($users, array($ID_MEMBER)));
echo '
<script type="text/javascript">
<!--
msg = "Sorry, protection is enabled to prevent you from deleting yourself!  Other IDs deleted successfully.";
alert(msg);
// -->
</script>
';
}
}
##################################################################


Find:
// How many are they deleting?
if (empty($users))
return;


Replace with:

#############  Thurnok's Disable Delete Admins Hack  #############
// // How many are they deleting?
// if (empty($users))
// return;

// How many are they deleting?
if (empty($users))
return false;
##################################################################


Find:
// Remove one or more members from one or more membergroups.
function removeMembersFromGroups($members, $groups = null)
{
global $db_prefix;


Add After:

#############  Thurnok's Disable Delete Admins Hack  #############
global $pu_protected_users, $pu_users_can_bypass, $pu_bypass_self, $ID_MEMBER;
##################################################################


Find:
// Cleaning the input.
if (!is_array($members))
$members = array((int) $members);
else
{
$members = array_unique($members);

// Cast the members to integer.
foreach ($members as $key => $value)
$members[$key] = (int) $value;
}


Add After:

#############  Thurnok's Disable Delete Admins Hack  #############
// if user not allowed to bypass protection
if (!in_array($ID_MEMBER, $pu_users_can_bypass)){
// get the users that won't be deleted of the selected ones
$pu_not_deleted_users = implode(",", array_values(array_intersect($pu_protected_users, $members)));
// remove protected users from the $members array
$members = array_values(array_diff($members, $pu_protected_users));
if (!empty($pu_not_deleted_users)){
echo '
<script type="text/javascript">
<!--
msg = "Could not remove the following protected user ID(s) from this group: '.$pu_not_deleted_users.'";
alert(msg);
// -->
</script>
';
}
} else {
if (in_array($ID_MEMBER, $members) && empty($pu_bypass_self)){
// remove self from deletion array
$members = array_values(array_diff($members, array($ID_MEMBER)));
echo '
<script type="text/javascript">
<!--
msg = "Sorry, protection is enabled to prevent you from removing yourself from this group!  Other IDs removed successfully.";
alert(msg);
// -->
</script>
';
}
}
##################################################################






Next - /Sources/Profile.php
Find:

// Save the profile changes....
function saveProfileChanges(&$profile_vars, &$post_errors, $memID)
{
global $db_prefix, $user_info, $txt, $modSettings, $user_profile;
global $newpassemail, $validationCode, $context, $settings, $sourcedir;
global $func;


Add After:

#############  Thurnok's Disable Delete Admins Hack  #############
global $pu_protected_users, $pu_users_can_bypass, $pu_bypass_self, $ID_MEMBER;
##################################################################



Find:

// Assigning membergroups (you need admin_forum permissions to change an admins' membergroups).
if (allowedTo('manage_membergroups'))
{
// The account page allows the change of your ID_GROUP - but not to admin!.
if (isset($_POST['ID_GROUP']) && (allowedTo('admin_forum') || ((int) $_POST['ID_GROUP'] != 1 && $old_profile['ID_GROUP'] != 1)))
$profile_vars['ID_GROUP'] = (int) $_POST['ID_GROUP'];


Add After:

#############  Thurnok's Disable Delete Admins Hack  #############
// if they used to be an admin, but now not - validate protected users
if ($old_profile['ID_GROUP'] == 1 && $profile_vars['ID_GROUP'] != 1){
// trying to remove admin group privileges... check if protected user!
if (in_array($memID, $pu_protected_users)){
// user is protected, are we allowed to bypass?
if (!in_array($ID_MEMBER, $pu_users_can_bypass)){
// I can't bypass, don't change them!
$_POST['ID_GROUP'] = 1;
$profile_vars['ID_GROUP'] = 1;
} else {
if ($ID_MEMBER == $memID && empty($pu_bypass_self)){
// I am not allowed to change self
$_POST['ID_GROUP'] = 1;
$profile_vars['ID_GROUP'] = 1;
}
}
}
}
##################################################################



Find:

// Find the additional membergroups (if any)
if (isset($_POST['additionalGroups']) && is_array($_POST['additionalGroups']))
{
foreach ($_POST['additionalGroups'] as $i => $group_id)
{
if ((int) $group_id == 0 || (!allowedTo('admin_forum') && (int) $group_id == 1))
unset($_POST['additionalGroups'][$i], $_POST['additionalGroups'][$i]);
else
$_POST['additionalGroups'][$i] = (int) $group_id;
}

// Put admin back in there if you don't have permission to take it away.
if (!allowedTo('admin_forum') && in_array(1, explode(',', $old_profile['additionalGroups'])))
$_POST['additionalGroups'][] = 1;

$profile_vars['additionalGroups'] = '\'' . implode(',', $_POST['additionalGroups']) . '\'';
}


Add After:

#############  Thurnok's Disable Delete Admins Hack  #############
// if they used to be an admin as an additional group, but now not - validate protected users
if (in_array(1, explode(',', $old_profile['additionalGroups'])) && !in_array(1, explode(',', $profile_vars['additionalGroups'])) && $profile_vars['ID_GROUP'] != 1){
// trying to remove admin group privileges... check if protected user!
if (in_array($memID, $pu_protected_users)){
// user is protected, are we allowed to bypass?
if (!in_array($ID_MEMBER, $pu_users_can_bypass)){
// I can't bypass, put admin additional group back!
$_POST['additionalGroups'][] = 1;
$profile_vars['additionalGroups'] = '\'' . implode(',', $_POST['additionalGroups']) . '\'';
} else {
if ($ID_MEMBER == $memID && empty($pu_bypass_self)){
// I am not allowed to change self
$_POST['additionalGroups'][] = 1;
$profile_vars['additionalGroups'] = '\'' . implode(',', $_POST['additionalGroups']) . '\'';
}
}
}
}
##################################################################



Find:

function deleteAccount2($profile_vars, $post_errors, $memID)
{
global $ID_MEMBER, $user_info, $sourcedir, $context, $db_prefix, $user_profile, $modSettings;


Add After:

#############  Thurnok's Disable Delete Admins Hack  #############
global $pu_protected_users, $pu_users_can_bypass, $pu_bypass_self, $boardurl;
// if this user is protected
if (in_array($memID, $pu_protected_users)){
// are we allowed to bypass protection?
if (!in_array($ID_MEMBER, $pu_users_can_bypass)){
// No?  Sorry, no can delete then!
echo '
<body onload="try {self.location.href=\''.$boardurl.'/index.php?action=profile;u='.$memID.'\' } catch(e) {}"><a href="'.$boardurl.'/index.php?action=profile;u='.$memID.'">return</a>
<script type="text/javascript">
<!--
msg = "Could not delete protected user ID: '.$memID.'";
alert(msg);
// -->
</script>
</body>
';
flush();
if (!headers_sent()) {
ob_end_clean();
header("Location: " . $boardurl . "/index.php?action=profile;u=".$memID);
}
exit;
} else {
// we can bypass, but if it is us and cannnot bypass self, don't delete either
if ($ID_MEMBER == $memID && empty($pu_bypass_self)){
// can't bypass self is set, so no delete
echo '
<body onload="try {self.location.href=\''.$boardurl.'/index.php?action=profile;u='.$memID.'\' } catch(e) {}"><a href="'.$boardurl.'/index.php?action=profile;u='.$memID.'">return</a>
<script type="text/javascript">
<!--
msg = "Sorry, protection is enabled to prevent you from deleting yourself!";
alert(msg);
// -->
</script>
</body>
';
flush();
if (!headers_sent()) {
ob_end_clean();
header("Location: " . $boardurl . "/index.php?action=profile;u=".$memID);
}
exit;
}
}
}
##################################################################

Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Crip on April 29, 2007, 01:00:31 PM
you code monkey U ;D
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Ken. on April 29, 2007, 01:07:06 PM
Looks like you had to put more than little work into this one...  and it's a most worthy effort!  ;D

Thanks Thurnok, you build some great code. :up:
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: tribalost on April 29, 2007, 02:31:55 PM
can i ask permission to package this? hmm btw this should really be included in the core since its a great security benefit :D

Edit:
#############  Thurnok's Disable Delete Admins Hack  #############
// // How many are they deleting?
// if (empty($users))
// return;

// How many are they deleting?
if (empty($users)){
return false;
##################################################################


Returned an error for me on 1.1.2 (I dunno about the other versions thou)
so I removed the "{" after if "(empty($users))"...

here's the full
#############  Thurnok's Disable Delete Admins Hack  #############
// // How many are they deleting?
// if (empty($users))
// return;

// How many are they deleting?
if (empty($users))
return false;
##################################################################
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: RoarinRow on April 29, 2007, 03:41:01 PM
Sweet idea!  A package would be great!   :up:
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Thurnok on April 29, 2007, 10:00:08 PM
Modified the code in the first post.

Here's the reason you got the error...

In my original code I had:

// How many are they deleting?
if (empty($users)){
// some other code and stuff here I later removed
return false;
}
##################################################################


... then I changed the code to:

// How many are they deleting?
if (empty($users)){
return false;
##################################################################

}


LOL.. in other words, I accidentally moved my comment marker above the "}" that was still actually in my code... but when I was copying all my code segments to post, the last curly brace was left out since I use my code markers to know where my modified code was... hehe  woopsie :)

Anyway, the starting and ending curly brace is not needed for that segment now since I removed the other code I had there originally that I found also unneeded.. so I've updated the source in the first post to reflect the change.

Have fun :)
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Thurnok on April 29, 2007, 10:09:44 PM
There had been requests for making the options available via the ACP, however, I have not done so because of one major factor:

If you are an Admin, you can access the ACP and change the values!  I didn't make this only to prevent "accidental" removal, I also wanted to ensure that "you" as the site owner could prevent any of your Admins from removing "you" on purpose, at least to the best of abilities.  The way it is setup, in order to circumvent the protection they must have direct file access to your settings.php file.  This would not be the case if the settings (who is protected, who can bypass, etc) were in the ACP.

I was planning on packaging it after I tested it with SMF 1.1.2 (it was late when I finished it hehe), but I'm assuming you installed it on 1.1.2 by what you posted.  Have you seen any issues (other than my slip of the cut/paste already noted)?
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Zetan on April 29, 2007, 10:34:15 PM
I'm currently the only Admin, but if I do choose a co Admin sometime, then I will definatly be using this Thurnok.
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: tribalost on April 30, 2007, 12:04:36 AM
nope everything  workin like a charm :D... very usefull code indeed... at least no one can remove you from the root :D
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: RoarinRow on April 30, 2007, 05:27:59 AM
Thanks for the code, I made the changes manually   :up:
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Reality12 on May 02, 2007, 03:24:59 PM
I've been looking for something like this for a while now!

I'll have to play with the code later, since I'm at work right now, but I look forward to a package too!
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Thurnok on May 03, 2007, 05:49:45 AM
Been tied up this week with <ick> "work" stuff.  But I'll see about putting something together this weekend.
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: Thurnok on May 05, 2007, 10:08:40 PM
This is now an SMF mod, you can download the mod from my TP Blocks site (http://www.tpblocks.com).  I'll be submitting to SMF today.
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: babjusi on May 09, 2007, 02:58:21 PM
Quote from: Thurnok on May 05, 2007, 10:08:40 PM
This is now an SMF mod, you can download the mod from my TP Blocks site (http://www.tpblocks.com).  I'll be submitting to SMF today.

Thanks for making this into a package, it''s such a handy mod. Can you please tell me the direct link where I can doqnload it, cause I couldn''t find it yet at SMF site, thank you
Title: Re: [SMF HACK] Protect Admin Users from Deletion/Admin Removal
Post by: G6Cad on May 09, 2007, 03:23:42 PM
It's not approved by the SMF staff yet.

As for now you can get it from Thurnoks own site. (need to be registerd there to get to the download)