diff --git a/sites/all/modules/masquerade/masquerade.module b/sites/all/modules/masquerade/masquerade.module index 252b4bd..1a05409 100644 --- a/sites/all/modules/masquerade/masquerade.module +++ b/sites/all/modules/masquerade/masquerade.module @@ -23,15 +23,21 @@ function masquerade_help($path, $arg) { * @return array */ function masquerade_permission() { - return array( - 'masquerade as user' => array( - 'title' => t('Masquerade as user'), - 'description' => t('Masquerade as another user.'), - ), - 'masquerade as admin' => array( - 'title' => t('Masquerade as admin'), - 'description' => t('Masquerade as the site admin (UID 1).'), - ), + $roles = array(); + // Load and build permissions for all roles in our site + foreach (user_roles() as $rid => $role) { + $title = 'masquerade as '. $role; + $description = t('Masquerade as a member of the @role role.', array('@role' => $role)); + if ($rid == DRUPAL_AUTHENTICATED_RID) { + $description = t('Grant this permission with caution. Any user signed in is given this role.'); + } + $roles[$title] = array( + 'title' => t($title), + 'description' => $description, + ); + } + + return $roles + array( 'administer masquerade' => array( 'title' => t('Administer Masquerade'), 'description' => t('Perform administration tasks and configure the Masquerade module.'), @@ -188,7 +194,7 @@ function masquerade_translated_menu_link_alter(&$item, $map) { function masquerade_user_operations() { return array( 'masquerade' => array( - 'label' => t('Masquerade as user'), + 'label' => t('Masquerade as this user'), 'callback' => 'masquerade_user_operations_masquerade', ), ); @@ -223,7 +229,7 @@ function masquerade_menu_access($type, $uid = NULL) { case 'unswitch': return isset($_SESSION['masquerading']) || arg(2) == 'menu-customize' || arg(2) == 'menu'; case 'autocomplete': - return isset($_SESSION['masquerading']) || (user_access('masquerade as user') || user_access('masquerade as admin')); + return isset($_SESSION['masquerading']) || masquerade_has_any_masquerade_permission(); break; case 'user': global $user; @@ -232,18 +238,20 @@ function masquerade_menu_access($type, $uid = NULL) { case 'switch': $switch_to_account = FALSE; global $user; - if ($uid) { - if (!is_numeric($uid)) { + if (!is_numeric($uid)) { + return FALSE; + } + if ($account = user_load($uid)) { + $switch_to_account = db_query("SELECT 1 FROM {masquerade_users} WHERE uid_from = :uid_from AND uid_to = :uid_to", array( + ':uid_from' => $user->uid, + ':uid_to' => $account->uid + ))->fetchField(); + // Ensure the user we want to switch to has only roles we're permitted to access. + if (!masquerade_check_user_roles($account)) { return FALSE; } - if ($account = user_load($uid)) { - $switch_to_account = db_query("SELECT 1 FROM {masquerade_users} WHERE uid_from = :uid_from AND uid_to = :uid_to", array( - ':uid_from' => $user->uid, - ':uid_to' => $account->uid - ))->fetchField(); - } } - return !isset($_SESSION['masquerading']) && (user_access('masquerade as user') || user_access('masquerade as admin') || $switch_to_account); + return !isset($_SESSION['masquerading']) || $switch_to_account; break; } } @@ -252,26 +260,6 @@ function masquerade_menu_access($type, $uid = NULL) { * Admin settings form. */ function masquerade_admin_settings() { - // create a list of roles; all selected roles are considered administrative. - $roles = user_roles(); - $form['masquerade_admin_roles'] = array( - '#type' => 'checkboxes', - '#title' => t('Roles that are considered "administrators" for masquerading'), - '#options' => $roles, - '#default_value' => variable_get('masquerade_admin_roles', array()), - ); - - $test_name = _masquerade_user_load(variable_get('masquerade_test_user', '')); - - $form['masquerade_test_user'] = array( - '#type' => 'textfield', - '#title' => t('Menu Quick Switch user'), - '#autocomplete_path' => 'masquerade/autocomplete', - '#default_value' => isset($test_name->name) ? check_plain($test_name->name) : '', - '#description' => t('Enter the username of an account you wish to switch easily between via a menu item.'), - '#maxlength' => NULL, - ); - $quick_switch = user_load_multiple(variable_get('masquerade_quick_switches', array())); $quick_switch_users = array(); foreach ($quick_switch as $uid => $account) { @@ -297,15 +285,6 @@ function masquerade_admin_settings() { } function masquerade_admin_settings_validate($form, &$form_state) { - if (!empty($form_state['values']['masquerade_test_user'])) { - $test_user = _masquerade_user_load($form_state['values']['masquerade_test_user']); - if (!$test_user) { - form_set_error('masquerade_test_user', t('%user does not exist. Please enter a valid username.', array('%user' => $form_state['values']['masquerade_test_user']))); - } - } - // Needs to rebuild menu in masquerade_admin_settings_submit(). - $form_state['masquerade_rebuild_menu'] = (variable_get('masquerade_test_user', '') != $form_state['values']['masquerade_test_user']); - // A comma-separated list of users. $masquerade_switches = drupal_explode_tags($form_state['values']['masquerade_quick_switches']); // Change user names to user ID's for system_settings_form_submit() to save. @@ -374,15 +353,17 @@ function masquerade_user_logout($account) { * Implements hook_user_view(). */ function masquerade_user_view($account, $view_mode, $langcode) { - // check if user qualifies as admin - $roles = array_keys(array_filter(variable_get('masquerade_admin_roles', array()))); - $perm = $account->uid == 1 || array_intersect(array_keys((array)$account->roles), $roles) ? - 'masquerade as admin' : - 'masquerade as user'; - global $user; + // Make sure the account viewed isn't our own and that we have adequate + // permissions to masquerade as it + if ($user->uid == $account->uid || !masquerade_check_user_roles($account)) { + return; + } - if (user_access($perm) && empty($account->masquerading) && $user->uid != $account->uid) { + // Ensure we have access to: the user page, that we are not presently masquerading, + // that the current account isn't our own, and that the user we're looking at + // only has roles we can become. + if (empty($account->masquerading)) { $account->content['masquerade'] = array( '#markup' => l(t('Masquerade as !user', array('!user' => $account->name)), 'masquerade/switch/' . $account->uid, @@ -444,6 +425,9 @@ function masquerade_user_validate(&$form, $form_state) { if (!_masquerade_user_load($username)) { form_set_error('masquerade_users', t('%user is not a valid user name.', array('%user' => $username))); } + if (!masquerade_check_user_roles($username)) { + form_set_error('masquerade_users', t('This account has been assigned roles you are not permitted to access.')); + } } } } @@ -532,7 +516,7 @@ function masquerade_block_view($delta = '') { $block = array(); switch ($delta) { case 'masquerade': - if (isset($_SESSION['masquerading']) || (user_access('masquerade as user') || user_access('masquerade as admin'))) { + if (isset($_SESSION['masquerading']) || masquerade_has_any_masquerade_permission()) { $block['subject'] = t('Masquerade'); $block['content'] = drupal_get_form('masquerade_block_1'); } @@ -568,6 +552,10 @@ function masquerade_block_1() { if (!isset($_SESSION['user']->uid) || $switch_user != $_SESSION['user']->uid) { $account = user_load($switch_user); if (isset($account->uid)) { + // Make sure the users in the quick switch list only have roles we're allowed to become. + if (!masquerade_check_user_roles($account)) { + continue; + } $switch_link = 'masquerade/switch/' . $account->uid; if ($account->uid) { $quick_switch_links[] = l($account->name, $switch_link, array('query' => array('token' => drupal_get_token($switch_link)))); @@ -631,6 +619,9 @@ function masquerade_block_1_validate($form, &$form_state) { if (!$masq_user) { form_set_error('masquerade_user_field', t('User %masq_as does not exist. Please enter a valid username.', array('%masq_as' => $form_state['values']['masquerade_user_field']))); } + elseif (!masquerade_check_user_roles($masq_user)) { + form_set_error('masquerade_user_field', t('You cannot masquerade as %masq_as because this person has roles you are not permitted to switch to.', array('%masq_as' => $form_state['values']['masquerade_user_field']))); + } elseif ($masq_user->uid == $user->uid) { form_set_error('masquerade_user_field', t('You cannot masquerade as yourself. Please choose a different user to masquerade as.')); } @@ -660,18 +651,35 @@ function masquerade_block_1_submit($form, &$form_state) { * Returns JS array for Masquerade autocomplete fields. */ function masquerade_autocomplete($string) { + global $user; + $matches = array(); // Anonymous user goes first to be visible for user. $anonymous = variable_get('anonymous', t('Anonymous')); if (stripos($anonymous, $string) === 0) { - $matches[$anonymous] = $anonymous; + if (masquerade_check_role_permission('anonymous user')) { + $matches[$anonymous] = $anonymous; + } } + // Other suggestions. - $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER(:string)", 0, 10, array( - ':string' => $string . '%', - )); - foreach ($result as $user) { - $matches[$user->name] = check_plain($user->name); + if (masquerade_check_role_permission('authenticated user')) { + $rids = masquerade_get_not_allowed_roles(); + $subquery = db_select('users_roles', 'ur'); + $subquery->addField('ur','uid','uid'); + $subquery->condition('rid', $rids); + + $query = db_select('users', 'u') + ->fields('u', array('name')) + ->condition('name', db_like($string) . '%', 'LIKE') + ->condition('uid', $user->uid, '!=') + ->condition('uid', $subquery, 'NOT IN') + ->orderBy('name', 'ASC') + ->range(0, 10); + + foreach ($query->execute() as $found_user) { + $matches[$found_user->name] = check_plain($found_user->name); + } } if (module_exists('devel')) { $GLOBALS['devel_shutdown'] = FALSE; @@ -690,6 +698,8 @@ function masquerade_autocomplete($string) { * Flag to include Anonymous user into result. */ function masquerade_autocomplete_multiple($string, $add_anonymous = TRUE) { + global $user; + $matches = array(); // The user enters a comma-separated list of users. We only autocomplete the last user. $users_typed = drupal_explode_tags($string); @@ -701,27 +711,41 @@ function masquerade_autocomplete_multiple($string, $add_anonymous = TRUE) { // Anonymous user goes first to be visible for user. $anonymous = variable_get('anonymous', t('Anonymous')); if (stripos($anonymous, $last_string) === 0) { - $matches[$prefix . $anonymous] = $anonymous; + if (masquerade_check_role_permission('anonymous user')) { + $matches[$prefix . $anonymous] = $anonymous; + } } } // Other suggestions. - $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE :string", 0, 10, array( - ':string' => $last_string . '%', - )); - foreach ($result as $user) { - $matches[$prefix . $user->name] = check_plain($user->name); - } + if (masquerade_check_role_permission('authenticated user')) { + $rids = masquerade_get_not_allowed_roles(); + $subquery = db_select('users_roles', 'ur'); + $subquery->addField('ur','uid','uid'); + $subquery->condition('rid', $rids); + + $query = db_select('users', 'u') + ->fields('u', array('name')) + ->condition('name', db_like($string) . '%', 'LIKE') + ->condition('uid', $user->uid, '!=') + ->condition('uid', $subquery, 'NOT IN') + ->orderBy('name', 'ASC') + ->range(0, 10); + + foreach ($query->execute() as $found_user) { + $matches[$prefix . $found_user->name] = check_plain($found_user->name); + } - // Remove existing tags. - $matches = array_diff($matches, $users_typed); + // Remove existing tags. + $matches = array_diff($matches, $users_typed); - // @todo Check compatibility for D7. - if (module_exists('alt_login')) { - $result = db_query_range("SELECT u.alt_login AS alt_login FROM {alt_login} u WHERE LOWER(u.alt_login) LIKE LOWER(:string)", 0, 10, array( - ':string' => $last_string . '%', - )); - foreach ($result as $user) { - $matches[$user->alt_login] = check_plain($user->alt_login); + // @todo Check compatibility for D7. + if (module_exists('alt_login')) { + $result = db_query_range("SELECT u.alt_login AS alt_login FROM {alt_login} u WHERE LOWER(u.alt_login) LIKE LOWER(:string)", 0, 10, array( + ':string' => $last_string . '%', + )); + foreach ($result as $user) { + $matches[$user->alt_login] = check_plain($user->alt_login); + } } } } @@ -762,23 +786,15 @@ function masquerade_switch_user($uid) { $new_user = user_load($uid); - $roles = array_keys(array_filter(variable_get('masquerade_admin_roles', array()))); - $perm = $uid == 1 || array_intersect(array_keys($new_user->roles), $roles) ? - 'masquerade as admin' : - 'masquerade as user'; - - // Check to see if we need admin permission. - $results = db_query_range('SELECT 1 FROM {masquerade_users} WHERE uid_from = :uid_from AND uid_to = :uid_to', 0, 1, array( - ':uid_from' => $user->uid, - ':uid_to' => $new_user->uid, - )); - if (!user_access($perm) && !isset($_SESSION['masquerading']) && !$results->fetchField()) { - watchdog('masquerade', 'This user requires administrative permissions to switch to the user %user.', array('%user' => $new_user->name), WATCHDOG_ERROR); + if ($user->uid == $uid || isset($user->masquerading)) { + watchdog('masquerade', 'This user is already %user.', array('%user' => $new_user->name), WATCHDOG_ERROR); return FALSE; } - if ($user->uid == $uid || isset($user->masquerading)) { - watchdog('masquerade', 'This user is already %user.', array('%user' => $new_user->name), WATCHDOG_ERROR); + // Ensure the account we're switching to isn't our own and that we have + // permission to masquerade with these roles + if ($user->uid !== $new_user->uid && !masquerade_check_user_roles($new_user)) { + watchdog('masquerade', 'The user %user has roles %user2 does not have permission to obtain.', array('%user' => $new_user->name, '%user2' => $user->name), WATCHDOG_ERROR); return FALSE; } @@ -798,7 +814,6 @@ function masquerade_switch_user($uid) { 'sid' => session_id(), )); $query->execute(); - // switch user watchdog('masquerade', 'User %user now masquerading as %masq_as.', array('%user' => $user->name, '%masq_as' => $new_user->name ? $new_user->name : variable_get('anonymous', t('Anonymous'))), WATCHDOG_INFO); drupal_set_message(t('You are now masquerading as !masq_as.', array('!masq_as' => theme('username', array('account' => $new_user))))); @@ -859,3 +874,88 @@ function masquerade_switch_back() { watchdog('masquerade', 'User %user no longer masquerading as %masq_as.', array('%user' => $user->name, '%masq_as' => $oldname), WATCHDOG_INFO); } + +/** + * Checks if the user has access to masquerade as a specific role. + * @param string $role + * The name of the role to check. Also accepts a machine name of the + * permission. + * @return bool + * Whether or not the current user is allowed to masquerade as someone with this role. + */ +function masquerade_check_role_permission($role) { + $permission = stripos($role, 'masquerade as') ? $role : 'masquerade as ' . $role; + return user_access($permission); +} + +/** + * Checks an array of roles to see if we have access to them. + * + * @param $roles + * An array of roles to check + * @return bool + * Return FALSE if any role exists that the current user isn't permitted to become. + * Return TRUE otherwise. + */ +function masquerade_check_roles($roles = array()) { + foreach ($roles as $role) { + if (!masquerade_check_role_permission($role)) { + return FALSE; + } + } + return TRUE; +} + +/** + * Checks all roles of the user we're trying to become. + * + * @param mixed + * The user object to check roles. Also accepts uids and user names. + * @return bool + * Return FALSE if any role exists that the current user isn't permitted to become. + * Return TRUE otherwise. + */ +function masquerade_check_user_roles($user) { + if (is_numeric($user)) { + $user = user_load($user); + } + elseif (is_string($user)) { + $user = user_load_by_name($user); + } + elseif (!is_object($user) || !isset($user->roles)) { + return FALSE; + } + return masquerade_check_roles($user->roles); +} + +/** + * Check if the current user has ANY masquerade permission. + * + * @return bool + * Return TRUE if user has access to masquerade at all. + * Return FALSE if user can't masquerade. + */ +function masquerade_has_any_masquerade_permission() { + $return = FALSE; + foreach(user_roles() as $rid => $role) { + if (masquerade_check_role_permission($role)) { + $return = TRUE; + } + } + return $return; +} + +/** + * Get roles the current user is allowed to masquerade to. + * + * @return void + **/ +function masquerade_get_not_allowed_roles() { + $rids = array(); + foreach (user_roles() as $rid => $role) { + if (!masquerade_check_role_permission($role)) { + $rids[$rid] = $rid; + } + } + return $rids; +} \ No newline at end of file