Fix XSS problem with unsanitized style tags in messages [CVE-2011-2023]
[squirrelmail.git] / src / configtest.php
index 99cfdb57edef0240722469824591a2de643a26df..2cac584c21518e34f41cbc8b4e14e0457f7ffdd3 100644 (file)
@@ -3,7 +3,7 @@
 /**
  * SquirrelMail configtest script
  *
- * @copyright © 2003-2007 The SquirrelMail Project Team
+ * @copyright 2003-2011 The SquirrelMail Project Team
  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  * @version $Id$
  * @package squirrelmail
@@ -21,7 +21,10 @@ define('PAGE_NAME', 'configtest');
 // This script could really use some restructuring as it has grown quite rapidly
 // but is not very 'clean'. Feel free to get some structure into this thing.
 
-/** force verbose error reporting and turn on display of errors */
+// force verbose error reporting and turn on display of errors, but not before
+// getting their original values
+$php_display_errors_original_value = ini_get('display_errors');
+$php_error_reporting_original_value = ini_get('error_reporting');
 error_reporting(E_ALL);
 ini_set('display_errors',1);
 
@@ -87,6 +90,7 @@ define('SM_PATH', '../');
 require(SM_PATH . 'include/constants.php');
 require(SM_PATH . 'functions/global.php');
 require(SM_PATH . 'functions/strings.php');
+require(SM_PATH . 'functions/files.php');
 $SQM_INTERNAL_VERSION = explode('.', SM_VERSION, 3);
 $SQM_INTERNAL_VERSION[2] = intval($SQM_INTERNAL_VERSION[2]);
 
@@ -116,6 +120,12 @@ if (file_exists(SM_PATH . 'config/config_local.php')) {
     require(SM_PATH . 'config/config_local.php');
 }
 
+/**
+ * Include Compatibility plugin if available.
+ */
+if (!$disable_plugins && file_exists(SM_PATH . 'plugins/compatibility/functions.php'))
+    include_once(SM_PATH . 'plugins/compatibility/functions.php');
+
 /** Load plugins */
 global $disable_plugins;
 $squirrelmail_plugin_hooks = array();
