X-Git-Url: https://vcs.fsf.org/?p=squirrelmail.git;a=blobdiff_plain;f=functions%2Fglobal.php;h=f07d313da43b284a6482fe7c21f70c9d3c19c6eb;hp=36ee51a58011f14d01512ac8177b22f0adfd712b;hb=8ed1923822b383ddb338e9eef75bb7f110cc47b4;hpb=f151e745404bb45f6162d41b4e75d5b0fbddceba diff --git a/functions/global.php b/functions/global.php index 36ee51a5..f07d313d 100644 --- a/functions/global.php +++ b/functions/global.php @@ -7,13 +7,17 @@ * It also has some session register functions that work across various * php versions. * - * @copyright © 1999-2007 The SquirrelMail Project Team + * @copyright 1999-2019 The SquirrelMail Project Team * @license http://opensource.org/licenses/gpl-license.php GNU Public License * @version $Id$ * @package squirrelmail */ /** + * These constants are used in the function sqgetGlobalVar(). See + * sqgetGlobalVar() for a description of what they mean. + * + * @since 1.4.0 */ define('SQ_INORDER',0); define('SQ_GET',1); @@ -111,7 +115,7 @@ function sqstripslashes(&$array) { * executed will be returned. * */ -function sq_call_function_suppress_errors($function, $args=NULL) { +function sq_call_function_suppress_errors($function, $args=array()) { global $sm_debug_mode; $display_errors = ini_get('display_errors'); @@ -155,7 +159,9 @@ function sqsession_unregister ($name) { unset($_SESSION[$name]); - session_unregister("$name"); + // starts throwing warnings in PHP 5.3.0 and is + // removed in PHP 6 and is redundant anyway + //session_unregister("$name"); } /** @@ -261,19 +267,24 @@ function sqGetGlobalVarMultiple($name, &$value, $indicator_field, /** - * Search for the var $name in $_SESSION, $_POST, $_GET, $_COOKIE, or $_SERVER - * and set it in provided var. + * Search for the variable $name in one or more of the global variables + * $_SESSION, $_POST, $_GET, $_COOKIE, and $_SERVER, and set the value of it in + * the variable $vaule. * - * If $search is not provided, or if it is SQ_INORDER, it will search $_SESSION, - * then $_POST, then $_GET. If $search is SQ_FORM it will search $_POST and - * $_GET. Otherwise, use one of the defined constants to look for a var in one - * place specifically. + * $search must be one of the defined constants below. The default is + * SQ_INORDER. Both SQ_INORDER and SQ_FORM stops on the first match. * - * Note: $search is an int value equal to one of the constants defined above. + * SQ_INORDER searches $_SESSION, then $_POST, and then $_GET. + * SQ_FORM searches $_POST and then $_GET. + * SQ_COOKIE searches $_COOKIE only. + * SQ_GET searches $_GET only. + * SQ_POST searches $_POST only. + * SQ_SERVER searches $_SERVER only. + * SQ_SESSION searches $_SESSION only. * * Example: - * sqgetGlobalVar('username',$username,SQ_SESSION); - * // No quotes around last param, it's a constant - not a string! + * sqgetGlobalVar('username', $username, SQ_SESSION); + * // No quotes around the last parameter, it's a constant - not a string! * * @param string name the name of the var to search * @param mixed value the variable to return @@ -285,66 +296,108 @@ function sqGetGlobalVarMultiple($name, &$value, $indicator_field, * * @return bool whether variable is found. */ -function sqgetGlobalVar($name, &$value, $search = SQ_INORDER, $default = NULL, $typecast = false) { - - $result = false; +function sqgetGlobalVar($name, &$value, $search = SQ_INORDER, $default = NULL, $typecast = FALSE) { + // The return value defaults to FALSE, i.e. the variable wasn't found. + $result = FALSE; + // Search the global variables to find a match. switch ($search) { - /* we want the default case to be first here, - so that if a valid value isn't specified, - all three arrays will be searched. */ - default: - case SQ_INORDER: // check session, post, get - case SQ_SESSION: - if( isset($_SESSION[$name]) ) { - $value = $_SESSION[$name]; - $result = TRUE; - break; - } elseif ( $search == SQ_SESSION ) { - break; - } - case SQ_FORM: // check post, get - case SQ_POST: - if( isset($_POST[$name]) ) { - $value = $_POST[$name]; - $result = TRUE; - break; - } elseif ( $search == SQ_POST ) { - break; - } - case SQ_GET: - if ( isset($_GET[$name]) ) { - $value = $_GET[$name]; - $result = TRUE; + default: + // The default needs to be first here so SQ_INORDER will be used if + // $search isn't a valid constant. + case SQ_INORDER: + // Search $_SESSION, then $_POST, and then $_GET. Stop on the first + // match. + case SQ_SESSION: + if (isset($_SESSION[$name])) { + // If a match is found, set the specified variable to the found + // value, indicate a match, and stop the search. + $value = $_SESSION[$name]; + $result = TRUE; + break; + } elseif ($search == SQ_SESSION) { + // Only stop the search if SQ_SESSION is set. SQ_INORDER will + // continue with the next clause. + break; + } + case SQ_FORM: + // Search $_POST and then $_GET. Stop on the first match. + case SQ_POST: + if (isset($_POST[$name])) { + // If a match is found, set the specified variable to the found + // value, indicate a match, and stop the search. + $value = $_POST[$name]; + $result = TRUE; + break; + } elseif ($search == SQ_POST) { + // Only stop the search if SQ_POST is set. SQ_INORDER and + // SQ_FORM will continue with the next clause. + break; + } + case SQ_GET: + if (isset($_GET[$name])) { + // If a match is found, set the specified variable to the found + // value, indicate a match, and stop the search. + $value = $_GET[$name]; + $result = TRUE; + break; + } + // Stop the search regardless of if SQ_INORDER, SQ_FORM, or SQ_GET + // is set. All three of them ends here. break; - } - /* NO IF HERE. FOR SQ_INORDER CASE, EXIT after GET */ - break; - case SQ_COOKIE: - if ( isset($_COOKIE[$name]) ) { - $value = $_COOKIE[$name]; - $result = TRUE; + case SQ_COOKIE: + if (isset($_COOKIE[$name])) { + // If a match is found, set the specified variable to the found + // value, indicate a match, and stop the search. + $value = $_COOKIE[$name]; + $result = TRUE; + break; + } + // Stop the search. break; - } - break; - case SQ_SERVER: - if ( isset($_SERVER[$name]) ) { - $value = $_SERVER[$name]; - $result = TRUE; + case SQ_SERVER: + if (isset($_SERVER[$name])) { + // If a match is found, set the specified variable to the found + // value, indicate a match, and stop the search. + $value = $_SERVER[$name]; + $result = TRUE; + break; + } + // Stop the search. break; - } - break; } + if ($result && $typecast) { + // Only typecast if it's requested and a match is found. The default is + // not to typecast, which will happen if a valid constant isn't + // specified. switch ($typecast) { - case SQ_TYPE_INT: $value = (int) $value; break; - case SQ_TYPE_STRING: $value = (string) $value; break; - case SQ_TYPE_BOOL: $value = (bool) $value; break; - default: break; + case SQ_TYPE_INT: + // Typecast the value and stop. + $value = (int) $value; + break; + case SQ_TYPE_STRING: + // Typecast the value and stop. + $value = (string) $value; + break; + case SQ_TYPE_BOOL: + // Typecast the value and stop. + $value = (bool) $value; + break; + case SQ_TYPE_BIGINT: + // Typecast the value and stop. + $value = (preg_match('/^[0-9]+$/', $value) ? $value : '0'); + break; + default: + // The default is to do nothing. + break; } } else if (!$result && !is_null($default)) { + // If no match is found and a default value is specified, set it. $value = $default; } + + // Return if a match was found or not. return $result; } @@ -437,9 +490,29 @@ function sqsession_destroy() { global $base_uri, $_COOKIE, $_SESSION; - if (isset($_COOKIE[session_name()]) && session_name()) sqsetcookie(session_name(), $_COOKIE[session_name()], 1, $base_uri); + if (isset($_COOKIE[session_name()]) && session_name()) { + sqsetcookie(session_name(), $_COOKIE[session_name()], 1, $base_uri); + + /* + * Make sure to kill /src and /src/ cookies, just in case there are + * some left-over or malicious ones set in user's browser. + * NB: Note that an attacker could try to plant a cookie for one + * of the /plugins/* directories. Such cookies can block + * access to certain plugin pages, but they do not influence + * or fixate the $base_uri cookie, so we don't worry about + * trying to delete all of them here. + */ + sqsetcookie(session_name(), $_COOKIE[session_name()], 1, $base_uri . 'src'); + sqsetcookie(session_name(), $_COOKIE[session_name()], 1, $base_uri . 'src/'); + } + if (isset($_COOKIE['key']) && $_COOKIE['key']) sqsetcookie('key','SQMTRASH',1,$base_uri); + /* Make sure new session id is generated on subsequent session_start() */ + unset($_COOKIE[session_name()]); + unset($_GET[session_name()]); + unset($_POST[session_name()]); + $sessid = session_id(); if (!empty( $sessid )) { $_SESSION = array(); @@ -516,6 +589,21 @@ function sqsession_start() { function sqsetcookie($sName, $sValue='deleted', $iExpire=0, $sPath="", $sDomain="", $bSecure=false, $bHttpOnly=true, $bReplace=false) { + // some environments can get overwhelmed by an excessive + // setting of the same cookie over and over (e.g., many + // calls to this function via sqsession_is_active() result + // in repeated setting of the session cookie when $bReplace + // is FALSE, but something odd happens (during login only) + // if we change that to default TRUE) ... so we keep our own + // naive per-request name/value cache and only set the cookie + // if its value is changing (or never seen before) + static $cookies = array(); + if (isset($cookies[$sName]) && $cookies[$sName] === $sValue) + return; + else + $cookies[$sName] = $sValue; + + // if we have a secure connection then limit the cookies to https only. global $is_secure_connection; if ($sName && $is_secure_connection) @@ -555,6 +643,7 @@ function sqsetcookie($sName, $sValue='deleted', $iExpire=0, $sPath="", $sDomain= * session_regenerate_id replacement for PHP < 4.3.2 * * This code is borrowed from Gallery, session.php version 1.53.2.1 +FIXME: I saw this code on php.net (in the manual); that's where it comes from originally, but I don't think we need it - it's just redundant to all the hard work we already did seeding the random number generator IMO. I think we can just call to GenerateRandomString() and dump the rest. */ if (!function_exists('session_regenerate_id')) { @@ -596,32 +685,56 @@ if (!function_exists('session_regenerate_id')) { /** * php_self * - * Creates an URL for the page calling this function, using either the PHP global - * REQUEST_URI, or the PHP global PHP_SELF with QUERY_STRING added. Before 1.5.1 - * function was stored in function/strings.php. + * Attempts to determine the path and filename and any arguments + * for the currently executing script. This is usually found in + * $_SERVER['REQUEST_URI'], but some environments may differ, so + * this function tries to standardize this value. + * + * Note that before SquirrelMail version 1.5.1, this function was + * stored in function/strings.php. * - * @return string the complete url for this page * @since 1.2.3 + * @return string The path, filename and any arguments for the + * current script */ -function php_self () { - // PHP 4.4.4 apparently gives the wrong value here - missing the query string - // this code is commented out in the 1.4.x code, so we'll do the same here - //if ( sqgetGlobalVar('REQUEST_URI', $req_uri, SQ_SERVER) && !empty($req_uri) ) { - // return $req_uri; - //} +function php_self() { - if ( sqgetGlobalVar('PHP_SELF', $php_self, SQ_SERVER) && !empty($php_self) ) { + $request_uri = ''; - // need to add query string to end of PHP_SELF to match REQUEST_URI - // - if ( sqgetGlobalVar('QUERY_STRING', $query_string, SQ_SERVER) && !empty($query_string) ) { - $php_self .= '?' . $query_string; - } + // first try $_SERVER['PHP_SELF'], which seems most reliable + // (albeit it usually won't include the query string) + // + $request_uri = ''; + if (!sqgetGlobalVar('PHP_SELF', $request_uri, SQ_SERVER) + || empty($request_uri)) { + + // well, then let's try $_SERVER['REQUEST_URI'] + // + $request_uri = ''; + if (!sqgetGlobalVar('REQUEST_URI', $request_uri, SQ_SERVER) + || empty($request_uri)) { + + // TODO: anyone have any other ideas? maybe $_SERVER['SCRIPT_NAME']??? + // + return ''; + } - return $php_self; } - return ''; + // we may or may not have any query arguments, depending on + // which environment variable was used above, and the PHP + // version, etc., so let's check for it now + // + $query_string = ''; + if (strpos($request_uri, '?') === FALSE + && sqgetGlobalVar('QUERY_STRING', $query_string, SQ_SERVER) + && !empty($query_string)) { + + $request_uri .= '?' . $query_string; + } + + return $request_uri; + } @@ -666,8 +779,8 @@ function sm_print_r() { /** - * Sanitize a value using htmlspecialchars() or similar, but also - * recursively run htmlspecialchars() (or similar) on array keys + * Sanitize a value using sm_encode_html_special_chars() or similar, but also + * recursively run sm_encode_html_special_chars() (or similar) on array keys * and values. * * If $value is not a string or an array with strings in it, @@ -713,7 +826,7 @@ function sq_htmlspecialchars($value, $quote_style=ENT_QUOTES) { if ($quote_style === TRUE) return str_replace(array('\'', '"'), array(''', '"'), $value); else - return htmlspecialchars($value, $quote_style); + return sm_encode_html_special_chars($value, $quote_style); } // anything else gets returned with no changes