Skip to content

Commit

Permalink
Disallow deleting or disabling last admin
Browse files Browse the repository at this point in the history
- When checking for remaining admins, exclude disabled ones.
- Don't worry about changes to already disabled users.
- Complain when disabling last administrator, not just reducing their
  access level.

Fixes #20381
Fixes #20382
  • Loading branch information
vboctor committed Dec 15, 2015
1 parent 27bfe82 commit a3f9d03
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 15 deletions.
26 changes: 16 additions & 10 deletions core/user_api.php
Expand Up @@ -375,18 +375,17 @@ function user_is_monitoring_bug( $p_user_id, $p_bug_id ) {
}

/**
* return true if the user has access of ADMINISTRATOR or higher, false otherwise
* Check if the specified user is an enabled user with admin access level or above.
* @param integer $p_user_id A valid user identifier.
* @return boolean
* @return boolean true: admin, false: otherwise.
*/
function user_is_administrator( $p_user_id ) {
$t_access_level = user_get_field( $p_user_id, 'access_level' );

if( $t_access_level >= config_get_global( 'admin_site_threshold' ) ) {
return true;
} else {
if( !user_is_enabled( $p_user_id ) ) {
return false;
}

$t_access_level = user_get_field( $p_user_id, 'access_level' );
return $t_access_level >= config_get_global( 'admin_site_threshold' );
}

/**
Expand Down Expand Up @@ -449,13 +448,20 @@ function user_is_enabled( $p_user_id ) {
}

/**
* count the number of users at or greater than a specific level
* Count the number of users at or greater than a specific level
*
* @param integer $p_level Access Level to count users. The default is to include ANYBODY.
* @return integer
* @param bool $p_enabled true: must be enabled, false: must be disabled, null: don't care.
* @return integer The number of users.
*/
function user_count_level( $p_level = ANYBODY ) {
function user_count_level( $p_level = ANYBODY, $p_enabled = null ) {
$t_query = 'SELECT COUNT(id) FROM {user} WHERE access_level>=' . db_param();
if( $p_enabled === true ) {
$t_query .= ' AND enabled = 1';
} else if( $p_enabled === false ) {
$t_query .= ' AND enabled = 0';
}

$t_result = db_query( $t_query, array( $p_level ) );

# Get the list of connected users
Expand Down
4 changes: 2 additions & 2 deletions manage_user_delete.php
Expand Up @@ -62,10 +62,10 @@
# current user.
access_ensure_global_level( $t_user['access_level'] );

# check that we are not deleting the last administrator account
# Check that we are not deleting the last administrator account
$t_admin_threshold = config_get_global( 'admin_site_threshold' );
if( user_is_administrator( $f_user_id ) &&
user_count_level( $t_admin_threshold ) <= 1 ) {
user_count_level( $t_admin_threshold, /* enabled */ true ) <= 1 ) {
trigger_error( ERROR_USER_CHANGE_LAST_ADMIN, ERROR );
}

Expand Down
7 changes: 4 additions & 3 deletions manage_user_update.php
Expand Up @@ -139,9 +139,10 @@
# check that we are not downgrading the last administrator
$t_admin_threshold = config_get_global( 'admin_site_threshold' );
if( user_is_administrator( $f_user_id ) &&
$f_access_level < $t_admin_threshold &&
user_count_level( $t_admin_threshold ) <= 1 ) {
trigger_error( ERROR_USER_CHANGE_LAST_ADMIN, ERROR );
user_count_level( $t_admin_threshold, /* enabled */ true ) <= 1 ) {
if( $f_access_level < $t_admin_threshold || $c_enabled === false ) {
trigger_error( ERROR_USER_CHANGE_LAST_ADMIN, ERROR );
}
}

# Project specific access rights override global levels, hence, for users who are changed
Expand Down

0 comments on commit a3f9d03

Please sign in to comment.