Fix HTTPS detection under Windows IIS (#2318118)
authorpdontthink <pdontthink@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Wed, 26 Nov 2008 02:56:42 +0000 (02:56 +0000)
committerpdontthink <pdontthink@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Wed, 26 Nov 2008 02:56:42 +0000 (02:56 +0000)
git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@13336 7612ce4b-ef26-0410-bec9-ea0150e637f0

config/conf.pl
config/config_default.php
functions/global.php
functions/strings.php
include/init.php

index 771289b..9107ba6 100755 (executable)
@@ -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 = <STDIN>;
+    $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 = <STDIN>;
+        }
+    }
+    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 = <STDIN>;
+    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);
index 646e2aa..56f48cf 100644 (file)
@@ -1167,6 +1167,8 @@ $buffer_output = false;
 $buffered_output_handler = '';
 
 /**
+ * Allow Remote configtest Access
+ *
  * Controls remote configuration checks
  * @global boolean $allow_remote_configtest
  * @since 1.5.1
@@ -1174,6 +1176,43 @@ $buffered_output_handler = '';
 $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
  *
  * this disables listing all of the folders on the IMAP Server to
index 7a77c25..acfa062 100644 (file)
@@ -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;
+}
+
+
index 61f88df..1fcbd6d 100644 (file)
@@ -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 = '';
index ba052c6..9f17708 100644 (file)
@@ -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');