From 8f557b942c5a3fb6663c349f4cc7d4a1c8aa4504 Mon Sep 17 00:00:00 2001 From: pdontthink Date: Wed, 26 Nov 2008 02:56:42 +0000 Subject: [PATCH] Fix HTTPS detection under Windows IIS (#2318118) git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@13336 7612ce4b-ef26-0410-bec9-ea0150e637f0 --- config/conf.pl | 69 +++++++++++++++++++++++++++++++++++++++ config/config_default.php | 39 ++++++++++++++++++++++ functions/global.php | 52 +++++++++++++++++++++++++++-- functions/strings.php | 23 ++++--------- include/init.php | 6 ++++ 5 files changed, 170 insertions(+), 19 deletions(-) diff --git a/config/conf.pl b/config/conf.pl index 771289b5..9107ba60 100755 --- a/config/conf.pl +++ b/config/conf.pl @@ -435,6 +435,8 @@ $use_iframe = 'false' if ( !$use_iframe ); $lossy_encoding = 'false' if ( !$lossy_encoding ); $allow_remote_configtest = 'false' if ( !$allow_remote_configtest ); $secured_config = 'true' if ( !$secured_config ); +$sq_https_port = 443 if ( !$sq_https_port ); +$sq_ignore_http_x_forwarded_headers = 'true' if ( !$sq_ignore_http_x_forwarded_headers ); $sm_debug_mode = 'SM_DEBUG_MODE_MODERATE' if ( !$sm_debug_mode ); #FIXME: When this is STABLE software, remove the line above and uncomment the one below: @@ -862,6 +864,8 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) && ( $command ne ":q" ) ) { print "7. Allow remote configtest : $WHT$allow_remote_configtest$NRM\n"; print "8. Debug mode : $WHT$sm_debug_mode$NRM\n"; print "9. Secured configuration mode : $WHT$secured_config$NRM\n"; + print "10. HTTPS port : $WHT$sq_https_port$NRM\n"; + print "11. Ignore HTTP_X_FORWARDED headers: $WHT$sq_ignore_http_x_forwarded_headers$NRM\n"; print "\n"; print "R Return to Main Menu\n"; } @@ -1040,6 +1044,8 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) && ( $command ne ":q" ) ) { elsif ( $command == 7 ) { $allow_remote_configtest = commandB7(); } elsif ( $command == 8 ) { $sm_debug_mode = commandB8(); } elsif ( $command == 9 ) { $secured_config = commandB9(); } + elsif ( $command == 10 ) { $sq_https_port = commandB10(); } + elsif ( $command == 11 ) { $sq_ignore_http_x_forwarded_headers = commandB11(); } } } } @@ -4626,6 +4632,65 @@ sub commandB9 { return $secured_config; } +# Set a (non-standard) HTTPS port +sub commandB10 { + print "If you run HTTPS (SSL-secured HTTP) on a non-standard port, you should\n"; + print "indicate that port here. Even if you do not, SquirrelMail may still\n"; + print "auto-detect secure connections, but it is safer and also very useful\n"; + print "for third party plugins if you specify the port number here.\n"; + print "\n"; + print "Most SquirrelMail administrators will not need to use this setting\n"; + print "because most all web servers use port 443 for HTTPS connections, and\n"; + print "SquirrelMail assumes 443 unless something else is given here.\n"; + print "\n"; + + print "Enter your HTTPS port [$sq_https_port]: "; + my $tmp = ; + $tmp = trim($tmp); + # value is not modified, if user hits Enter or enters space + if ($tmp ne '') { + # make sure that input is numeric + if ($tmp =~ /^\d+$/) { + $sq_https_port = $tmp; + } else { + print "\n"; + print "--- INPUT ERROR ---\n"; + print "\n"; + print "If you want to change this setting, you must enter a number.\n"; + print "If you want to keep the original value, just press Enter.\n\n"; + print "Press Enter to continue..."; + $tmp = ; + } + } + return $sq_https_port; +} + +# Ignore HTTP_X_FORWARDED_* headers? +sub commandB11 { + + if ( lc($sq_ignore_http_x_forwarded_headers) eq 'true' ) { + $default_value = "y"; + } else { + $default_value = "n"; + } + + print "Because HTTP_X_FORWARDED_* headers can be sent by the client and\n"; + print "therefore possibly exploited by an outsider, SquirrelMail ignores\n"; + print "them by default. If a proxy server or other machine sits between\n"; + print "clients and your SquirrelMail server, you can turn this off to\n"; + print "tell SquirrelMail to use such headers.\n"; + print "\n"; + + print "Ignore HTTP_X_FORWARDED headers? (y/n) [$WHT$default_value$NRM]: $WHT"; + $sq_ignore_http_x_forwarded_headers = ; + if ( ( $sq_ignore_http_x_forwarded_headers =~ /^y\n/i ) || ( ( $sq_ignore_http_x_forwarded_headers =~ /^\n/ ) && ( $default_value eq "y" ) ) ) { + $sq_ignore_http_x_forwarded_headers = 'true'; + } else { + $sq_ignore_http_x_forwarded_headers = 'false'; + } + return $sq_ignore_http_x_forwarded_headers; +} + sub save_data { $tab = " "; if ( open( CF, ">config.php" ) ) { @@ -5035,6 +5100,10 @@ sub save_data { # boolean print CF "\$allow_remote_configtest = $allow_remote_configtest;\n"; print CF "\$secured_config = $secured_config;\n"; + # integer + print CF "\$sq_https_port = $sq_https_port;\n"; + # boolean + print CF "\$sq_ignore_http_x_forwarded_headers = $sq_ignore_http_x_forwarded_headers;\n"; # (binary) integer or constant - convert integer # values to constants before output $sm_debug_mode = convert_debug_binary_integer_to_constants($sm_debug_mode); diff --git a/config/config_default.php b/config/config_default.php index 646e2aa4..56f48cfb 100644 --- a/config/config_default.php +++ b/config/config_default.php @@ -1167,12 +1167,51 @@ $buffer_output = false; $buffered_output_handler = ''; /** + * Allow Remote configtest Access + * * Controls remote configuration checks * @global boolean $allow_remote_configtest * @since 1.5.1 */ $allow_remote_configtest = false; +/** + * SquirrelMail Debug Mode + * + * Various debugging levels can be enabled using this setting. + * More than one mode can be used at once by combining them + * with pipes ("|"). See the SM_DEBUG_MODE_* constants in + * include/constants.php + */ +$sm_debug_mode = SM_DEBUG_MODE_OFF; + +/** + * "Secured Configuration" Mode + * + * Enable/disable "Secured Configuration" mode, wherein certain + * security-sensitive configuration settings are made immutable + * by other code. + */ +$secured_config = true; + +/** + * HTTPS Port + * + * This is the HTTPS (SSL-secured HTTP) port. It can be left empty, + * in which case SquirrelMail will assume the standard port 443. + * Make sure to set this correctly when serving HTTPS on a non- + * standard port. + */ +$sq_https_port = 443; + +/** + * Ignore HTTP_X_FORWARDED_* headers? + * + * Whether or not HTTP_X_FORWARDED_* headers are respected by + * SquirrelMail (or plugins). + */ +$sq_ignore_http_x_forwarded_headers = true; + /** * Subscribe Listing Control * diff --git a/functions/global.php b/functions/global.php index 7a77c256..acfa0625 100644 --- a/functions/global.php +++ b/functions/global.php @@ -517,9 +517,9 @@ function sqsetcookie($sName, $sValue='deleted', $iExpire=0, $sPath="", $sDomain= $bSecure=false, $bHttpOnly=true, $bReplace=false) { // if we have a secure connection then limit the cookies to https only. - if ($sName && isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']) { + global $is_secure_connection; + if ($sName && $is_secure_connection) $bSecure = true; - } // admin config can override the restriction of secure-only cookies global $only_secure_cookies; @@ -721,3 +721,51 @@ function sq_htmlspecialchars($value, $quote_style=ENT_QUOTES) { } +/** + * Detect whether or not we have a SSL secured (HTTPS) connection + * connection to the browser + * + * It is thought to be so if you have 'SSLOptions +StdEnvVars' + * in your Apache configuration, + * OR if you have HTTPS set to a non-empty value (except "off") + * in your HTTP_SERVER_VARS, + * OR if you have HTTP_X_FORWARDED_PROTO=https in your HTTP_SERVER_VARS, + * OR if you are on port 443. + * + * Note: HTTP_X_FORWARDED_PROTO could be sent from the client and + * therefore possibly spoofed/hackable. Thus, SquirrelMail + * ignores such headers by default. The administrator + * can tell SM to use such header values by setting + * $sq_ignore_http_x_forwarded_headers to boolean FALSE + * in config/config.php or by using config/conf.pl. + * + * Note: It is possible to run SSL on a port other than 443, and + * if that is the case, the administrator should set + * $sq_https_port in config/config.php or by using config/conf.pl. + * + * @return boolean TRUE if the current connection is SSL-encrypted; + * FALSE otherwise. + * + * @since 1.4.17 and 1.5.2 + * + */ +function is_ssl_secured_connection() +{ + global $sq_ignore_http_x_forwarded_headers, $sq_https_port; + $https_env_var = getenv('HTTPS'); + if ($sq_ignore_http_x_forwarded_headers + || !sqgetGlobalVar('HTTP_X_FORWARDED_PROTO', $forwarded_proto, SQ_SERVER)) + $forwarded_proto = ''; + if (empty($sq_https_port)) // won't work with port 0 (zero) + $sq_https_port = 443; + if ((isset($https_env_var) && strcasecmp($https_env_var, 'on') === 0) + || (sqgetGlobalVar('HTTPS', $https, SQ_SERVER) && !empty($https) + && strcasecmp($https, 'off') !== 0) + || (strcasecmp($forwarded_proto, 'https') === 0) + || (sqgetGlobalVar('SERVER_PORT', $server_port, SQ_SERVER) + && $server_port == $sq_https_port)) + return TRUE; + return FALSE; +} + + diff --git a/functions/strings.php b/functions/strings.php index 61f88dfa..1fcbd6dc 100644 --- a/functions/strings.php +++ b/functions/strings.php @@ -470,7 +470,8 @@ function readShortMailboxName($haystack, $needle) { */ function get_location () { - global $imap_server_type, $config_location_base; + global $imap_server_type, $config_location_base, + $is_secure_connection, $sq_ignore_http_x_forwarded_headers; /* Get the path, handle virtual directories */ if(strpos(php_self(), '?')) { @@ -492,25 +493,13 @@ function get_location () { /* Check if this is a HTTPS or regular HTTP request. */ $proto = 'http://'; - - /* - * If you have 'SSLOptions +StdEnvVars' in your apache config - * OR if you have HTTPS=on in your HTTP_SERVER_VARS - * OR if you have HTTP_X_FORWARDED_PROTO=https in your HTTP_SERVER_VARS - * OR if you are on port 443 - */ - $getEnvVar = getenv('HTTPS'); - if (!sqgetGlobalVar('HTTP_X_FORWARDED_PROTO', $forwarded_proto, SQ_SERVER)) - $forwarded_proto = ''; - if ((isset($getEnvVar) && strcasecmp($getEnvVar, 'on') === 0) || - (sqgetGlobalVar('HTTPS', $https_on, SQ_SERVER) && strcasecmp($https_on, 'on') === 0) || - (strcasecmp($forwarded_proto, 'https') === 0) || - (sqgetGlobalVar('SERVER_PORT', $server_port, SQ_SERVER) && $server_port == 443)) { + if ($is_secure_connection) $proto = 'https://'; - } /* Get the hostname from the Host header or server config. */ - if ( !sqgetGlobalVar('HTTP_X_FORWARDED_HOST', $host, SQ_SERVER) || empty($host) ) { + if ($sq_ignore_http_x_forwarded_headers + || !sqgetGlobalVar('HTTP_X_FORWARDED_HOST', $host, SQ_SERVER) + || empty($host)) { if ( !sqgetGlobalVar('HTTP_HOST', $host, SQ_SERVER) || empty($host) ) { if ( !sqgetGlobalVar('SERVER_NAME', $host, SQ_SERVER) || empty($host) ) { $host = ''; diff --git a/include/init.php b/include/init.php index ba052c63..9f17708e 100644 --- a/include/init.php +++ b/include/init.php @@ -235,6 +235,12 @@ if ($sm_debug_mode & SM_DEBUG_MODE_STRICT) error_reporting($error_level); +/** + * Detect SSL connections + */ +$is_secure_connection = is_ssl_secured_connection(); + + require(SM_PATH . 'functions/plugin.php'); require(SM_PATH . 'include/languages.php'); require(SM_PATH . 'class/template/Template.class.php'); -- 2.25.1