189 lines
5.9 KiB
PHP
189 lines
5.9 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Main class of User Role Editor WordPress plugin
|
|
* Author: Vladimir Garagulya
|
|
* Author email: support@role-editor.com
|
|
* Author URI: https://www.role-editor.com
|
|
* License: GPL v2+
|
|
*
|
|
*/
|
|
|
|
class URE_Protect_Admin {
|
|
|
|
private $lib = null;
|
|
private $user_to_check = null; // cached list of user IDs, who has Administrator role
|
|
|
|
public function __construct($lib) {
|
|
$this->lib = $lib;
|
|
$this->user_to_check = array();
|
|
|
|
// Exclude administrator role from edit list.
|
|
add_filter('editable_roles', array($this, 'exclude_admin_role'));
|
|
// prohibit any actions with user who has Administrator role
|
|
add_filter('user_has_cap', array($this, 'not_edit_admin'), 10, 3);
|
|
// exclude users with 'Administrator' role from users list
|
|
add_action('pre_user_query', array($this, 'exclude_administrators'));
|
|
// do not show 'Administrator (s)' view above users list
|
|
add_filter('views_users', array($this, 'exclude_admins_view'));
|
|
}
|
|
// end of __construct()
|
|
|
|
|
|
// apply protection to the user edit pages only
|
|
protected function is_protection_applicable() {
|
|
$result = false;
|
|
$links_to_block = array('profile.php', 'users.php', 'user-new.php');
|
|
foreach ($links_to_block as $key => $value) {
|
|
$result = stripos($_SERVER['REQUEST_URI'], $value);
|
|
if ($result !== false) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
// end of is_protection_applicable()
|
|
|
|
|
|
/**
|
|
* exclude administrator role from the roles list
|
|
*
|
|
* @param string $roles
|
|
* @return array
|
|
*/
|
|
public function exclude_admin_role($roles) {
|
|
|
|
if ($this->is_protection_applicable() && isset($roles['administrator'])) {
|
|
unset($roles['administrator']);
|
|
}
|
|
|
|
return $roles;
|
|
}
|
|
// end of exclude_admin_role()
|
|
|
|
|
|
/**
|
|
* Check if user has "Administrator" role assigned
|
|
*
|
|
* @global wpdb $wpdb
|
|
* @param int $user_id
|
|
* @return boolean returns true is user has Role "Administrator"
|
|
*/
|
|
private function has_administrator_role($user_id) {
|
|
global $wpdb;
|
|
|
|
if (empty($user_id) || !is_numeric($user_id)) {
|
|
return false;
|
|
}
|
|
|
|
$table_name = $this->lib->get_usermeta_table_name();
|
|
$meta_key = $wpdb->prefix . 'capabilities';
|
|
$query = "SELECT count(*)
|
|
FROM $table_name
|
|
WHERE user_id=$user_id AND meta_key='$meta_key' AND meta_value like '%administrator%'";
|
|
$has_admin_role = $wpdb->get_var($query);
|
|
if ($has_admin_role > 0) {
|
|
$result = true;
|
|
} else {
|
|
$result = false;
|
|
}
|
|
// cache checking result for the future use
|
|
$this->user_to_check[$user_id] = $result;
|
|
|
|
return $result;
|
|
}
|
|
|
|
// end of has_administrator_role()
|
|
|
|
|
|
/**
|
|
* We have two vulnerable queries with user id at admin interface, which should be processed
|
|
* 1st: http://blogdomain.com/wp-admin/user-edit.php?user_id=ID&wp_http_referer=%2Fwp-admin%2Fusers.php
|
|
* 2nd: http://blogdomain.com/wp-admin/users.php?action=delete&user=ID&_wpnonce=ab34225a78
|
|
* If put Administrator user ID into such request, user with lower capabilities (if he has 'edit_users')
|
|
* can edit, delete admin record
|
|
* This function removes 'edit_users' capability from current user capabilities
|
|
* if request has admin user ID in it
|
|
*
|
|
* @param array $allcaps
|
|
* @param type $caps
|
|
* @param string $name
|
|
* @return array
|
|
*/
|
|
public function not_edit_admin($allcaps, $caps, $name) {
|
|
|
|
$user_keys = array('user_id', 'user');
|
|
foreach ($user_keys as $user_key) {
|
|
$access_deny = false;
|
|
$user_id = $this->lib->get_request_var($user_key, 'get');
|
|
if (empty($user_id)) {
|
|
break;
|
|
}
|
|
if ($user_id == 1) { // built-in WordPress Admin
|
|
$access_deny = true;
|
|
} else {
|
|
if (!isset($this->user_to_check[$user_id])) {
|
|
// check if user_id has Administrator role
|
|
$access_deny = $this->has_administrator_role($user_id);
|
|
} else {
|
|
// user_id was checked already, get result from cash
|
|
$access_deny = $this->user_to_check[$user_id];
|
|
}
|
|
}
|
|
if ($access_deny) {
|
|
unset($allcaps['edit_users']);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return $allcaps;
|
|
}
|
|
// end of not_edit_admin()
|
|
|
|
|
|
/**
|
|
* add where criteria to exclude users with 'Administrator' role from users list
|
|
*
|
|
* @global wpdb $wpdb
|
|
* @param type $user_query
|
|
*/
|
|
public function exclude_administrators($user_query) {
|
|
|
|
global $wpdb;
|
|
|
|
if (!$this->is_protection_applicable()) { // block the user edit stuff only
|
|
return;
|
|
}
|
|
|
|
// get user_id of users with 'Administrator' role
|
|
$tableName = $this->lib->get_usermeta_table_name();
|
|
$meta_key = $wpdb->prefix . 'capabilities';
|
|
$admin_role_key = '%"administrator"%';
|
|
$query = "select user_id
|
|
from $tableName
|
|
where meta_key='$meta_key' and meta_value like '$admin_role_key'";
|
|
$ids_arr = $wpdb->get_col($query);
|
|
if (is_array($ids_arr) && count($ids_arr) > 0) {
|
|
$ids = implode(',', $ids_arr);
|
|
$user_query->query_where .= " AND ( $wpdb->users.ID NOT IN ( $ids ) )";
|
|
}
|
|
}
|
|
// end of exclude_administrators()
|
|
|
|
|
|
/*
|
|
* Exclude view of users with Administrator role
|
|
*
|
|
*/
|
|
public function exclude_admins_view($views) {
|
|
|
|
unset($views['administrator']);
|
|
|
|
return $views;
|
|
}
|
|
// end of exclude_admins_view()
|
|
|
|
}
|
|
// end of URE_Protect_Admin class
|