diff --git a/public_html/admin/auth.inc.php b/public_html/admin/auth.inc.php index 424773037..3ac6bf334 100644 --- a/public_html/admin/auth.inc.php +++ b/public_html/admin/auth.inc.php @@ -8,7 +8,7 @@ // | | // | Geeklog admin authentication module | // +---------------------------------------------------------------------------+ -// | Copyright (C) 2000-2010 by the following authors: | +// | Copyright (C) 2000-2019 by the following authors: | // | | // | Authors: Tony Bibbs - tony AT tonybibbs DOT com | // | Mark Limburg - mlimburg AT users DOT sourceforge DOT net | @@ -36,6 +36,8 @@ die('This file can not be used on its own.'); } +global $_TABLES; + // MAIN COM_clearSpeedlimit($_CONF['login_speedlimit'], 'login'); if (COM_checkSpeedlimit('login', $_CONF['login_attempts']) > 0) { @@ -65,22 +67,15 @@ if ($status == USER_ACCOUNT_ACTIVE) { DB_query("UPDATE {$_TABLES['users']} SET pwrequestid = NULL WHERE uid = $uid"); $_USER = SESS_getUserDataFromId($uid); - $sessid = SESS_newSession($_USER['uid'], $_SERVER['REMOTE_ADDR'], - $_CONF['session_cookie_timeout'], $_CONF['cookie_ip']); - SESS_setSessionCookie($sessid, $_CONF['session_cookie_timeout'], - $_CONF['cookie_session'], $_CONF['cookie_path'], - $_CONF['cookiedomain'], $_CONF['cookiesecure']); + SESS_newSession($_USER['uid'], $_SERVER['REMOTE_ADDR'], $_CONF['session_cookie_timeout']); PLG_loginUser($_USER['uid']); - // Now that we handled session cookies, handle longterm cookie - if (!isset($_COOKIE[$_CONF['cookie_name']])) { - // Either their cookie expired or they are new - $cooktime = COM_getUserCookieTimeout(); - - if (!empty($cooktime)) { - // They want their cookie to persist for some amount of time so set it now - SEC_setCookie($_CONF['cookie_name'], $_USER['uid'], time() + $cooktime); - } + // Now that we handled session cookies, handle long-term cookie + $cookieTime = COM_getUserCookieTimeout(); + if (!empty($cookieTime) && ($cookieTime > 0)) { + SESS_handleAutoLogin($cookieTime); + } else { + SESS_deleteAutoLoginKey(); } if (!SEC_hasRights('story.edit,block.edit,topic.edit,user.edit,plugin.edit,syndication.edit,theme.edit','OR')) { diff --git a/public_html/admin/install/classes/installer.class.php b/public_html/admin/install/classes/installer.class.php index da2240ab9..6e9fc54bc 100644 --- a/public_html/admin/install/classes/installer.class.php +++ b/public_html/admin/install/classes/installer.class.php @@ -4586,7 +4586,7 @@ private function installEngine($installType, $installStep) '1.3.5', '1.3.6', '1.3.7', '1.3.8', '1.3.9', '1.3.10', '1.3.11', '1.4.0', '1.4.1', '1.5.0', '1.5.1', '1.5.2', '1.6.0', '1.6.1', '1.7.0', '1.7.1', '1.7.2', '1.8.0', '1.8.1', '1.8.2', '2.0.0', - '2.1.0', '2.1.1', + '2.1.0', '2.1.1', '2.2.0', ); $tempCounter = 0; diff --git a/public_html/admin/install/classes/micro_template.class.php b/public_html/admin/install/classes/micro_template.class.php index 259a7885b..e461339f1 100644 --- a/public_html/admin/install/classes/micro_template.class.php +++ b/public_html/admin/install/classes/micro_template.class.php @@ -93,8 +93,6 @@ private function parseVarName($s) /** * Evaluate the content of a template - * - * @return string */ private function evaluate() { diff --git a/public_html/admin/install/config-install.php b/public_html/admin/install/config-install.php index 1120bd836..148c2f447 100644 --- a/public_html/admin/install/config-install.php +++ b/public_html/admin/install/config-install.php @@ -414,12 +414,10 @@ function install_config() $c->add('fs_cookies', NULL, 'fieldset', 7, 30, NULL, 0, TRUE, $me, 30); $c->add('cookie_session','gl_session','text',7,30,NULL,530,TRUE, $me, 30); $c->add('cookie_name','geeklog','text',7,30,NULL,540,TRUE, $me, 30); - $c->add('cookie_password','password','text',7,30,NULL,550,TRUE, $me, 30); $c->add('cookie_theme','theme','text',7,30,NULL,560,TRUE, $me, 30); $c->add('cookie_language','language','text',7,30,NULL,570,TRUE, $me, 30); $c->add('cookie_tzid','timezone','text',7,30,NULL,575,TRUE, $me, 30); $c->add('cookie_anon_name','anon_name','text',7,30,NULL,577,TRUE, $me, 30); - $c->add('cookie_ip',0,'select',7,30,0,580,TRUE, $me, 30); $c->add('default_perm_cookie_timeout',28800,'select',7,30,NULL,590,TRUE, $me, 30); $c->add('session_cookie_timeout',7200,'text',7,30,NULL,600,TRUE, $me, 30); $c->add('cookie_path','/','text',7,30,NULL,610,TRUE, $me, 30); diff --git a/public_html/users.php b/public_html/users.php index 4cdb9dc45..d57073c4f 100644 --- a/public_html/users.php +++ b/public_html/users.php @@ -40,6 +40,8 @@ * @author Jason Whittenburg */ +use Geeklog\Session; + /** * Geeklog common function library */ @@ -656,50 +658,13 @@ function USER_doLogin() global $_CONF, $_USER, $USER_VERBOSE; COM_resetSpeedlimit('login'); - $sessionId = SESS_newSession($_USER['uid'], $_SERVER['REMOTE_ADDR'], $_CONF['session_cookie_timeout'], $_CONF['cookie_ip']); - SESS_setSessionCookie( - $sessionId, $_CONF['session_cookie_timeout'], $_CONF['cookie_session'], $_CONF['cookie_path'], - $_CONF['cookiedomain'], $_CONF['cookiesecure'] - ); + SESS_newSession($_USER['uid'], $_SERVER['REMOTE_ADDR'], $_CONF['session_cookie_timeout']); PLG_loginUser($_USER['uid']); - // Now that we handled session cookies, handle long-term cookie - if (!isset($_COOKIE[$_CONF['cookie_name']]) || !isset($_COOKIE['cookie_password'])) { - // Either their cookie expired or they are new - $cookTime = COM_getUserCookieTimeout(); - if ($USER_VERBOSE) { - COM_errorLog("Trying to set permanent cookie with time of $cookTime", 1); - } - if ($cookTime > 0) { - // They want their cookie to persist for some amount of time so set it now - if ($USER_VERBOSE) { - COM_errorLog('Trying to set permanent cookie', 1); - } - SEC_setCookie($_CONF['cookie_name'], $_USER['uid'], time() + $cookTime); - SEC_setCookie($_CONF['cookie_password'], $_USER['passwd'], time() + $cookTime); - } - } else { - $userId = Geeklog\Input::fCookie($_CONF['cookie_name']); - - if (!empty($userId) && ($userId !== 'deleted')) { - $userId = (int) $userId; - - if ($userId > 1) { - if ($USER_VERBOSE) { - COM_errorLog('NOW trying to set permanent cookie', 1); - COM_errorLog('Got ' . $userId . ' from perm cookie in users.php', 1); - } - - // Create new session - $_USER = SESS_getUserDataFromId($userId); - if ($USER_VERBOSE) { - COM_errorLog('Got ' . $_USER['username'] . ' for the username in user.php', 1); - } - } - } - } + // Issue an auto-login key + SESS_issueAutoLoginCookie($_USER['uid']); - // Now that we have users data see if their theme cookie is set. + // Now that we have user's data see if their theme cookie is set. // If not set it if (!empty($_USER['theme'])) { setcookie( @@ -905,10 +870,8 @@ function USER_tryTwoFactorAuth() SESS_endUserSession($_USER['uid']); PLG_logoutUser($_USER['uid']); } - SEC_setCookie($_CONF['cookie_session'], '', time() - 10000); - SEC_setCookie($_CONF['cookie_password'], '', time() - 10000); - SEC_setCookie($_CONF['cookie_name'], '', time() - 10000); - + SESS_deleteAutoLoginKey(); + $msg = (int) Geeklog\Input::fGet('msg', 0); if ($msg == 0) { $msg = 8; diff --git a/public_html/usersettings.php b/public_html/usersettings.php index 2e5f9cb3c..570772d78 100644 --- a/public_html/usersettings.php +++ b/public_html/usersettings.php @@ -1142,12 +1142,6 @@ function saveuser(array $A) (SEC_encryptUserPassword($A['old_passwd'], $_USER['uid']) == 0) ) { SEC_updateUserPassword($A['passwd'], $_USER['uid']); - if ($A['cooktime'] > 0) { - $cooktime = $A['cooktime']; - } else { - $cooktime = -1000; - } - SEC_setCookie($_CONF['cookie_password'], $passwd, time() + $cooktime); } elseif (SEC_encryptUserPassword($A['old_passwd'], $_USER['uid']) < 0) { COM_redirect($_CONF['site_url'] . '/usersettings.php?msg=68'); } elseif ($A['passwd'] != $A['passwd_conf']) { @@ -1158,12 +1152,6 @@ function saveuser(array $A) } } else { // Cookie - if ($A['cooktime'] > 0) { - $cooktime = $A['cooktime']; - } else { - $cooktime = -1000; - } - SEC_setCookie($_CONF['cookie_password'], $passwd, time() + $cooktime); } if ($_US_VERBOSE) { @@ -1171,10 +1159,9 @@ function saveuser(array $A) } if ($A['cooktime'] <= 0) { - $cooktime = 1000; - SEC_setCookie($_CONF['cookie_name'], $_USER['uid'], time() - $cooktime); + SESS_deleteAutoLoginKey(); } else { - SEC_setCookie($_CONF['cookie_name'], $_USER['uid'], time() + $A['cooktime']); + SESS_handleAutoLogin(); } if ($_CONF['allow_user_photo'] == 1) { diff --git a/sql/mysql_tableanddata.php b/sql/mysql_tableanddata.php index 7a20bc00b..798379720 100644 --- a/sql/mysql_tableanddata.php +++ b/sql/mysql_tableanddata.php @@ -1,5 +1,7 @@ add('likes_speedlimit',20,'text',$sg,$fs,NULL,$so,TRUE, $me, $tab); $so += 10; + // Delete some cookie-related settings + $c->del('cookie_password', $me); + $c->del('cookie_ip', $me); + return true; } diff --git a/sql/updates/pgsql_2.2.0_to_2.2.1.php b/sql/updates/pgsql_2.2.0_to_2.2.1.php index b7d522065..e7d746234 100644 --- a/sql/updates/pgsql_2.2.0_to_2.2.1.php +++ b/sql/updates/pgsql_2.2.0_to_2.2.1.php @@ -49,6 +49,15 @@ `id`); "; +// Modify `sessions` table +$_SQL[] = "DELETE FROM {$_TABLES['sessions']}"; +$_SQL[] = "ALTER TABLE {$_TABLES['sessions']} ALTER COLUMN sess_id TYPE VARCHAR(250) NOT NULL default ''"; +$_SQL[] = "ALTER TABLE {$_TABLES['sessions']} DROP COLUMN md5_sess_id}"; +$_SQL[] = "ALTER TABLE {$_TABLES['sessions']} DROP COLUMN topic}"; + +// Add `autologin_key` column to `users' table +$_SQL[] = "ALTER TABLE {$_TABLES['users']} ADD COLUMN autologin_key VARCHAR(250) NOT NULL DEFAULT ''"; + /** * Upgrade Messages */ @@ -112,6 +121,10 @@ function update_ConfValuesFor221() $c->add('likes_speedlimit',20,'text',$sg,$fs,NULL,$so,TRUE, $me, $tab); $so += 10; + // Delete some cookie-related settings + $c->del('cookie_password', $me); + $c->del('cookie_ip', $me); + return true; } diff --git a/system/classes/Session.php b/system/classes/Session.php index 25067edab..971a83c3a 100644 --- a/system/classes/Session.php +++ b/system/classes/Session.php @@ -2,6 +2,8 @@ namespace Geeklog; +use InvalidArgumentException; + /** * Class Session * @@ -9,30 +11,24 @@ */ abstract class Session { - // Index of $_SESSION array - const GL_NAMESPACE = '__gl'; - const VAR_NAMESPACE = '__v'; - const FLASH_VAR_NAMESPACE = '__f'; + // Indices of $_SESSION array + const NS_GL = '__gl'; + const NS_FLASH_VAR = '__f'; + const NS_VAR = '__v'; - // Default lifespan of the session in seconds - const DEFAULT_LIFE_SPAN = 7200; // 60 * 60 * 2; + // Default session name + const DEFAULT_SESSION_NAME = 'GLSESSION'; // Anonymous user ID const ANON_USER_ID = 1; /** - * User ID - * - * @var int - */ - private static $uid = 1; - - /** - * Lifespan of the session + * Lifespan of the current user's session * - * @var int + * @var int the length of time after which the session will expire. 0 means + * the session will expire when the user closes the browser window. */ - private static $lifeSpan = self::DEFAULT_LIFE_SPAN; + private static $sessionLifeTime = 0; /** * "flash", i.e., one-time session variables @@ -51,74 +47,74 @@ abstract class Session /** * Init the Session class * - * @param array $config + * @param array $config + * @return bool whether the session cookie already exists */ public static function init(array $config) { + $retval = true; + if (self::$isInitialized) { - return; + return $retval; } - // Set PHP settings - if (version_compare(PHP_VERSION, '5.5.2', '>=')) { - ini_set('session.use_strict_mode', 1); - } + // Make PHP session settings safer + if (is_callable('ini_set')) { + if (version_compare(PHP_VERSION, '5.5.2', '>=')) { + ini_set('session.use_strict_mode', 1); - ini_set('session.use_cookies', 1); - ini_set('session.use_only_cookies', 1); - ini_set('session.use_trans_sid', 0); + if (version_compare(PHP_VERSION, '7.1.0', '>=')) { + ini_set('session.sid_length', 40); + ini_set('session.sid_bits_per_character', 5); - if (isset($config['session_dir']) && is_readable($config['session_dir']) && is_dir($config['session_dir'])) { - ini_set('session.save_path', $config['session_dir']); + if (version_compare(PHP_VERSION, '7.3.0', '>=')) { + ini_set('session.cookie_samesite', 'Lax'); + } + } + } + + ini_set('session.use_cookies', 1); + ini_set('session.use_only_cookies', 1); + ini_set('session.use_trans_sid', 0); + ini_set('session.cache_limiter', 'nocache'); + ini_set('session.cookie_lifetime', 0); } + // Set session cookie parameters + self::setSessionCookieParameters($config); + // Start a new session if (!session_start()) { die(__METHOD__ . ': Cannot start session.'); } - // Check if the user is new - if (!isset($_SESSION[self::GL_NAMESPACE]) - || !isset($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]) - || !is_array($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]) - || !isset($_SESSION[self::GL_NAMESPACE][self::FLASH_VAR_NAMESPACE]) - || !is_array($_SESSION[self::GL_NAMESPACE][self::FLASH_VAR_NAMESPACE]) - || !isset($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['uid']) - || ($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['uid'] < self::ANON_USER_ID) - || !isset($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['expiresAt']) - || self::isExpires()) { - $_SESSION[self::GL_NAMESPACE] = array( - self::FLASH_VAR_NAMESPACE => array(), - self::VAR_NAMESPACE => array( + // Initialize the $_SESSION var if this is the first visit to the site + if (!isset($_SESSION[self::NS_GL]) || + !isset($_SESSION[self::NS_GL][self::NS_FLASH_VAR]) || + !is_array($_SESSION[self::NS_GL][self::NS_FLASH_VAR]) || + !isset($_SESSION[self::NS_GL][self::NS_VAR]) || + !is_array($_SESSION[self::NS_GL][self::NS_VAR]) || + !isset($_SESSION[self::NS_GL][self::NS_VAR]['uid']) || + !is_int($_SESSION[self::NS_GL][self::NS_VAR]['uid']) || + ($_SESSION[self::NS_GL][self::NS_VAR]['uid'] < self::ANON_USER_ID) + ) { + $_SESSION[self::NS_GL] = array( + self::NS_FLASH_VAR => array(), + self::NS_VAR => array( 'uid' => self::ANON_USER_ID, ), ); + $retval = false; } - // Get user ID from session - self::$uid = $_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['uid']; - // Move "flash" session vars to the property of the class - self::$flashVars = $_SESSION[self::GL_NAMESPACE][self::FLASH_VAR_NAMESPACE]; - $_SESSION[self::GL_NAMESPACE][self::FLASH_VAR_NAMESPACE] = array(); - - // Update life span - self::setLifeSpan(self::$lifeSpan); + self::$flashVars = $_SESSION[self::NS_GL][self::NS_FLASH_VAR]; + $_SESSION[self::NS_GL][self::NS_FLASH_VAR] = array(); - // Finished initialization + // Finish initialization self::$isInitialized = true; - } - /** - * Return if the current session has already expired - * - * @return bool - */ - public static function isExpires() - { - return isset($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['expiresAt']) - && is_int($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['expiresAt']) - && ($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['expiresAt']) < time(); + return $retval; } /** @@ -128,7 +124,7 @@ public static function isExpires() */ public static function isLoggedIn() { - return (self::$uid > self::ANON_USER_ID); + return (self::getUid() > self::ANON_USER_ID); } /** @@ -138,99 +134,129 @@ public static function isLoggedIn() */ public static function getUid() { - return self::$uid; + return $_SESSION[self::NS_GL][self::NS_VAR]['uid']; } /** * Set the current user id * - * @param int $uid - * @throws \InvalidArgumentException + * @param int $uid + * @throws InvalidArgumentException */ public static function setUid($uid) { $uid = (int) $uid; if ($uid >= self::ANON_USER_ID) { - $_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['uid'] = $uid; - self::regenerate(); + $_SESSION[self::NS_GL][self::NS_VAR]['uid'] = $uid; } else { - throw new \InvalidArgumentException('User id must be ' . self::ANON_USER_ID . ' or greater.'); + throw new InvalidArgumentException('User id must be ' . self::ANON_USER_ID . ' or greater.'); } } /** - * Set a session value + * Set a session variable * - * @param string $name - * @param mixed $value + * @param string $name + * @param mixed $value */ - public static function set($name, $value) + public static function setVar($name, $value) { - $_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE][$name] = $value; + $_SESSION[self::NS_GL][self::NS_VAR][$name] = $value; } /** - * Set a "flash" session value + * Set a "flash" session variable * - * @param string $name - * @param mixed $value + * @param string $name + * @param mixed $value */ - public static function setFlash($name, $value) + public static function setFlashVar($name, $value) { - $_SESSION[self::GL_NAMESPACE][self::FLASH_VAR_NAMESPACE][$name] = $value; + $_SESSION[self::NS_GL][self::NS_FLASH_VAR][$name] = $value; } /** - * Get a session value + * Get a session variable * - * @param string $name - * @param mixed $defaultValue + * @param string $name + * @param mixed $defaultValue * @return mixed */ - public static function get($name, $defaultValue = null) + public static function getVar($name, $defaultValue = null) { - return isset($_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE][$name]) - ? $_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE][$name] + return isset($_SESSION[self::NS_GL][self::NS_VAR][$name]) + ? $_SESSION[self::NS_GL][self::NS_VAR][$name] : $defaultValue; } /** - * Get a "flash" session value + * Get a "flash" session variable * - * @param string $name - * @param mixed $defaultValue + * @param string $name + * @param mixed $defaultValue * @return mixed */ - public static function getFlash($name, $defaultValue = null) + public static function getFlashVar($name, $defaultValue = null) { return isset(self::$flashVars[$name]) ? self::$flashVars[$name] : $defaultValue; } /** * Regenerate the session id + * + * @return string the new session id */ - public static function regenerate() + public static function regenerateId() { session_regenerate_id(false); + + return self::getSessionId(); } /** - * Set session lifespan + * Set session cookie parameters * - * @param int $lifeSpan + * @param array $config */ - public static function setLifeSpan($lifeSpan) + private static function setSessionCookieParameters(array $config) { - $lifeSpan = (int) $lifeSpan; - if ($lifeSpan < 0) { - $lifeSpan = 0; + $args = session_get_cookie_params(); + + // Override 'lifetime' + $args['lifetime'] = 0; + + if (isset($config['cookie_path']) && (strlen($config['cookie_path']) > 0)) { + $args['path'] = $config['cookie_path']; } - self::$lifeSpan = $lifeSpan; - $_SESSION[self::GL_NAMESPACE][self::VAR_NAMESPACE]['expiresAt'] = time() + self::$lifeSpan; - $args = session_get_cookie_params(); - $args['lifetime'] = self::$lifeSpan; + if (isset($config['cookie_domain']) && (strlen($config['cookie_domain']) > 0)) { + $args['domain'] = $config['cookie_domain']; + } + + if (isset($config['cookie_secure']) && (is_bool($config['cookie_secure']) || is_int($config['cookie_secure']))) { + $args['secure'] = (bool) $config['cookie_secure']; + } + + if (!isset($config['session_name']) || preg_match('/\A[0-9]+\z/', $config['session_name'])) { + $config['session_name'] = self::DEFAULT_SESSION_NAME; + } else { + $config['session_name'] = str_replace('_', '', $config['session_name']); + $config['session_name'] = strtoupper($config['session_name']); + } + + $args['httponly'] = true; session_set_cookie_params($args['lifetime'], $args['path'], $args['domain'], $args['secure'], $args['httponly']); + session_name($config['session_name']); + } + + /** + * Return the current session id + * + * @return string + */ + public static function getSessionId() + { + return session_id(); } } diff --git a/system/lib-security.php b/system/lib-security.php index d8d9aac7d..8a749f497 100644 --- a/system/lib-security.php +++ b/system/lib-security.php @@ -2125,7 +2125,7 @@ function SEC_randomBytes($length) try { $retval = random_bytes($length); - } catch (\Exception $e) { + } catch (Exception $e) { $retval = false; if (is_callable('openssl_random_pseudo_bytes ')) { diff --git a/system/lib-sessions.php b/system/lib-sessions.php index 29cdf0ea6..0a5b25ab9 100644 --- a/system/lib-sessions.php +++ b/system/lib-sessions.php @@ -8,7 +8,7 @@ // | | // | Geeklog session library. | // +---------------------------------------------------------------------------+ -// | Copyright (C) 2000-2018 by the following authors: | +// | Copyright (C) 2000-2019 by the following authors: | // | | // | Authors: Tony Bibbs - tony AT tonybibbs DOT com | // | Mark Limburg - mlimburg AT users DOT sourceforge DOT net | @@ -33,22 +33,24 @@ /** * This is the session management library for Geeklog. Some of this code was * borrowed from phpBB 1.4.x which is also GPL'd -* */ +use Geeklog\Input; +use Geeklog\Session; + // Turn this on if you want to see various debug messages from this library $_SESS_VERBOSE = COM_isEnableDeveloperModeLog('session'); -if (strpos(strtolower($_SERVER['PHP_SELF']), 'lib-sessions.php') !== false) { +if (stripos($_SERVER['PHP_SELF'], 'lib-sessions.php') !== false) { die('This file can not be used on its own!'); } -if (empty ($_CONF['cookiedomain'])) { - preg_match ("/\/\/([^\/:]*)/", $_CONF['site_url'], $server); - if (substr ($server[1], 0, 4) == 'www.') { - $_CONF['cookiedomain'] = substr ($server[1], 3); +if (empty($_CONF['cookiedomain'])) { + preg_match("/\/\/([^\/:]*)/", $_CONF['site_url'], $server); + if (substr($server[1], 0, 4) === 'www.') { + $_CONF['cookiedomain'] = substr($server[1], 3); } else { - if (strchr ($server[1], '.') === false) { + if (strpos($server[1], '.') === false) { // e.g. 'localhost' or other local names $_CONF['cookiedomain'] = ''; } else { @@ -56,7 +58,7 @@ } } if ($_SESS_VERBOSE) { - COM_errorLog ("Setting cookiedomain = '" . $_CONF['cookiedomain'] . "'", 1); + COM_errorLog("Setting cookiedomain = '" . $_CONF['cookiedomain'] . "'", 1); } } @@ -65,9 +67,6 @@ * * Much of this code if from phpBB (www.phpbb.org). This checks the session * cookie and long term cookie to get the users state. -* -* @return void -* */ function SESS_sessionCheck() { @@ -77,118 +76,96 @@ function SESS_sessionCheck() COM_errorLog("*** Inside SESS_sessionCheck ***",1); } - $_USER = array(); + $_USER = array( + 'uid' => Session::ANON_USER_ID, + ); // Check for a cookie on the users's machine. If the cookie exists, build // an array of the users info and setup the theme. // Flag indicates if session cookie and session data exist - $session_exists = true; - - if (isset($_COOKIE[$_CONF['cookie_session']])) { - $sessid = COM_applyFilter($_COOKIE[$_CONF['cookie_session']]); + $sessionExists = Session::init(array( + 'cookie_lifetime' => $_CONF['session_cookie_timeout'], + 'cookie_path' => $_CONF['cookie_path'], + 'cookie_domain' => $_CONF['cookiedomain'], + 'cookie_secure' => $_CONF['cookiesecure'], + 'session_name' => $_CONF['cookie_session'], + )); + $sessId = Session::getSessionId(); + $status = -1; + + if ($sessionExists) { if ($_SESS_VERBOSE) { - COM_errorLog("Got $sessid as the session ID",1); + COM_errorLog("Got {$sessId} as the session ID",1); } - $userid = SESS_getUserIdFromSession($sessid, $_CONF['session_cookie_timeout'], - $_SERVER['REMOTE_ADDR'], $_CONF['cookie_ip']); - + $userId = Session::getUid(); if ($_SESS_VERBOSE) { - COM_errorLog("Got $userid as User ID from the session ID",1); + COM_errorLog("Got {$userId} as User ID from the session ID",1); } - if ($userid > 1) { + if ($userId > Session::ANON_USER_ID) { // Check user status - $status = SEC_checkUserStatus($userid); + $status = SEC_checkUserStatus($userId); if (($status == USER_ACCOUNT_ACTIVE) || ($status == USER_ACCOUNT_AWAITING_ACTIVATION || $status == USER_ACCOUNT_LOCKED || $status == USER_ACCOUNT_NEW_EMAIL || $status == USER_ACCOUNT_NEW_PASSWORD)) { - SESS_updateSessionTime($sessid, $_CONF['cookie_ip']); - $_USER = SESS_getUserDataFromId($userid); + SESS_updateSessionTime($sessId); + $_USER = SESS_getUserDataFromId($userId); if ($_SESS_VERBOSE) { $str = "Got " . count($_USER) . " pieces of data from userdata \n"; - foreach ($_USER as $k => $v) + foreach ($_USER as $k => $v) { $str .= sprintf("%15s [%s] \n", $k, $v); + } COM_errorLog($str, 1); } - $_USER['auto_login'] = false; + + SESS_issueAutoLoginCookie($userId); + } + } elseif ($userId === Session::ANON_USER_ID) { + // Check if the permanent cookie exists + $userId = SESS_handleAutoLogin(); + + if ($userId > Session::ANON_USER_ID) { + SESS_newSession($userId, $_SERVER['REMOTE_ADDR'], $_CONF['session_cookie_timeout']); + $_USER = SESS_getUserDataFromId($userId); + SESS_issueAutoLoginCookie($userId); + } else { + // Anonymous User has session so update any information + SESS_updateSessionTime($sessId); } - } elseif ($userid == 1) { - // Anonymous User has session so update any information - SESS_updateSessionTime($sessid, $_CONF['cookie_ip']); - } else { - // Session probably expired - $session_exists = false; } } else { + // Session cookie was not found, but the Session class was initialized. if ($_SESS_VERBOSE) { COM_errorLog("Session cookie not found",1); } - $session_exists = false; - } - if ($session_exists === false) { // Check if the permanent cookie exists - $userid = ''; - if (isset($_COOKIE[$_CONF['cookie_name']])) { - $userid = COM_applyFilter($_COOKIE[$_CONF['cookie_name']], true); - } + $userId = SESS_handleAutoLogin(); - if (!empty($userid)) { + if ($userId > Session::ANON_USER_ID) { // Session cookie or session data don't exist, but a permanent cookie does. - // Start a new session cookie and session data; if ($_SESS_VERBOSE) { - COM_errorLog("Got $userid as User ID from the permanent cookie",1); - } - - $cookie_password = ''; - $userpass = ''; - if (($userid > 1) && - isset($_COOKIE[$_CONF['cookie_password']])) { - $cookie_password = $_COOKIE[$_CONF['cookie_password']]; - $userpass = DB_getItem($_TABLES['users'], 'passwd', - "uid = $userid"); + COM_errorLog("Got {$userId} as User ID from the permanent cookie", 1); } - if (empty($cookie_password) || ($cookie_password <> $userpass)) { - if ($_SESS_VERBOSE) { - COM_errorLog("Password comparison failed or cookie password missing",1); - } - // Invalid or manipulated cookie data - $ctime = time() - 10000; - SEC_setCookie($_CONF['cookie_session'], '', $ctime); - SEC_setCookie($_CONF['cookie_password'], '', $ctime); - SEC_setCookie($_CONF['cookie_name'], '', $ctime); + Session::setUid($userId); - COM_clearSpeedlimit($_CONF['login_speedlimit'], 'login'); - if (COM_checkSpeedlimit('login', $_CONF['login_attempts']) > 0) { - if (! defined('XHTML')) { define('XHTML', ''); } - COM_displayMessageAndAbort(82, '', 403, 'Access denied'); - } - COM_updateSpeedlimit('login'); - } elseif ($userid > 1) { + // Check user status + $status = SEC_checkUserStatus($userId); + if (($status == USER_ACCOUNT_ACTIVE) || + ($status == USER_ACCOUNT_AWAITING_ACTIVATION)) { if ($_SESS_VERBOSE) { - COM_errorLog("Password comparison passed",1); - } - // Check user status - $status = SEC_checkUserStatus($userid); - if (($status == USER_ACCOUNT_ACTIVE) || - ($status == USER_ACCOUNT_AWAITING_ACTIVATION)) { - if ($_SESS_VERBOSE) { - COM_errorLog("Create new session and write cookie",1); - } - // Create new session and write cookie - $sessid = SESS_newSession($userid, $_SERVER['REMOTE_ADDR'], - $_CONF['session_cookie_timeout'], $_CONF['cookie_ip']); - SESS_setSessionCookie($sessid, $_CONF['session_cookie_timeout'], - $_CONF['cookie_session'], $_CONF['cookie_path'], - $_CONF['cookiedomain'], $_CONF['cookiesecure']); - $_USER = SESS_getUserDataFromId($userid); - $_USER['auto_login'] = true; + COM_errorLog('Create new session', 1); } + + // Create new session and write cookie + SESS_newSession($userId, $_SERVER['REMOTE_ADDR'], $_CONF['session_cookie_timeout']); + $_USER = SESS_getUserDataFromId($userId); + $_USER['auto_login'] = true; } } else { if ($_SESS_VERBOSE) { @@ -197,12 +174,7 @@ function SESS_sessionCheck() // Anonymous user has session id but it has been expired and wiped from the db so reset. // Or new anonymous user so create new session and write cookie. - $userid = 1; - $sessid = SESS_newSession($userid, $_SERVER['REMOTE_ADDR'], - $_CONF['session_cookie_timeout'], $_CONF['cookie_ip']); - SESS_setSessionCookie($sessid, $_CONF['session_cookie_timeout'], - $_CONF['cookie_session'], $_CONF['cookie_path'], - $_CONF['cookiedomain'], $_CONF['cookiesecure']); + SESS_newSession($userId, $_SERVER['REMOTE_ADDR'], $_CONF['session_cookie_timeout']); } } @@ -210,10 +182,8 @@ function SESS_sessionCheck() COM_errorLog("*** Leaving SESS_sessionCheck ***",1); } - $_USER['session_id'] = $sessid; - // Check to see if user status is set to something we have to redirect the user too - if (isset($_USER['uid']) && $_USER['uid'] > 1) { + if (isset($_USER['uid']) && $_USER['uid'] > Session::ANON_USER_ID) { // Check if active user has email account and if required // Doesn't matter if remote account or not if ($_CONF['require_user_email'] && empty($_USER['email']) && $_USER['status'] == USER_ACCOUNT_ACTIVE) { @@ -223,12 +193,12 @@ function SESS_sessionCheck() if ($_USER['status'] == USER_ACCOUNT_LOCKED) { // Account is locked so user shouldn't be logged in - if ($_SERVER['PHP_SELF'] != '/users.php') { + if ($_SERVER['PHP_SELF'] !== '/users.php') { COM_redirect($_CONF['site_url'] . '/users.php?mode=logout&msg=17'); } } elseif ($_USER['status'] == USER_ACCOUNT_NEW_EMAIL || $_USER['status'] == USER_ACCOUNT_NEW_PASSWORD) { // Account requires additional info so get it - if ($_SERVER['PHP_SELF'] != '/users.php') { + if ($_SERVER['PHP_SELF'] !== '/users.php') { if ($_USER['status'] == USER_ACCOUNT_NEW_EMAIL) { COM_redirect($_CONF['site_url'] . '/users.php?mode=newemailstatus'); } elseif ($status == USER_ACCOUNT_NEW_PASSWORD) { @@ -246,356 +216,300 @@ function SESS_sessionCheck() * Adds a new session to the database for the given userid and returns a new session ID. * Also deletes all expired sessions from the database, based on the given session lifespan. * -* @param int $userid User ID to create session for -* @param string $remote_ip IP address user is connected from -* @param string $lifespan How long (seconds) this cookie should persist -* @param int $md5_based If 1 session will be MD5 hash of ip address -* @return string Session ID -* +* @param int $userId User ID to create session for +* @param string $remote_ip IP address user is connected from +* @param string $lifespan How long (seconds) this cookie should persist +* @return string Session ID */ -function SESS_newSession($userid, $remote_ip, $lifespan, $md5_based=0) +function SESS_newSession($userId, $remote_ip, $lifespan) { global $_TABLES, $_CONF, $_SESS_VERBOSE; if ($_SESS_VERBOSE) { - COM_errorLog("*** Inside SESS_newSession ***",1); - COM_errorLog("Args to SESS_newSession: userid = $userid, " - . "remote_ip = $remote_ip, lifespan = $lifespan, " - . "md5_based = $md5_based",1); - } - $sessid = mt_rand(); - - // For added security we are adding the option to build a IP-based - // session ID. This has the advantage of better security but it may - // required dialed users to login every time. You can turn the below - // code on in the configuration (it's turned off by default) - $md5_sessid = ''; - if ($md5_based == 1) { - $ip = str_replace('.','',$remote_ip); - $md5_sessid = md5($ip + $sessid); + COM_errorLog("*** Inside SESS_newSession ***", 1); + COM_errorLog( + "Args to SESS_newSession: userid = {$userId}, remote_ip = {$remote_ip}, lifespan = {$lifespan}", + 1 + ); } + // Delete expired sessions from database $ctime = time(); - $currtime = (string) ($ctime); - $expirytime = (string) ($ctime - $lifespan); - if (!isset($_COOKIE[$_CONF['cookie_session']])) { - // ok, delete any old sessons for this user - if ($userid > 1) { - DB_delete($_TABLES['sessions'], 'uid', $userid); - } else { - DB_delete($_TABLES['sessions'], array('uid', 'remote_ip'), - array(1, $remote_ip)); - } - } else { + $currentTime = (string) ($ctime); + $expiryTime = (string) ($ctime - $lifespan); + $deleteResult = false; + $retryMax = 3; + $wait = 50000; // 50 ms + + for ($i = 0; $i < $retryMax; $i++) { DB_lockTable($_TABLES['sessions']); - $deleteSQL = "DELETE FROM {$_TABLES['sessions']} WHERE (start_time < $expirytime)"; - $delresult = DB_query($deleteSQL); + $deleteSQL = "DELETE FROM {$_TABLES['sessions']} WHERE (start_time < {$expiryTime})"; + $deleteResult = DB_query($deleteSQL); DB_unlockTable($_TABLES['sessions']); - if ($_SESS_VERBOSE) { COM_errorLog("Attempted to delete rows from session table with following SQL\n$deleteSQL\n",1); - COM_errorLog("Got $delresult as a result from the query",1); + COM_errorLog("Got $deleteResult as a result from the query",1); } - if (!$delresult) { - die("Delete failed in SESS_newSession()"); + if ($deleteResult) { + break; } + + usleep($wait); } - // Remove the anonymous session for this user - if ($userid > 1) { - // Retrieve any session variables that we need to add to the new logged in session - // To come - // Delete record - DB_delete($_TABLES['sessions'], array('uid', 'remote_ip'), - array(1, $remote_ip)); + + if (!$deleteResult) { + die("Delete failed in SESS_newSession()"); } + // Delete old session from database + $oldSessionId = Session::getSessionId(); + $escOldSessionId = DB_escapeString($oldSessionId); + DB_query("DELETE FROM {$_TABLES['sessions']} WHERE sess_id = '{$escOldSessionId}'"); + + // Create new session ID and insert it into database + $sessId = Session::regenerateId(); + $escSessionId = DB_escapeString($sessId); + $escRemoteIp = DB_escapeString($remote_ip); + // Create new session - if ($md5_based == 1) { - $sql = "INSERT INTO {$_TABLES['sessions']} " - . "(sess_id, md5_sess_id, uid, start_time, remote_ip, whos_online) " - . "VALUES ($sessid, '$md5_sessid', $userid, $currtime, '$remote_ip', 1)"; - } else { - $sql = "INSERT INTO {$_TABLES['sessions']} " - . "(sess_id, uid, start_time, remote_ip, whos_online) " - . "VALUES ($sessid, $userid, $currtime, '$remote_ip', 1)"; - } + Session::setUid($userId); + $sql = "INSERT INTO {$_TABLES['sessions']} (sess_id, uid, start_time, remote_ip, whos_online) " + . "VALUES ('{$escSessionId}', {$userId}, {$currentTime}, '{$escRemoteIp}', 1)"; $result = DB_query($sql); if (!$result) { - echo DB_error().": ".DB_error().""; - die("Insert failed in SESS_newSession()"); + echo DB_error() . ': ' . DB_error() . ''; + die('Insert failed in SESS_newSession()'); } - if ($_CONF['lastlogin'] == true) { + if ($_CONF['lastlogin']) { // Update userinfo record to record the date and time as lastlogin - DB_query("UPDATE {$_TABLES['userinfo']} SET lastlogin = UNIX_TIMESTAMP() WHERE uid=$userid"); + DB_query("UPDATE {$_TABLES['userinfo']} SET lastlogin = UNIX_TIMESTAMP() WHERE uid = {$userId}"); } if ($_SESS_VERBOSE) { - COM_errorLog("Assigned the following session id: $sessid",1); - COM_errorLog("*** Leaving SESS_newSession ***",1); - } - if ($md5_based == 1) { - return $md5_sessid; + COM_errorLog("Assigned the following session id: {$sessId}", 1); + COM_errorLog("*** Leaving SESS_newSession ***", 1); } - return $sessid; + + return $sessId; } /** -* Sets the session cookie +* Updates a session cookie's timeout and the session id * -* This saves the session ID to the session cookie on client's machine for -* later use -* -* @param string $sessid Session ID to save to cookie -* @param int $cookietime Cookie timeout value (not used) -* @param string $cookiename Name of cookie to save sessiond ID to -* @param string $cookiepath Path in which cookie should be sent to server for -* @param string $cookiedomain Domain in which cookie should be sent to server for -* @param int $cookiesecure if =1, set cookie only on https connection +* Refresh the start_time of the given session in the database. +* This is called whenever a page is hit by a user with a valid session. * +* @param string $sessId Session ID to update time for +* @return string a new session ID */ -function SESS_setSessionCookie($sessid, $cookietime, $cookiename, $cookiepath, $cookiedomain, $cookiesecure) +function SESS_updateSessionTime($sessId) { - global $_SESS_VERBOSE; + global $_TABLES; - // This sets a cookie that will persist until the user closes their browser - // window. since session expiry is handled on the server-side, cookie expiry - // time isn't a big deal. - if ($_SESS_VERBOSE) { - COM_errorLog("Setting session cookie: setcookie($cookiename, $sessid, 0, " - . "$cookiepath, $cookiedomain, $cookiesecure);", 1); - } + $escOldSessionId = DB_escapeString($sessId); + $newSessionId = Session::regenerateId(); + $escNewSessionId = DB_escapeString($newSessionId); + $newTime = (string) time(); + $sql = "UPDATE {$_TABLES['sessions']} SET start_time = {$newTime}, " + . "whos_online = 1, sess_id = '{$escNewSessionId}' " + . "WHERE sess_id = '{$escOldSessionId}'"; + DB_query($sql); - if (SEC_setCookie($cookiename, $sessid, 0, $cookiepath, $cookiedomain, - $cookiesecure) === false) { - COM_errorLog("Failed to set session cookie.", 1); - } + return $newSessionId; } /** -* Gets the user id from Session ID +* This ends a user session * -* Returns the userID associated with the given session, based on -* the given session lifespan $cookietime and the given remote IP -* address. If no match found, returns 0. +* Delete the given session from the database. Used by the logout page. * -* @param string $sessid Session ID to get user ID from -* @param string $cookietime Used to query DB for valid sessions -* @param string $remote_ip Used to pull session we need -* @param int $md5_based Let's us now if we need to take MD5 hash into consideration -* @return int User ID +* @param int $userId User ID to end session of +* @return bool Always true for some reason */ -function SESS_getUserIdFromSession($sessid, $cookietime, $remote_ip, $md5_based=0) +function SESS_endUserSession($userId) { - global $_TABLES, $_SESS_VERBOSE; - - if ($_SESS_VERBOSE) { - COM_errorLog("*** Inside SESS_getUserIdFromSession ***",1); - } - - $mintime = (string) (time() - $cookietime); - - if ($md5_based == 1) { - $sql_where = "md5_sess_id = '$sessid'"; - } else { - $sql_where = "sess_id = '$sessid'"; - } - $sql = "SELECT uid FROM {$_TABLES['sessions']} WHERE " - . "($sql_where) AND (start_time > $mintime) AND (remote_ip = '$remote_ip')"; - - if ($_SESS_VERBOSE) { - COM_errorLog("SQL in SESS_getUserIdFromSession is: \n$sql \n", 1); - } + global $_CONF, $_TABLES; - $result = DB_query($sql); - $numrows = DB_numRows($result); + $userId = (int) $userId; - if ($_SESS_VERBOSE) { - COM_errorLog("*** Leaving SESS_getUserIdFromSession ***",1); + if (!(isset($_CONF['demo_mode']) && $_CONF['demo_mode'])) { + DB_delete($_TABLES['sessions'], 'uid', $userId); + Session::setUid(Session::ANON_USER_ID); } - if ($numrows == 1) { - $row = DB_fetchArray($result); - return $row['uid']; - } - return 0; + return 1; } /** -* Updates a session cookies timeout -* -* Refresh the start_time of the given session in the database. -* This is called whenever a page is hit by a user with a valid session. -* -* @param string $sessid Session ID to update time for -* @param int $md5_based Indicates if sessid is MD5 hash -* @return boolean always true for some reason +* Gets user's data based on their user id * +* @param int $userId User ID of user to get data for +* @return array returns user's data in an array */ -function SESS_updateSessionTime($sessid, $md5_based=0) +function SESS_getUserDataFromId($userId) { global $_TABLES; - $newtime = (string) time(); + $userId = (int) $userId; + if ($userId <= Session::ANON_USER_ID) { + return array( + 'uid' => Session::ANON_USER_ID, + 'username' => 'anonymous', + ); + } + + $sql = "SELECT *,format FROM {$_TABLES['dateformats']},{$_TABLES['users']},{$_TABLES['userprefs']} " + . "WHERE {$_TABLES['dateformats']}.dfid = {$_TABLES['userprefs']}.dfid AND " + . "{$_TABLES['userprefs']}.uid = $userId AND {$_TABLES['users']}.uid = {$userId}"; - if ($md5_based == 1) { - $sql_where = "md5_sess_id = '$sessid'"; - } else { - $sql_where = "sess_id = '$sessid'"; + if ((!$result = DB_query($sql)) || (!$myRow = DB_fetchArray($result, false))) { + return array( + 'uid' => $userId, + 'username' => 'anonymous', + 'error' => '1', + ); } - DB_query("UPDATE {$_TABLES['sessions']} " - . "SET start_time = $newtime, whos_online = 1 WHERE ($sql_where)"); - return 1; + return $myRow; } /** -* This ends a user session -* -* Delete the given session from the database. Used by the logout page. -* -* @param int $userid User ID to end session of -* @return boolean Always true for some reason +* Retrieves a session variable from the db * +* @param string $name Variable name to retrieve +* @return mixed data from variable */ -function SESS_endUserSession($userid) +function SESS_getVariable($name) { - global $_CONF, $_TABLES; + return Session::getVar($name, ''); +} - if (!(isset($_CONF['demo_mode']) && $_CONF['demo_mode'])) { - DB_delete($_TABLES['sessions'], 'uid', $userid); - } +/** +* Updates a session variable from the db +* +* @param string $name Variable name to update +* @param mixed $value Value of variable +* @return bool Always true for some reason +*/ +function SESS_setVariable($name, $value) +{ + Session::setVar($name, $value); return 1; } /** -* Gets a user's data -* -* Gets user's data based on their username -* -* @param string $username Username of user to get data for -* @return array returns user's data in an array -* -*/ -function SESS_getUserData($username) + * Handle an auto-login key + * + * @param int $lifeTime cookie lifetime + * @return int user id or 1 when no auto-login key was found + */ +function SESS_handleAutoLogin($lifeTime = -1) { - global $_TABLES; + global $_CONF, $_TABLES; - $sql = "SELECT *,format FROM {$_TABLES['users']}, {$_TABLES['userprefs']}, {$_TABLES['dateformats']} " - . "WHERE {$_TABLES['dateformats']}.dfid = {$_TABLES['userprefs']}.dfid AND " - . "{$_TABLES['userprefs']}.uid = {$_TABLES['users']}.uid AND username = '$username'"; + // Get an auto-login key from cookie + $autoLoginKey = Input::cookie($_CONF['cookie_name'], ''); + $autoLoginKey = preg_replace('/[^0-9a-f]/', '', $autoLoginKey); - if (!$result = DB_query($sql)) { - COM_errorLog("Error in SESS_getUserData", 1); + if ($autoLoginKey === '') { + // No auto-login key was found in the permanent cookie + return 1; } - if (!$myrow = DB_fetchArray($result)) { - COM_errorLog("Error in SESS_getUserData", 1); + $escAutoLoginKey = DB_escapeString($autoLoginKey); + $sql = "SELECT uid FROM {$_TABLES['users']} WHERE autologin_key = '{$escAutoLoginKey}'"; + $result = DB_query($sql); + if (DB_error()) { + return 1; } - return $myrow; -} + switch (DB_numRows($result)) { + case 0: + // The Auto-login key given was not found in database. Possible attack + COM_clearSpeedlimit($_CONF['login_speedlimit'], 'login'); + if (COM_checkSpeedlimit('login', $_CONF['login_attempts']) > 0) { + COM_displayMessageAndAbort(82, '', 403, 'Access denied'); + } + COM_updateSpeedlimit('login'); -/** -* Gets user's data -* -* Gets user's data based on their user id -* -* @param int $userid User ID of user to get data for -* @return array returns user's data in an array -* -*/ -function SESS_getUserDataFromId($userid) -{ - global $_TABLES; + return 1; + break; - $sql = "SELECT *,format FROM {$_TABLES['dateformats']},{$_TABLES['users']},{$_TABLES['userprefs']} " - . "WHERE {$_TABLES['dateformats']}.dfid = {$_TABLES['userprefs']}.dfid AND " - . "{$_TABLES['userprefs']}.uid = $userid AND {$_TABLES['users']}.uid = $userid"; + case 1: + $A = DB_fetchArray($result, false); + $uid = (int) $A['uid']; - if (!$result = DB_query($sql)) { - $userdata = array('error' => '1'); - return $userdata; - } + // Issue a new auto-login key + SESS_issueAutoLoginCookie($uid); - if (!$myrow = DB_fetchArray($result, false)) { - $userdata = array('error' => '1'); - return $userdata; - } + return $uid; + break; - return $myrow; -} + default: + // very unlikely case + $sql = "UPDATE {$_TABLES['users']} SET autologin_key = '' WHERE autologin_key = {$escAutoLoginKey}"; + DB_query($sql); + return 1; + break; + } +} /** -* Gets the Session ID from the User Id -* -* Returns the session id associated with the user if available. -* This is not for anonymous users. If no match found, returns an empty string. -* -* @param int $uid User Id to retrieve session Id for -* @return string Session ID -*/ -function SESS_getSessionIdFromUserId($uid) + * Issue a cookie containing an auto-login cookie + * + * @param int $userId + * @param int $lifeTime + * @return string a newly created auto-login key or false on failure + */ +function SESS_issueAutoLoginCookie($userId, $lifeTime = -1) { - global $_TABLES; + global $_CONF, $_TABLES; - $retval = ''; - if ($uid > 1) { - $retval = DB_getItem($_TABLES['sessions'], "sess_id", "uid = $uid"); + // We don't issue auto-login cookies for anonymous users + $userId = (int) $userId; + if ($userId <= Session::ANON_USER_ID) { + return false; } - return $retval; -} + $lifeTime = (int) $lifeTime; + if ($lifeTime <= 0) { + $lifeTime = COM_getUserCookieTimeout(); -/** -* Retrieves a session variable from the db -* -* @param string $variable Variable name to retrieve -* @return string data from variable -* -*/ -function SESS_getVariable($variable) -{ - global $_TABLES, $_CONF, $_USER; + // This user doesn't want auto-login feature + if ($lifeTime <= 0) { + return false; + } + } - $session_id = $_USER['session_id']; + $autoLoginKey = SEC_randomBytes(80); + $autoLoginKey = sha1($autoLoginKey); - if ($_CONF['cookie_ip'] == 1) { // $md5_based Indicates if sessid is MD5 hash - $sql_where = "md5_sess_id = '$session_id'"; + if (SEC_setCookie($_CONF['cookie_name'], $autoLoginKey, time() + $lifeTime)) { + $escAutoLoginKey = DB_escapeString($autoLoginKey); + $sql = "UPDATE {$_TABLES['users']} SET autologin_key = '{$escAutoLoginKey}' WHERE uid = {$userId}"; + DB_query($sql); + return $autoLoginKey; } else { - $sql_where = "sess_id = '$session_id'"; + return false; } - $retval = DB_getItem($_TABLES['sessions'], $variable, $sql_where); - - return $retval; } /** -* Updates a session variable from the db -* -* @param string $variable Variable name to update -* @param string $value Value of variable -* @param string $session_id Session ID of variable to update (0 = current session) -* @return boolean always true for some reason -* -*/ -function SESS_setVariable($variable, $value, $session_id = '') + * Delete an existing auto-login key for the current user + */ +function SESS_deleteAutoLoginKey() { - global $_TABLES, $_CONF, $_USER; + global $_CONF, $_TABLES; - if ($session_id === '') { - $session_id = $_USER['session_id']; - } + $autoLoginKey = Input::fCookie($_CONF['cookie_name'], ''); - if ($_CONF['cookie_ip'] == 1) { // $md5_based Indicates if sessid is MD5 hash - $sql_where = "md5_sess_id = '$session_id'"; - } else { - $sql_where = "sess_id = '$session_id'"; + if (!empty($autoLoginKey)) { + $escAutoLoginKey = DB_escapeString($autoLoginKey); + $sql = "UPDATE {$_TABLES['users']} SET autologin_key = '' WHERE autologin_key = '{$escAutoLoginKey}'"; + DB_query($sql); + SEC_setCookie($_CONF['cookie_name'], '', time() - 10000); } - DB_query("UPDATE {$_TABLES['sessions']} " - . "SET $variable = '$value' WHERE ($sql_where)"); - - return 1; }