TP-Docs
HTML5 Icon HTML5 Icon HTML5 Icon
TP on Social Media

Recent

Welcome to TinyPortal. Please login or sign up.

April 30, 2024, 12:07:18 PM

Login with username, password and session length
Members
  • Total Members: 3,885
  • Latest: Growner
Stats
  • Total Posts: 195,174
  • Total Topics: 21,220
  • Online today: 147
  • Online ever: 3,540 (September 03, 2022, 01:38:54 AM)
Users Online
  • Users: 0
  • Guests: 99
  • Total: 99

[SMF HACK] Protect Admin Users from Deletion/Admin Removal

Started by Thurnok, April 29, 2007, 12:48:20 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Thurnok

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;
}
}
}
##################################################################


Crip

I have become comfortably numb!

Cripzone | Crip's Free 2.0.2 Themes



Ken.

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:
" If everything seems under control, you're not going fast enough." - Mario Andretti
Yesterday When I was Young.

tribalost

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;
##################################################################

RoarinRow


SMF 2.0 RC3
TP 1.0 beta 5-1
Wordpress 3.0

Thurnok

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 :)

Thurnok

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)?

Zetan

I'm currently the only Admin, but if I do choose a co Admin sometime, then I will definatly be using this Thurnok.

tribalost

nope everything  workin like a charm :D... very usefull code indeed... at least no one can remove you from the root :D

RoarinRow

Thanks for the code, I made the changes manually   :up:

SMF 2.0 RC3
TP 1.0 beta 5-1
Wordpress 3.0