@@ -196,12 +206,39 @@ if(!check_php_version(4,1,0)) {
 
 echo $IND . 'PHP version ' . PHP_VERSION . ' OK. (You have: ' . phpversion() . ". Minimum: 4.1.0)<br />\n";
 
-echo $IND . 'display_errors: ' . ini_get('display_errors') . "<br />\n";
-
-echo $IND . 'error_reporting: ' . ini_get('error_reporting') . "<br />\n";
+// try to determine information about the user and group the web server is running as
+//
+$webOwnerID = 'N/A';
+$webOwnerInfo = array('name' => 'N/A');
+if (function_exists('posix_getuid'))
+    $webOwnerID = posix_getuid();
+if ($webOwnerID === FALSE)
+    $webOwnerID = 'N/A';
+if ($webOwnerID !== 'N/A' && function_exists('posix_getpwuid'))
+    $webOwnerInfo = posix_getpwuid($webOwnerID);
+if (!$webOwnerInfo)
+    $webOwnerInfo = array('name' => 'N/A');
+$webGroupID = 'N/A';
+$webGroupInfo = array('name' => 'N/A');
+if (function_exists('posix_getgid'))
+    $webGroupID = posix_getgid();
+if ($webGroupID === FALSE)
+    $webGroupID = 'N/A';
+if ($webGroupID !== 'N/A' && function_exists('posix_getgrgid'))
+    $webGroupInfo = posix_getgrgid($webGroupID);
+if (!$webGroupInfo)
+    $webGroupInfo = array('name' => 'N/A');
+
+echo $IND . 'Running as ' . $webOwnerInfo['name'] . '(' . $webOwnerID
+          . ') / ' . $webGroupInfo['name'] . '(' . $webGroupID . ")<br />\n";
+
+echo $IND . 'display_errors: ' . $php_display_errors_original_value . " (overridden with 1 for this page only)<br />\n";
+
+echo $IND . 'error_reporting: ' . $php_error_reporting_original_value . " (overridden with 2047 for this page only)<br />\n";
 
 $safe_mode = ini_get('safe_mode');
 if ($safe_mode) {
+    //FIXME: should show that safe_mode is off when it is (this only shows the safe_mode setting when it's on) (also might be generally helpful to show things like open_basedir, too or even add phpinfo() output or a link to another script that has phpinfo()
     echo $IND . 'safe_mode: ' . $safe_mode;
     if (empty($prefs_dsn) || empty($addrbook_dsn))
         echo ' (<font color="red">double check data and attachment directory ownership, etc!</font>)';
@@ -313,6 +350,17 @@ if (ini_get('short_open_tag') == 0) {
     do_err($short_open_tag_warning, false);
 }
 
+
+/* check who the web server is running as if possible */
+
+if ($process_info = get_process_owner_info()) {
+    echo $IND . 'Web server is running as user: ' . $process_info['name'] . ' (' . $process_info['uid'] . ")<br />\n";
+    //echo $IND . 'Web server is running as effective user: ' . $process_info['ename'] . ' (' . $process_info['euid'] . ")<br />\n";
+    echo $IND . 'Web server is running as group: ' . $process_info['group'] . ' (' . $process_info['gid'] . ")<br />\n";
+    //echo $IND . 'Web server is running as effective group: ' . $process_info['egroup'] . ' (' . $process_info['egid'] . ")<br />\n";
+}
+
+
 /* checking paths */
 
 echo "Checking paths...<br />\n";
@@ -336,7 +384,7 @@ if(!isset($data_dir_error) && !is_dir($data_dir)) {
     }
 }
 // datadir should be executable - but no clean way to test on that
-if(!isset($data_dir_error) && !is_writable($data_dir)) {
+if(!isset($data_dir_error) && !sq_is_writable($data_dir)) {
     if (!empty($prefs_dsn)) {
         $data_dir_error = "Data dir ($data_dir) is not writable!\n";
         echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
@@ -364,7 +412,7 @@ if($data_dir == $attachment_dir) {
     if (!is_dir($attachment_dir)) {
         do_err("Attachment dir ($attachment_dir) is not a directory!");
     }
-    if (!is_writable($attachment_dir)) {
+    if (!sq_is_writable($attachment_dir)) {
         do_err("I cannot write to attachment dir ($attachment_dir)!");
     }
     echo $IND . "Attachment dir OK.<br />\n";
@@ -411,27 +459,61 @@ if (isset($plugins[0])) {
         if(!file_exists(SM_PATH .'plugins/'.$plugin)) {
             do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot find it.', FALSE);
         } elseif (!is_readable(SM_PATH .'plugins/'.$plugin.'/setup.php')) {
-            do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot read its setup.php file.', FALSE);
+            do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot locate or read its setup.php file.', FALSE);
         } elseif (in_array($plugin, $bad_plugins)) {
             do_err('You have enabled the <i>'.$plugin.'</i> plugin, which causes problems with this version of SquirrelMail. Please check the ReleaseNotes or other documentation for more information.', false);
         }
     }
+
+
     // load plugin functions
     include_once(SM_PATH . 'functions/plugin.php');
+
     // turn on output buffering in order to prevent output of new lines
     ob_start();
     foreach ($plugins as $name) {
         use_plugin($name);
+
+        // get output and remove whitespace
+        $output = trim(ob_get_contents());
+
+        // if plugin outputs more than newlines and spacing, stop script execution.
+        if (!empty($output)) {
+            $plugin_load_error = 'Some output was produced when plugin <i>' . $name . '</i> was loaded.  Usually this means there is an error in the plugin\'s setup or configuration file.  The output was: '.htmlspecialchars($output);
+            do_err($plugin_load_error);
+        }
     }
-    // get output and remove whitespace
-    $output = trim(ob_get_contents());
     ob_end_clean();
-    // if plugins output more than newlines and spacing, stop script execution.
-    if (!empty($output)) {
-//FIXME: if the output buffer is checked INSIDE the foreach loop above, we can tell the user WHICH plugin has the problem - seems like a good idea
-        $plugin_load_error = 'Some output is produced when plugins are loaded. Usually this means there is an error in one of the plugin setup or configuration files. The output was: '.htmlspecialchars($output);
-        do_err($plugin_load_error);
+
+
+    /**
+     * Check the contents of the static plugin hooks array file against
+     * the plugin setup file, which may have changed in an upgrade, etc.
+     * This helps remind admins to re-run the configuration utility when
+     * a plugin has been changed or upgraded.
+     */
+    $static_squirrelmail_plugin_hooks = $squirrelmail_plugin_hooks;
+    $squirrelmail_plugin_hooks = array();
+    foreach ($plugins as $name) {
+        $function = "squirrelmail_plugin_init_$name";
+        if (function_exists($function)) {
+            $function();
+
+            // now iterate through each hook and make sure the
+            // plugin is registered on the correct ones in the
+            // static plugin configuration file
+            //
+            foreach ($squirrelmail_plugin_hooks as $hook_name => $hooked_plugins)
+                foreach ($hooked_plugins as $hooked_plugin => $hooked_function)
+                    if ($hooked_plugin == $name
+                     && (empty($static_squirrelmail_plugin_hooks[$hook_name][$hooked_plugin])
+                      || $static_squirrelmail_plugin_hooks[$hook_name][$hooked_plugin] != $hooked_function))
+                        do_err('The plugin <i>' . $name . '</i> is supposed to be registered on the <i>' . $hook_name . '</i> hook, but it is not.  You need to re-run the configuration utility and re-save your configuration file.', FALSE);
+        }
     }
+    $squirrelmail_plugin_hooks = $static_squirrelmail_plugin_hooks;
+
+
     /**
      * Print plugin versions
      */
@@ -450,13 +532,21 @@ if (isset($plugins[0])) {
         }
         else if (is_array($failed_dependencies)) {
             $missing_plugins = '';
+            $incompatible_plugins = '';
             foreach ($failed_dependencies as $depend_name => $depend_requirements) {
-                $missing_plugins .= ', ' . $depend_name . ' (version ' . $depend_requirements['version'] . ', ' . ($depend_requirements['activate'] ? 'must be activated' : 'need not be activated') . ')';
+                if ($depend_requirements['version'] == SQ_INCOMPATIBLE)
+                    $incompatible_plugins .= ', ' . $depend_name;
+                else
+                    $missing_plugins .= ', ' . $depend_name . ' (version ' . $depend_requirements['version'] . ', ' . ($depend_requirements['activate'] ? 'must be activated' : 'need not be activated') . ')';
             }
-            do_err($name . ' is missing some dependencies: ' . trim($missing_plugins, ', '), FALSE);
+            $error_string = (!empty($incompatible_plugins) ? $name . ' cannot be activated at the same time as the following plugins: ' . trim($incompatible_plugins, ', ') : '')
+                          . (!empty($missing_plugins) ? (!empty($incompatible_plugins) ? '.  ' . $name . ' is also ' : $name . ' is ') . 'missing some dependencies: ' . trim($missing_plugins, ', ') : '');
+            do_err($error_string, FALSE);
         }
 
     }
+
+
     /**
      * This hook was added in 1.5.2 and 1.4.10. Each plugins should print an error
      * message and return TRUE if there are any errors in its setup/configuration.
@@ -559,8 +649,17 @@ if($useSendmail) {
     if ($use_smtp_tls===2) {
         // if something breaks, script should close smtp connection on exit.
 
+
+        // format EHLO argument correctly if needed
+        //
+        if (preg_match('/^\d+\.\d+\.\d+\.\d+$/', $client_ip))
+            $helohost = '[' . $client_ip . ']';
+        else // some day might add IPv6 here
+            $helohost = $client_ip;
+
+
         // say helo
-        fwrite($stream,"EHLO $client_ip\r\n");
+        fwrite($stream,"EHLO $helohost\r\n");
 
         $ehlo=array();
         $ehlo_error = false;
@@ -612,15 +711,16 @@ if($useSendmail) {
 
     /* POP before SMTP */
     if($pop_before_smtp) {
-        $stream = fsockopen($smtpServerAddress, 110, $err_no, $err_str);
+        if (empty($pop_before_smtp_host)) $pop_before_smtp_host = $smtpServerAddress;
+        $stream = fsockopen($pop_before_smtp_host, 110, $err_no, $err_str);
         if (!$stream) {
-            do_err("Error connecting to POP Server ($smtpServerAddress:110) "
+            do_err("Error connecting to POP Server ($pop_before_smtp_host:110) "
                 . $err_no . ' : ' . htmlspecialchars($err_str));
         }
 
         $tmp = fgets($stream, 1024);
         if (substr($tmp, 0, 3) != '+OK') {
-            do_err("Error connecting to POP Server ($smtpServerAddress:110)"
+            do_err("Error connecting to POP Server ($pop_before_smtp_host:110)"
                 . ' '.htmlspecialchars($tmp));
         }
         fputs($stream, 'QUIT');
@@ -917,7 +1017,7 @@ if( empty($ldap_server) ) {
                 if ( empty($param['binddn']) ) {
                     $bind = @ldap_bind($linkid);
                 } else {
-                    $bind = @ldap_bind($param['binddn'], $param['bindpw']);
+                    $bind = @ldap_bind($linkid, $param['binddn'], $param['bindpw']);
                 }
 
                 if ( $bind ) {