<?php
/*
Plugin Name: Role Manager Security Core Patch Example Plugin
Plugin URI: http://www.im-web-gefunden.de/wordpress-plugins/role-manager/
Description: Add-On to Role Manager plugin to use WP API to better control the editing of users by other users. Specifically to avoid users having the ability to change their role to administrator when they are give the edit_users privilege. 
Version: 2.2.1
Author: Jeremy Clarke
Author URI: http://www.im-web-gefunden.de/
Update Server:  http://www.im-web-gefunden.de/
Min WP Version: 2.0
Max WP Version: 2.3
License: MIT License - http://www.opensource.org/licenses/mit-license.php

*/

// ***************************************************************
// Remove any role that has a capability that the current user doesn't have.
// 
// uses the 'role_names_listing' filter which might not exist yet. Probably
// won't be around until 2.6 is released, maybe 2.5.1...
//

function check_user_editable_roles($role_names) {
	global $wp_roles;
	foreach ($wp_roles->roles as $role => $details) :
		foreach ($details['capabilities'] as $capability => $value) :
			if (!current_user_can($capability)) :
				unset ($role_names[$role]);
				break;
			endif; 
		endforeach; //capabilities
	endforeach; //foreach $wp_roles;
	return $role_names;
}
add_filter('role_names_listing', 'check_user_editable_roles');


// ***************************************************************
// Check if the logged in user should be allowed to edit another
// user. 
//
// For hooking into 'user_has_cap' filter. Use when doing a 
// check for current_user_can('edit_user', $user_id);
// Works by comparing the logged-in user to the $user_object,
// if $user_object has any capability that 
//
// $allcaps - a copy of $wp_roles->role_names , it should return with
//          innapropriate roles removed.
			
function check_user_editable($allcaps, $caps, $args) {
	// only run if we're checking the 'edit_users' cap
	// also, only if there is a second argument in $args (the second, edited, user)
	if ($caps[0] == 'edit_users' && $args[2]) :
		
		// Get full information about the user that they want to edit.
		global $user_object, $wp_roles;
		
		// Get the user object if globalizing it didn't work
		// note: that means we are on user_edit.php and not users.php
		
		if (!$user_object) $user_object = new wp_user($args[2]);

		if ($user_object->ID != $args[2]) return $allcaps;
		
		$edited_user_caps = $user_object->allcaps;
		$edited_user_roles = $user_object->roles;
		$checked_roles = array();

		// go through edited user's roles, and check for missing caps. 
		foreach ($edited_user_roles as $role => $name) :
			$rolecaps = $wp_roles->roles[$name]['capabilities'];
			foreach($rolecaps as $capability => $value) :
				if (!current_user_can($capability)) :
					unset ($allcaps['edit_users']);
					return $allcaps;
				endif; 
			endforeach; // rolecaps
			// add the role to a list of checked roles if there are no problems
			$checked_roles[] = $name;
		endforeach; // foreach edited_user_roles
		
		// This only runs if there were no conflicts while checking roles
		// go through the edited users caps and check if current user has them all
		foreach ($edited_user_caps as $capability => $value) :
			if (in_array($capability, $checked_roles)) :
				continue;
			elseif (!current_user_can($capability)) :
				unset ($allcaps['edit_users']);
				return $allcaps;
			endif; 
		endforeach; //capabilities	
	endif;// if edit_users
	 
	return $allcaps;
}

add_filter('user_has_cap', 'check_user_editable', 10, 3)


?>