View source
<?php
define('PERSISTENT_LOGIN_SECURE_PATHS', "user/*/*\nuser/*/address\ncart/checkout\nadmin/settings/persistent_login\n");
define('PERSISTENT_LOGIN_MAXLIFE', 30);
function persistent_login_help($path, $arg) {
if ($path == 'admin/help#persistent_login') {
return t('Provide a "Remember Me" checkbox in the login form.');
}
}
function persistent_login_perm() {
return array(
'administer Persistent Login',
);
}
function persistent_login_boot() {
_persistent_login_check();
}
function persistent_login_init() {
global $user;
if (isset($_SESSION['persistent_login_login']) && _persistent_login_match($_GET['q'])) {
$_SESSION['persistent_login_default_user'] = $user->name;
$user = user_load(array(
'uid' => 0,
));
unset($_SESSION['persistent_login_check']);
unset($_SESSION['persistent_login_login']);
$_SESSION['persistent_login_reauth'] = TRUE;
unset($_REQUEST['destination']);
drupal_set_message(t('Please verify your username and password to access this page.'), 'error');
drupal_goto('user/login', drupal_get_destination());
}
}
function persistent_login_menu() {
$items = array();
$items['persistent_login/erase'] = array(
'title' => 'Erase persistent logins',
'page callback' => 'persistent_login_erase',
'access callback' => 'persistent_login_erase_access',
'access arguments' => array(
2,
),
'type' => MENU_CALLBACK,
'file' => 'persistent_login.pages.inc',
);
$items['admin/settings/persistent_login'] = array(
'title' => 'Persistent Login',
'description' => 'Control Persistent Login session lifetime and restricted pages.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'persistent_login_admin_settings',
),
'access arguments' => array(
'administer Persistent Login',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'persistent_login.pages.inc',
);
return $items;
}
function persistent_login_menu_alter(&$items) {
$items['user/password']['access callback'] = 'persistent_login_user_password_access';
$items['user/register']['access callback'] = 'persistent_login_user_register_access';
}
function persistent_login_erase_access($uid = NULL) {
global $user;
if ($user->uid) {
if (empty($uid)) {
$uid = $user->uid;
}
if ($user->uid == $uid || user_access('administer Persistent Login')) {
return TRUE;
}
}
return FALSE;
}
function persistent_login_form_alter(&$form, $form_state, $form_id) {
$alter_form = FALSE;
if (substr($form_id, 0, 10) == 'user_login') {
$alter_form = TRUE;
}
elseif (substr($form_id, 0, 13) == 'user_register') {
if (!variable_get('user_email_verification', 1) && variable_get('user_register', 1) == 1 && !user_access('administer users')) {
$alter_form = TRUE;
}
}
if (!$alter_form) {
return;
}
if (isset($_SESSION['persistent_login_default_user'])) {
if (isset($form['name'])) {
$form['name']['#default_value'] = $_SESSION['persistent_login_default_user'];
}
unset($_SESSION['persistent_login_default_user']);
}
if (!empty($_SESSION['persistent_login_reauth'])) {
return;
}
if (isset($form['account']) && is_array($form['account'])) {
$form['account']['persistent_login'] = array(
'#type' => 'checkbox',
'#title' => t('Remember me'),
);
}
else {
$form['persistent_login'] = array(
'#type' => 'checkbox',
'#title' => t('Remember me'),
);
}
if (!isset($form['#after_build'])) {
$form['#after_build'] = array();
}
$form['#after_build'][] = 'persistent_login_form_after_build_proxy';
}
function persistent_login_form_after_build_proxy($form, &$form_state) {
module_load_include('inc', 'persistent_login', 'persistent_login.pages');
return persistent_login_form_after_build($form, $form_state);
}
function persistent_login_user($op, &$edit, &$account, $category = NULL) {
global $user;
switch ($op) {
case 'login':
if (!empty($edit['persistent_login'])) {
_persistent_login_create_cookie($account, $edit);
}
unset($_SESSION['persistent_login_login']);
unset($_SESSION['persistent_login_reauth']);
break;
case 'logout':
$cookie_name = _persistent_login_get_cookie_name();
if (!empty($_COOKIE[$cookie_name])) {
_persistent_login_setcookie($cookie_name, '', time() - 86400);
unset($_SESSION['persistent_login_check']);
unset($_SESSION['persistent_login_login']);
unset($_SESSION['persistent_login_reauth']);
list($uid, $series, $token) = explode(':', $_COOKIE[$cookie_name]);
_persistent_login_invalidate('logout', "uid = %d AND series = '%s'", $uid, $series);
}
break;
case 'view':
if ($user->uid == $account->uid || user_access('administer Persistent Login')) {
$n = db_result(db_query('SELECT COUNT(*) FROM {persistent_login} WHERE uid = %d AND (expires = 0 OR expires > %d)', $account->uid, time()));
if ($n > 0) {
if (!isset($account->content['security'])) {
$account->content['security'] = array();
}
$account->content['security'] += array(
'#type' => 'user_profile_category',
'#title' => t('Security'),
'#weight' => 10,
);
$account->content['security']['persistent_login'] = array(
'#type' => 'user_profile_item',
'#title' => t('Remembered logins'),
'#value' => t('@acct %n persistent login session(s) created with the "Remember Me" login option on this site. If you no longer trust the computer(s) on which these remembered sessions were created or think your account has been compromised for any reason, you can !erase_link. This will not log you out of your current session but you will have to provide your username and password to log in the next time you visit this site.', array(
'@acct' => $user->uid == $account->uid ? t('You have') : t('User @user has', array(
'@user' => $account->name,
)),
'%n' => $n,
'!erase_link' => l(t('erase persistent logins now'), 'persistent_login/erase/' . $account->uid, array(), drupal_get_destination()),
)),
'#attributes' => array(
'class' => 'logins',
),
);
}
}
break;
case 'update':
if (empty($edit['pass'])) {
break;
}
case 'delete':
_persistent_login_invalidate($op, 'uid = %d', $account->uid);
unset($_SESSION['persistent_login_check']);
unset($_SESSION['persistent_login_login']);
break;
}
}
function persistent_login_cron() {
_persistent_login_invalidate('cron', 'expires > 0 AND expires < %d', time());
if (0 < ($history_days = variable_get('persistent_login_history', 0))) {
db_query('DELETE FROM {persistent_login_history} WHERE at < %d', time() - 86400 * $history_days);
}
}
function _persistent_login_check() {
global $user;
$path = isset($_GET['q']) ? $_GET['q'] : '';
$mode = variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE);
if ($mode == LANGUAGE_NEGOTIATION_PATH_DEFAULT || $mode == LANGUAGE_NEGOTIATION_PATH) {
foreach (array_keys(language_list('prefix')) as $prefix) {
if (!empty($prefix) && preg_match('`^(?:' . preg_quote($prefix) . '/){0,1}(?:user/login|logout)$`', $path)) {
return;
}
}
}
elseif ($path == 'user/login' || $path == 'logout') {
return;
}
$now = time();
$cookie_name = _persistent_login_get_cookie_name();
if ($user->uid == 0 && isset($_COOKIE[$cookie_name]) && !isset($_SESSION['persistent_login_check'])) {
$_SESSION['persistent_login_check'] = TRUE;
list($uid, $series, $token) = explode(':', $_COOKIE[$cookie_name]);
$res = db_query("SELECT u.name, pl.uid, pl.series as pl_series, pl.token as pl_token, pl.expires as pl_expires FROM {persistent_login} pl INNER JOIN {users} u USING (uid) WHERE u.status = 1 AND pl.uid = %d AND pl.series = '%s'", $uid, $series);
$r = db_fetch_array($res);
if (!is_array($r) || count($r) == 0) {
return;
}
else {
if ($r['pl_expires'] > 0 && $r['pl_expires'] < time()) {
return;
}
}
require_once './includes/common.inc';
require_once './includes/path.inc';
require_once './includes/theme.inc';
if ($r['pl_token'] === $token) {
_persistent_login_invalidate('used', "uid = %d AND series = '%s'", $uid, $series);
$r['persistent_login'] = 1;
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$account = user_load(array(
'uid' => $r['uid'],
));
if (!user_external_login($account, $r)) {
return;
}
$_SESSION['persistent_login_login'] = TRUE;
if (empty($_SESSION['persistent_login_welcomed']) && variable_get('persistent_login_welcome', TRUE)) {
drupal_set_message(t('Welcome back, %name.', array(
'%name' => $r['name'],
)));
}
$_SESSION['persistent_login_welcomed'] = TRUE;
if (empty($_POST)) {
if (!isset($_REQUEST['destination']) && drupal_is_front_page()) {
drupal_goto('');
}
else {
$_REQUEST['destination'] = substr(drupal_get_destination(), 12);
drupal_goto();
}
}
return;
}
else {
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$d = array();
_persistent_login_invalidate('stolen', 'uid = %d', $uid);
persistent_login_user('logout', $d, $user);
sess_destroy_uid($uid);
watchdog('security', 'Stolen Persistent Login session for user %user detected.', array(
'%user' => $r['name'],
), WATCHDOG_ERROR);
drupal_set_message(t('<p><b>SECURITY ALERT!</b></p><p>You previously logged in to this site and checked the <em>Remember me</em> box. At that time, this site stored a "login cookie" on your web browser that it uses to identify you each time you return. However, the login cookie that your browser just provided is incorrect. One possible cause of this error is that your web browser cookies have been stolen and used by someone else to impersonate you at this site.</p><p>As a precaution, we logged out all of your current sessions and deactivated all your remembered logins to this site. You can log in again now.</p>'), 'error');
drupal_goto();
return;
}
}
}
function _persistent_login_create_cookie($acct, $edit = array()) {
$cookie_name = _persistent_login_get_cookie_name();
if (isset($_COOKIE[$cookie_name]) && !isset($edit['pl_series'])) {
list($uid, $series, $token) = explode(':', $_COOKIE[$cookie_name]);
_persistent_login_invalidate('cleanup', "uid = %d AND series = '%s'", $uid, $series);
}
$token = drupal_get_token(uniqid(mt_rand(), TRUE));
$days = variable_get('persistent_login_maxlife', PERSISTENT_LOGIN_MAXLIFE);
$expires = isset($edit['pl_expires']) ? $edit['pl_expires'] : ($days > 0 ? time() + $days * 86400 : 0);
$series = isset($edit['pl_series']) ? $edit['pl_series'] : drupal_get_token(uniqid(mt_rand(), TRUE));
_persistent_login_setcookie($cookie_name, $acct->uid . ':' . $series . ':' . $token, $expires > 0 ? $expires : 2147483647);
db_query("INSERT INTO {persistent_login} (uid, series, token, expires) VALUES (%d, '%s', '%s', %d)", $acct->uid, $series, $token, $expires);
if (db_affected_rows() != 1) {
watchdog('security', 'Persistent Login FAILURE: could not insert (%user, %series, %tok, %expires)', array(
'%user' => $acct->name,
'%series' => $series,
'%tok' => $token,
'%expires' => $expires,
), WATCHDOG_ERROR);
}
else {
$maxlogins = variable_get('persistent_login_maxlogins', 10);
$expires = (int) db_result(db_query_range('SELECT expires FROM {persistent_login} WHERE uid = %d ORDER BY expires DESC', $acct->uid, $maxlogins, 1));
if ($expires > 0) {
_persistent_login_invalidate('too many', 'uid = %d AND expires <= %d', $acct->uid, $expires);
}
}
}
function _persistent_login_setcookie($name, $value, $expire = 0) {
$params = session_get_cookie_params();
setcookie($name, $value, $expire, $params['path'], $params['domain'], $params['secure']);
}
function _persistent_login_get_cookie_name() {
static $cookie_name;
if (!isset($cookie_name)) {
$cookie_name = variable_get('persistent_login_cookie_prefix', 'PERSISTENT_LOGIN_') . substr(session_name(), 4);
}
return $cookie_name;
}
function _persistent_login_match($path) {
$secure = variable_get('persistent_login_secure', 1);
$pages = trim(variable_get('persistent_login_pages', PERSISTENT_LOGIN_SECURE_PATHS));
if ($pages) {
$front = variable_get('site_frontpage', 'node');
$regexp = '/^(?:' . preg_replace(array(
'/(\\r\\n?|\\n)/',
'/\\\\\\*/',
'/(^|\\|)\\\\<front\\\\>($|\\|)/',
), array(
'|',
'.*',
'\\1' . preg_quote($front, '/') . '\\2',
), preg_quote($pages, '/')) . ')$/';
return !($secure xor preg_match($regexp, $path));
}
else {
return 0;
}
}
function _persistent_login_invalidate($why, $where) {
$vals = func_get_args();
array_shift($vals);
array_shift($vals);
if (variable_get('persistent_login_history', 0)) {
$vals2 = $vals;
array_unshift($vals2, time(), $why);
db_query("INSERT INTO {persistent_login_history} (uid, series, token, expires, at, why) SELECT uid, series, token, expires, %d, '%s' FROM {persistent_login} WHERE " . $where, $vals2);
}
db_query('DELETE FROM {persistent_login} WHERE ' . $where, $vals);
}
function _persistent_login_get_config_warning_msg() {
return t('Your site\'s <em>session.cookie_lifetime</em> PHP setting is %life. When using Persistent Login, it should be 0 so that PHP sessions end when the user closes his/her browser. You can change this setting by editing <strong>%file</strong>.', array(
'%life' => ini_get('session.cookie_lifetime'),
'%file' => conf_path() . '/settings.php',
));
}
function persistent_login_user_register_access() {
return user_register_access() && empty($_SESSION['persistent_login_reauth']);
}
function persistent_login_user_password_access() {
return user_is_anonymous() && empty($_SESSION['persistent_login_reauth']);
}