You are here

session_limit.module in Session Limit 5

Established Sessions do NOT need to verify every page load. new Session must deal w/ determining which connection is cut.

File

session_limit.module
View source
<?php

/**
 * @file
 * Established Sessions do NOT need to verify every page load.
 * new Session must deal w/ determining which connection is cut.
 */

/**
 * Implementation of hook_settings().
 */
function session_limit_settings() {
  $form = array();
  $form['session_limit_max'] = array(
    '#type' => 'select',
    '#title' => t('Maximum sessions per user'),
    '#description' => t('Select the maximum # of active sessions a user can have. 0 implies unlimited sessions.'),
    '#default_value' => variable_get('session_limit_max', 1),
    '#options' => range(0, 10),
  );
  $form['session_limit_auto_drop'] = array(
    '#type' => 'checkbox',
    '#title' => t('Automatically drop the oldest session without prompting.'),
    '#default_value' => variable_get('session_limit_auto_drop', 0),
  );
  if (module_exists('masquerade')) {
    $form['session_limit_masquerade_ignore'] = array(
      '#type' => 'checkbox',
      '#title' => t('Ignore masqueraded sessions.'),
      '#description' => t("When a user administrator uses the masquerade module to impersonate a different user, it won't count against the session limit counter"),
      '#default_value' => variable_get('session_limit_masquerade_ignore', false),
    );
  }
  return system_settings_form($form);
}

/**
 * Implementation of hook_help().
 */
function session_limit_help($section) {
  switch ($section) {
    case 'session/limit':
      return t('The maximum number of simultaneous sessions (@num) for your account has been reached. You did not log off from a previous session or someone else is logged on to your account. This may indicate that your account has been compromised or that account sharing is limited on this site. Please contact the site administrator if you suspect your account has been compromised.', array(
        '@num' => variable_get('session_limit_max', 1),
      ));
  }
}

/**
 * Implementation of hook_init().
 *
 * Determine whether session has been verified.
 */
function session_limit_init() {
  global $user;
  if (variable_get('session_limit_max', 1) && $user->uid > 1 && !isset($_SESSION['session_limit'])) {

    // Exclude from the redirect.
    if (arg(0) == 'session' && arg(1) == 'limit' || arg(0) == 'logout') {
      return;
    }
    if (module_exists('masquerade') && variable_get('session_limit_masquerade_ignore', false)) {
      $result = db_query('SELECT COUNT(s.uid) FROM {sessions} AS s
        LEFT JOIN {masquerade} AS m ON s.uid = m.uid_as AND s.sid = m.sid
        WHERE s.uid = %d AND m.sid IS NULL', $user->uid);
    }
    else {
      $result = db_query('SELECT COUNT(*) FROM {sessions} WHERE uid = %d', $user->uid);
    }
    if (db_result($result) > variable_get('session_limit_max', 1)) {

      // redirect to session handler.
      drupal_goto('session/limit');
    }
    else {

      // mark session as verified to bypass this in future.
      $_SESSION['session_limit'] = TRUE;
    }
  }
}

/**
 * Implementation of hook_menu().
 * Redirect user if over session limit.
 */
function session_limit_menu($may_cache) {
  global $user;
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'session/limit',
      'title' => t('Session Limit Exceeded'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'session_limit_page',
      ),
      'access' => TRUE,
      'type' => MENU_CALLBACK,
    );
    if ($user->uid) {
      $items[] = array(
        'path' => 'mysessions',
        'title' => t('My sessions'),
        'callback' => 'drupal_get_form',
        'callback arguments' => array(
          'session_limit_page',
        ),
        'access' => TRUE,
        'type' => MENU_SUGGESTED_ITEM,
      );
    }
    $items[] = array(
      'path' => 'admin/settings/session_limit',
      'title' => t('Session Limit'),
      'description' => t('Configure session limits.'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'session_limit_settings',
      ),
    );
  }
  return $items;
}

/**
 * Display/Delete sessions..
 */
function session_limit_page() {
  global $user;
  if (!$user->uid > 0) {
    drupal_goto();
  }
  if (variable_get('session_limit_auto_drop', 0)) {

    // Get the oldest session.
    $sid = db_result(db_query_range("SELECT sid FROM {sessions} WHERE uid = %d ORDER BY timestamp", $user->uid, 0, 1));
    if ($sid) {
      _session_limit_disconnect($sid);
    }
    drupal_goto();
  }
  $result = db_query('SELECT * FROM {sessions} WHERE uid = %d', $user->uid);
  while ($obj = db_fetch_object($result)) {
    if ($user->sid == $obj->sid) {
      $message = t('Your current session.');
    }
    else {
      unset($message);
    }
    $sids[$obj->sid] = t('<strong>Host:</strong> %host (idle: %time) <b>@message</b>', array(
      '%host' => $obj->hostname,
      '@message' => $message,
      '%time' => format_interval(time() - $obj->timestamp),
    ));
  }
  $form['sid'] = array(
    '#type' => 'radios',
    '#title' => t('Select a session to disconnect'),
    '#options' => $sids,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Disconnect'),
  );
  return $form;
}

/**
 * Handler for submissions from session_limit_page().
 */
function session_limit_page_submit($form_id, $form_values) {
  global $user;
  if ($user->sid == $form_values['sid']) {

    // force a normal logout for ourself.
    drupal_set_message(t('Your session has been disconnected.'));
    drupal_goto('logout');
  }
  else {
    _session_limit_disconnect($form_values['sid']);
    drupal_set_message(t('Session has been disconnected.'));

    // redirect to main page.
    drupal_goto();
  }
}

/**
 * Logout a specific session id and leave them a message.
 */
function _session_limit_disconnect($sid) {
  $logout_message = <<<EOM
You have been automatically logged out.
Someone else has logged in with your username and password and the maximum number of @num simultaneous sessions was exceeded.
This may indicate that your account has been compromised or that account sharing is not allowed on this site.
Please contact the site administrator if you suspect your account has been compromised.
EOM;
  $logout_message = 'messages|' . serialize(array(
    'error' => array(
      t($logout_message, array(
        '@num' => variable_get('session_limit_max', 1),
      )),
    ),
  ));
  db_query("UPDATE {sessions} SET uid = 0, session = '%s' WHERE sid = '%s'", $logout_message, $sid);
}

Functions

Namesort descending Description
session_limit_help Implementation of hook_help().
session_limit_init Implementation of hook_init().
session_limit_menu Implementation of hook_menu(). Redirect user if over session limit.
session_limit_page Display/Delete sessions..
session_limit_page_submit Handler for submissions from session_limit_page().
session_limit_settings Implementation of hook_settings().
_session_limit_disconnect Logout a specific session id and leave them a message.