Minor adjustments to variable_orders & gpc_order checks. "Special thanks" to Tomas...
[squirrelmail.git] / src / configtest.php
CommitLineData
d1ae9d4c 1<?php
134e4174 2
30967a1e 3/**
d1ae9d4c 4 * SquirrelMail configtest script
5 *
4b5049de 6 * @copyright &copy; 2003-2007 The SquirrelMail Project Team
4b4abf93 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
30967a1e 8 * @version $Id$
9 * @package squirrelmail
10 * @subpackage config
d1ae9d4c 11 */
12
13/************************************************************
14 * NOTE: you do not need to change this script! *
15 * If it throws errors you need to adjust your config. *
16 ************************************************************/
17
df758744 18// This script could really use some restructuring as it has grown quite rapidly
19// but is not very 'clean'. Feel free to get some structure into this thing.
20
dda39a1a 21/** force verbose error reporting and turn on display of errors */
22error_reporting(E_ALL);
23ini_set('display_errors',1);
24
25/** Blockcopy from init.php. Cleans globals. */
26if ((bool) ini_get('register_globals') &&
27 strtolower(ini_get('register_globals'))!='off') {
28 /**
29 * Remove all globals that are not reserved by PHP
30 * 'value' and 'key' are used by foreach. Don't unset them inside foreach.
31 */
32 foreach ($GLOBALS as $key => $value) {
33 switch($key) {
34 case 'HTTP_POST_VARS':
35 case '_POST':
36 case 'HTTP_GET_VARS':
37 case '_GET':
38 case 'HTTP_COOKIE_VARS':
39 case '_COOKIE':
40 case 'HTTP_SERVER_VARS':
41 case '_SERVER':
42 case 'HTTP_ENV_VARS':
43 case '_ENV':
44 case 'HTTP_POST_FILES':
45 case '_FILES':
46 case '_REQUEST':
47 case 'HTTP_SESSION_VARS':
48 case '_SESSION':
49 case 'GLOBALS':
50 case 'key':
51 case 'value':
52 break;
53 default:
54 unset($GLOBALS[$key]);
55 }
56 }
57 // Unset variables used in foreach
58 unset($GLOBALS['key']);
59 unset($GLOBALS['value']);
60}
61
62
63/**
64 * Displays error messages and warnings
65 * @param string $str message
66 * @param boolean $fatal fatal error or only warning
67 */
3a196538 68function do_err($str, $fatal = TRUE) {
f084f987 69 global $IND, $warnings;
70 $level = $fatal ? 'FATAL ERROR:' : 'WARNING:';
3a196538 71 echo '<p>'.$IND.'<font color="red"><b>' . $level . '</b></font> ' .$str. "</p>\n";
72 if($fatal) {
f084f987 73 echo '</body></html>';
74 exit;
3a196538 75 } else {
f084f987 76 $warnings++;
77 }
5b53b7e0 78}
79
5b53b7e0 80ob_implicit_flush();
30967a1e 81/** @ignore */
5b53b7e0 82define('SM_PATH', '../');
dda39a1a 83/** load minimal function set */
b37e457f 84require(SM_PATH . 'include/constants.php');
dda39a1a 85require(SM_PATH . 'functions/global.php');
86require(SM_PATH . 'functions/strings.php');
a895042a 87$SQM_INTERNAL_VERSION = explode('.', SM_VERSION, 3);
b37e457f 88$SQM_INTERNAL_VERSION[2] = intval($SQM_INTERNAL_VERSION[2]);
5b53b7e0 89
dda39a1a 90/** set default value in order to block remote access */
d0184454 91$allow_remote_configtest=false;
92
dda39a1a 93/** Load all configuration files before output begins */
94
95/* load default configuration */
96require(SM_PATH . 'config/config_default.php');
97/* reset arrays in default configuration */
98$ldap_server = array();
99$plugins = array();
100$fontsets = array();
101$theme = array();
102$theme[0]['PATH'] = SM_PATH . 'themes/default_theme.php';
103$theme[0]['NAME'] = 'Default';
104$aTemplateSet = array();
105$aTemplateSet[0]['ID'] = 'default';
106$aTemplateSet[0]['NAME'] = 'Default';
107/* load site configuration */
5b53b7e0 108if (file_exists(SM_PATH . 'config/config.php')) {
dda39a1a 109 require(SM_PATH . 'config/config.php');
5b53b7e0 110}
dda39a1a 111/* load local configuration overrides */
112if (file_exists(SM_PATH . 'config/config_local.php')) {
113 require(SM_PATH . 'config/config_local.php');
114}
115
8459a9bb 116/** Load plugins */
117global $disable_plugins;
118$squirrelmail_plugin_hooks = array();
119if (!$disable_plugins && file_exists(SM_PATH . 'config/plugin_hooks.php')) {
120 require(SM_PATH . 'config/plugin_hooks.php');
121}
122
dda39a1a 123/** Warning counter */
124$warnings = 0;
125
126/** indent */
127$IND = str_repeat('&nbsp;',4);
c772f125 128
69792446 129/**
130 * get_location starts session and must be run before output is started.
131 */
132$test_location = get_location();
133
151562a7 134?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
135 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
d1ae9d4c 136<html>
137<head>
f084f987 138 <meta name="robots" content="noindex,nofollow">
139 <title>SquirrelMail configtest</title>
d1ae9d4c 140</head>
141<body>
142<h1>SquirrelMail configtest</h1>
143
144<p>This script will try to check some aspects of your SquirrelMail configuration
145and point you to errors whereever it can find them. You need to go run <tt>conf.pl</tt>
d18703d3 146in the <tt>config/</tt> directory first before you run this script.</p>
d1ae9d4c 147
148<?php
149
d1ae9d4c 150$included = array_map('basename', get_included_files() );
151if(!in_array('config.php', $included)) {
152 if(!file_exists(SM_PATH . 'config/config.php')) {
153 do_err('Config file '.SM_PATH . 'config/config.php does not exist!<br />'.
f084f987 154 'You need to run <tt>conf.pl</tt> first.');
d1ae9d4c 155 }
156 do_err('Could not read '.SM_PATH.'config/config.php! Check file permissions.');
157}
158if(!in_array('strings.php', $included)) {
159 do_err('Could not include '.SM_PATH.'functions/strings.php!<br />'.
f084f987 160 'Check permissions on that file.');
d1ae9d4c 161}
162
d0184454 163/* Block remote use of script */
164if (! $allow_remote_configtest) {
165 sqGetGlobalVar('REMOTE_ADDR',$client_ip,SQ_SERVER);
a15f9d93 166 sqGetGlobalVar('SERVER_ADDR',$server_ip,SQ_SERVER);
167
168 if ((! isset($client_ip) || $client_ip!='127.0.0.1') &&
f084f987 169 (! isset($client_ip) || ! isset($server_ip) || $client_ip!=$server_ip)) {
f8a1ed5a 170 do_err('Enable "Allow remote configtest" option in squirrelmail configuration in order to use this script.');
d0184454 171 }
172}
d1ae9d4c 173
b37e457f 174echo "<p><table>\n<tr><td>SquirrelMail version:</td><td><b>" . SM_VERSION . "</b></td></tr>\n" .
f084f987 175 '<tr><td>Config file version:</td><td><b>' . $config_version . "</b></td></tr>\n" .
176 '<tr><td>Config file last modified:</td><td><b>' .
177 date ('d F Y H:i:s', filemtime(SM_PATH . 'config/config.php')) .
178 "</b></td></tr>\n</table>\n</p>\n\n";
d1ae9d4c 179
c3da9f50 180/* check $config_version */
65efa982 181if ($config_version!='1.5.0') {
c3da9f50 182 do_err('Configuration file version does not match required version. Please update your configuration file.');
183}
a15f9d93 184
a1912bbc 185
186/* checking PHP specs */
187
d1ae9d4c 188echo "Checking PHP configuration...<br />\n";
189
abd74f7d 190if(!check_php_version(4,1,0)) {
191 do_err('Insufficient PHP version: '. PHP_VERSION . '! Minimum required: 4.1.0');
d1ae9d4c 192}
193
3a196538 194echo $IND . 'PHP version ' . PHP_VERSION . ' OK. (You have: ' . phpversion() . ". Minimum: 4.1.0)<br />\n";
a1912bbc 195
196/* register_globals check: test for boolean false and any string that is not equal to 'off' */
197
a3b99374 198if ((bool) ini_get('register_globals') &&
199 strtolower(ini_get('register_globals'))!='off') {
dda39a1a 200 do_err('You have register_globals turned on. This is not an error, but it CAN be a security hazard. Consider turning register_globals off.', false);
c772f125 201}
a1912bbc 202
203
204/* variables_order check */
205
206// FIXME(?): Hmm, how do we distinguish between when an ini setting is
207// not available (ini_set() returns empty string) and when
208// the administrator set the value to an empty string? The
209// latter is sure to be highly rare, so for now, just assume
210// that empty value means the setting isn't even available
211// (could also check PHP version when this setting was implemented)
47fa8e9b 212// although, we'll also warn the user if it is empty, with
213// a non-fatal error
214$variables_order = strtoupper(ini_get('variables_order'));
215if (empty($variables_order))
216 do_err('Your variables_order setting seems to be empty. Make sure it is undefined in any PHP ini files, .htaccess files, etc. and not specifically set to an empty value or SquirrelMail may not function correctly', false);
217else if (strpos($variables_order, 'G') === FALSE
a1912bbc 218 || strpos($variables_order, 'P') === FALSE
219 || strpos($variables_order, 'C') === FALSE
47fa8e9b 220 || strpos($variables_order, 'S') === FALSE) {
221 do_err('Your variables_order setting is insufficient for SquirrelMail to function. It needs at least "GPCS", but you have it set to "' . htmlspecialchars($variables_order) . '"', true);
a1912bbc 222} else {
223 echo $IND . "variables_order OK: $variables_order.<br />\n";
224}
225
226
47fa8e9b 227/* gpc_order check (removed from PHP as of v5.0) */
228
229if (!check_php_version(5)) {
230 // FIXME(?): Hmm, how do we distinguish between when an ini setting is
231 // not available (ini_set() returns empty string) and when
232 // the administrator set the value to an empty string? The
233 // latter is sure to be highly rare, so for now, just assume
234 // that empty value means the setting isn't even available
235 // (could also check PHP version when this setting was implemented)
236 // although, we'll also warn the user if it is empty, with
237 // a non-fatal error
238 $gpc_order = strtoupper(ini_get('gpc_order'));
239 if (empty($gpc_order))
240 do_err('Your gpc_order setting seems to be empty. Make sure it is undefined in any PHP ini files, .htaccess files, etc. and not specifically set to an empty value or SquirrelMail may not function correctly', false);
241 else if (strpos($gpc_order, 'G') === FALSE
242 || strpos($gpc_order, 'P') === FALSE
243 || strpos($gpc_order, 'C') === FALSE) {
244 do_err('Your gpc_order setting is insufficient for SquirrelMail to function. It needs to be set to "GPC", but you have it set to "' . htmlspecialchars($gpc_order) . '"', true);
245 } else {
246 echo $IND . "gpc_order OK: $gpc_order.<br />\n";
247 }
a1912bbc 248}
249
250
251/* check PHP extensions */
252
d1ae9d4c 253$php_exts = array('session','pcre');
254$diff = array_diff($php_exts, get_loaded_extensions());
255if(count($diff)) {
256 do_err('Required PHP extensions missing: '.implode(', ',$diff) );
257}
258
17fca61d 259echo $IND . "PHP extensions OK.<br />\n";
d1ae9d4c 260
8f186a2a 261/* dangerous php settings */
262/**
263 * mbstring.func_overload allows to replace original string and regexp functions
264 * with their equivalents from php mbstring extension. It causes problems when
d0184454 265 * scripts analyze 8bit strings byte after byte or use 8bit strings in regexp tests.
9211bcef 266 * Setting can be controlled in php.ini (php 4.2.0), webserver config (php 4.2.0)
8f186a2a 267 * and .htaccess files (php 4.3.5).
268 */
269if (function_exists('mb_internal_encoding') &&
9211bcef 270 check_php_version(4,2,0) &&
8f186a2a 271 (int)ini_get('mbstring.func_overload')!=0) {
272 $mb_error='You have enabled mbstring overloading.'
273 .' It can cause problems with SquirrelMail scripts that rely on single byte string functions.';
274 do_err($mb_error);
275}
d1ae9d4c 276
99c1c0d6 277/**
278 * Do not use SquirrelMail with magic_quotes_* on.
279 */
280if ( get_magic_quotes_runtime() || get_magic_quotes_gpc() ||
281 ( (bool) ini_get('magic_quotes_sybase') && ini_get('magic_quotes_sybase') != 'off' )
282 ) {
283 $magic_quotes_warning='You have enabled any one of <tt>magic_quotes_runtime</tt>, '
284 .'<tt>magic_quotes_gpc</tt> or <tt>magic_quotes_sybase</tt> in your PHP '
285 .'configuration. We recommend all those settings to be off. SquirrelMail '
286 .'may work with them on, but when experiencing stray backslashes in your mail '
287 .'or other strange behaviour, it may be advisable to turn them off.';
288 do_err($magic_quotes_warning,false);
289}
290
291
d1ae9d4c 292/* checking paths */
293
294echo "Checking paths...<br />\n";
295
296if(!file_exists($data_dir)) {
d0184454 297 // data_dir is not that important in db_setups.
298 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
299 $data_dir_error = "Data dir ($data_dir) does not exist!\n";
300 echo $IND .'<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
301 } else {
302 do_err("Data dir ($data_dir) does not exist!");
303 }
91e0dccc 304}
d0184454 305// don't check if errors
306if(!isset($data_dir_error) && !is_dir($data_dir)) {
307 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
308 $data_dir_error = "Data dir ($data_dir) is not a directory!\n";
309 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
310 } else {
311 do_err("Data dir ($data_dir) is not a directory!");
312 }
91e0dccc 313}
d4eaadbe 314// datadir should be executable - but no clean way to test on that
d0184454 315if(!isset($data_dir_error) && !is_writable($data_dir)) {
316 if (isset($prefs_dsn) && ! empty($prefs_dsn)) {
317 $data_dir_error = "Data dir ($data_dir) is not writable!\n";
318 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
319 } else {
320 do_err("Data dir ($data_dir) is not writable!");
321 }
d1ae9d4c 322}
323
d0184454 324if (isset($data_dir_error)) {
325 echo " Some plugins might need access to data directory.<br />\n";
326} else {
327 // todo_ornot: actually write something and read it back.
328 echo $IND . "Data dir OK.<br />\n";
329}
d1ae9d4c 330
331if($data_dir == $attachment_dir) {
332 echo $IND . "Attachment dir is the same as data dir.<br />\n";
d0184454 333 if (isset($data_dir_error)) {
334 do_err($data_dir_error);
335 }
d1ae9d4c 336} else {
337 if(!file_exists($attachment_dir)) {
338 do_err("Attachment dir ($attachment_dir) does not exist!");
91e0dccc 339 }
d1ae9d4c 340 if (!is_dir($attachment_dir)) {
341 do_err("Attachment dir ($attachment_dir) is not a directory!");
91e0dccc 342 }
d1ae9d4c 343 if (!is_writable($attachment_dir)) {
344 do_err("I cannot write to attachment dir ($attachment_dir)!");
345 }
346 echo $IND . "Attachment dir OK.<br />\n";
347}
348
349
646b17e0 350echo "Checking plugins...<br />\n";
351
d1ae9d4c 352/* check plugins and themes */
99a44bdc 353//FIXME: check requirements given in plugin _info() function, such
354// as required PHP extensions, Pear packages, other plugins, SM version, etc
355// see development docs for list of returned info from that function
f084f987 356$bad_plugins = array(
0880efc9 357 'attachment_common', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 358 'auto_prune_sent', // Obsolete: See Proon Automatic Folder Pruning plugin
0880efc9 359 'compose_new_window', // Integrated into SquirrelMail 1.4 core
360 'delete_move_next', // Integrated into SquirrelMail 1.5 core
eb7bd9b7 361 'disk_quota', // Obsolete: See Check Quota plugin
0880efc9 362 'email_priority', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 363 'emoticons', // Obsolete: See HTML Mail plugin
0880efc9 364 'focus_change', // Integrated into SquirrelMail 1.2 core
365 'folder_settings', // Integrated into SquirrelMail 1.5.1 core
366 'global_sql_addressbook', // Integrated into SquirrelMail 1.4 core
eb7bd9b7 367 'hancock', // Not Working: See Random Signature Taglines plugin
0880efc9 368 'msg_flags', // Integrated into SquirrelMail 1.5.1 core
369 'message_source', // Added to SquirrelMail 1.4 Core Plugins (message_details)
370 'motd', // Integrated into SquirrelMail 1.2 core
371 'paginator', // Integrated into SquirrelMail 1.2 core
372 'printer_friendly', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 373 'procfilter', // Obsolete: See Server Side Filter plugin
0880efc9 374 'redhat_php_cgi_fix', // Integrated into SquirrelMail 1.1.1 core
375 'send_to_semicolon', // Integrated into SquirrelMail 1.4.1 core
376 'spamassassin', // Not working beyond SquirrelMail 1.2.7: See Spamassassin SpamFilter (Frontend) v2 plugin
377 'sqcalendar', // Added to SquirrelMail 1.2 Core Plugins (calendar)
378 'sqclock', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 379 'sql_squirrel_logger', // Obsolete: See Squirrel Logger plugin
380 'tmda', // Obsolete: See TMDA Tools plugin
381 'vacation', // Obsolete: See Vacation Local plugin
0880efc9 382 'view_as_html', // Integrated into SquirrelMail 1.5.1 core
383 'xmailer' // Integrated into SquirrelMail 1.2 core
f084f987 384 );
3a196538 385
5b53b7e0 386if (isset($plugins[0])) {
387 foreach($plugins as $plugin) {
388 if(!file_exists(SM_PATH .'plugins/'.$plugin)) {
f084f987 389 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot find it.', FALSE);
5b53b7e0 390 } elseif (!is_readable(SM_PATH .'plugins/'.$plugin.'/setup.php')) {
f084f987 391 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot read its setup.php file.', FALSE);
392 } elseif (in_array($plugin, $bad_plugins)) {
393 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);
394 }
d1ae9d4c 395 }
69792446 396 // load plugin functions
397 include_once(SM_PATH . 'functions/plugin.php');
398 // turn on output buffering in order to prevent output of new lines
399 ob_start();
400 foreach ($plugins as $name) {
401 use_plugin($name);
402 }
403 // get output and remove whitespace
404 $output = trim(ob_get_contents());
405 ob_end_clean();
406 // if plugins output more than newlines and spacing, stop script execution.
407 if (!empty($output)) {
c13b8d16 408 $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);
69792446 409 do_err($plugin_load_error);
410 }
56f9bb83 411 /**
412 * Print plugin versions
413 */
56f9bb83 414 echo $IND . "Plugin versions...<br />\n";
415 foreach ($plugins as $name) {
d95b10b3 416 $plugin_version = get_plugin_version($name);
fc6228e4 417 echo $IND . $IND . $name . ' ' . (empty($plugin_version) ? '??' : $plugin_version) . "<br />\n";
2cbaf68d 418
419 // check if this plugin has any other plugin
420 // dependencies and if they are satisfied
421 //
422 $failed_dependencies = check_plugin_dependencies($name);
f258865c 423 if ($failed_dependencies === SQ_INCOMPATIBLE) {
03a69f57 424 do_err($name . ' is NOT COMPATIBLE with this version of SquirrelMail', FALSE);
425 }
426 else if (is_array($failed_dependencies)) {
2cbaf68d 427 $missing_plugins = '';
fc6228e4 428 foreach ($failed_dependencies as $depend_name => $depend_requirements) {
429 $missing_plugins .= ', ' . $depend_name . ' (version ' . $depend_requirements['version'] . ', ' . ($depend_requirements['activate'] ? 'must be activated' : 'need not be activated') . ')';
2cbaf68d 430 }
431 do_err($name . ' is missing some dependencies: ' . trim($missing_plugins, ', '), FALSE);
432 }
433
56f9bb83 434 }
69792446 435 /**
97ae6d06 436 * This hook was added in 1.5.2 and 1.4.10. Each plugins should print an error
6e515418 437 * message and return TRUE if there are any errors in its setup/configuration.
69792446 438 */
62fb877b 439 $plugin_err = boolean_hook_function('configtest', $null, 1);
69792446 440 if($plugin_err) {
441 do_err('Some plugin tests failed.');
442 } else {
443 echo $IND . "Plugins OK.<br />\n";
444 }
5b53b7e0 445} else {
446 echo $IND . "Plugins are not enabled in config.<br />\n";
d1ae9d4c 447}
d1ae9d4c 448foreach($theme as $thm) {
449 if(!file_exists($thm['PATH'])) {
450 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot find it ('.$thm['PATH'].').', FALSE);
451 } elseif(!is_readable($thm['PATH'])) {
452 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot read it ('.$thm['PATH'].').', FALSE);
453 }
454}
455
456echo $IND . "Themes OK.<br />\n";
457
07337c9b 458if ( $squirrelmail_default_language != 'en_US' ) {
459 $loc_path = SM_PATH .'locale/'.$squirrelmail_default_language.'/LC_MESSAGES/squirrelmail.mo';
460 if( ! file_exists( $loc_path ) ) {
f8a1ed5a 461 do_err('You have set <i>' . $squirrelmail_default_language .
f084f987 462 '</i> as your default language, but I cannot find this translation (should be '.
463 'in <tt>' . $loc_path . '</tt>). Please note that you have to download translations '.
464 'separately from the main SquirrelMail package.', FALSE);
07337c9b 465 } elseif ( ! is_readable( $loc_path ) ) {
f8a1ed5a 466 do_err('You have set <i>' . $squirrelmail_default_language .
f084f987 467 '</i> as your default language, but I cannot read this translation (file '.
468 'in <tt>' . $loc_path . '</tt> unreadable).', FALSE);
07337c9b 469 } else {
470 echo $IND . "Default language OK.<br />\n";
471 }
472} else {
473 echo $IND . "Default language OK.<br />\n";
474}
475
74530cf4 476echo $IND . "Base URL detected as: <tt>" . htmlspecialchars($test_location) .
477 "</tt> (location base " . (empty($config_location_base) ? 'autodetected' : 'set to <tt>' .
478 htmlspecialchars($config_location_base)."</tt>") . ")<br />\n";
23649466 479
a15f9d93 480/* check minimal requirements for other security options */
d1ae9d4c 481
a15f9d93 482/* imaps or ssmtp */
483if($use_smtp_tls == 1 || $use_imap_tls == 1) {
d1ae9d4c 484 if(!check_php_version(4,3,0)) {
485 do_err('You need at least PHP 4.3.0 for SMTP/IMAP TLS!');
486 }
487 if(!extension_loaded('openssl')) {
488 do_err('You need the openssl PHP extension to use SMTP/IMAP TLS!');
489 }
490}
a15f9d93 491/* starttls extensions */
1c4f110f 492if($use_smtp_tls === 2 || $use_imap_tls === 2) {
a15f9d93 493 if (! function_exists('stream_socket_enable_crypto')) {
494 do_err('If you want to use STARTTLS extension, you need stream_socket_enable_crypto() function from PHP 5.1.0 and newer.');
495 }
496}
497/* digest-md5 */
498if ($smtp_auth_mech=='digest-md5' || $imap_auth_mech =='digest-md5') {
499 if (!extension_loaded('xml')) {
500 do_err('You need the PHP XML extension to use Digest-MD5 authentication!');
501 }
502}
503
504/* check outgoing mail */
d1ae9d4c 505
506echo "Checking outgoing mail service....<br />\n";
507
508if($useSendmail) {
509 // is_executable also checks for existance, but we want to be as precise as possible with the errors
510 if(!file_exists($sendmail_path)) {
511 do_err("Location of sendmail program incorrect ($sendmail_path)!");
91e0dccc 512 }
d1ae9d4c 513 if(!is_executable($sendmail_path)) {
514 do_err("I cannot execute the sendmail program ($sendmail_path)!");
515 }
516
517 echo $IND . "sendmail OK<br />\n";
518} else {
a15f9d93 519 $stream = fsockopen( ($use_smtp_tls==1?'tls://':'').$smtpServerAddress, $smtpPort,
f084f987 520 $errorNumber, $errorString);
d1ae9d4c 521 if(!$stream) {
522 do_err("Error connecting to SMTP server \"$smtpServerAddress:$smtpPort\".".
f084f987 523 "Server error: ($errorNumber) ".htmlspecialchars($errorString));
d1ae9d4c 524 }
525
526 // check for SMTP code; should be 2xx to allow us access
527 $smtpline = fgets($stream, 1024);
528 if(((int) $smtpline{0}) > 3) {
9c941728 529 do_err("Error connecting to SMTP server. Server error: ".
f084f987 530 htmlspecialchars($smtpline));
d1ae9d4c 531 }
532
a15f9d93 533 /* smtp starttls checks */
1c4f110f 534 if ($use_smtp_tls===2) {
a15f9d93 535 // if something breaks, script should close smtp connection on exit.
536
537 // say helo
538 fwrite($stream,"EHLO $client_ip\r\n");
539
540 $ehlo=array();
541 $ehlo_error = false;
542 while ($line=fgets($stream, 1024)){
543 if (preg_match("/^250(-|\s)(\S*)\s+(\S.*)/",$line,$match)||
f084f987 544 preg_match("/^250(-|\s)(\S*)\s+/",$line,$match)) {
a15f9d93 545 if (!isset($match[3])) {
546 // simple one word extension
547 $ehlo[strtoupper($match[2])]='';
548 } else {
549 // ehlo-keyword + ehlo-param
550 $ehlo[strtoupper($match[2])]=trim($match[3]);
551 }
552 if ($match[1]==' ') {
553 $ret = $line;
554 break;
555 }
556 } else {
557 //
558 $ehlo_error = true;
559 $ehlo[]=$line;
560 break;
561 }
562 }
563 if ($ehlo_error) {
564 do_err('SMTP EHLO failed. You need ESMTP support for SMTP STARTTLS');
565 } elseif (!array_key_exists('STARTTLS',$ehlo)) {
566 do_err('STARTTLS support is not declared by SMTP server.');
567 }
568
569 fwrite($stream,"STARTTLS\r\n");
570 $starttls_response=fgets($stream, 1024);
571 if ($starttls_response[0]!=2) {
572 $starttls_cmd_err = 'SMTP STARTTLS failed. Server replied: '
573 .htmlspecialchars($starttls_response);
574 do_err($starttls_cmd_err);
575 } elseif(! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
576 do_err('Failed to enable encryption on SMTP STARTTLS connection.');
577 } else {
578 echo $IND . "SMTP STARTTLS extension looks OK.<br />\n";
579 }
580 // According to RFC we should second ehlo call here.
581 }
582
d1ae9d4c 583 fputs($stream, 'QUIT');
584 fclose($stream);
9c941728 585 echo $IND . 'SMTP server OK (<tt><small>'.
f084f987 586 trim(htmlspecialchars($smtpline))."</small></tt>)<br />\n";
d1ae9d4c 587
588 /* POP before SMTP */
589 if($pop_before_smtp) {
590 $stream = fsockopen($smtpServerAddress, 110, $err_no, $err_str);
591 if (!$stream) {
9c941728 592 do_err("Error connecting to POP Server ($smtpServerAddress:110) "
f084f987 593 . $err_no . ' : ' . htmlspecialchars($err_str));
d1ae9d4c 594 }
595
596 $tmp = fgets($stream, 1024);
597 if (substr($tmp, 0, 3) != '+OK') {
598 do_err("Error connecting to POP Server ($smtpServerAddress:110)"
f084f987 599 . ' '.htmlspecialchars($tmp));
d1ae9d4c 600 }
601 fputs($stream, 'QUIT');
602 fclose($stream);
603 echo $IND . "POP-before-SMTP OK.<br />\n";
604 }
605}
606
df758744 607/**
608 * Check the IMAP server
609 */
d1ae9d4c 610echo "Checking IMAP service....<br />\n";
611
df758744 612/** Can we open a connection? */
a15f9d93 613$stream = fsockopen( ($use_imap_tls==1?'tls://':'').$imapServerAddress, $imapPort,
f084f987 614 $errorNumber, $errorString);
d1ae9d4c 615if(!$stream) {
70b71161 616 do_err("Error connecting to IMAP server \"$imapServerAddress:$imapPort\".".
f084f987 617 "Server error: ($errorNumber) ".
618 htmlspecialchars($errorString));
d1ae9d4c 619}
620
df758744 621/** Is the first response 'OK'? */
d1ae9d4c 622$imapline = fgets($stream, 1024);
623if(substr($imapline, 0,4) != '* OK') {
f084f987 624 do_err('Error connecting to IMAP server. Server error: '.
625 htmlspecialchars($imapline));
d1ae9d4c 626}
627
df758744 628echo $IND . 'IMAP server ready (<tt><small>'.
9c941728 629 htmlspecialchars(trim($imapline))."</small></tt>)<br />\n";
d1ae9d4c 630
df758744 631/** Check capabilities */
632fputs($stream, "A001 CAPABILITY\r\n");
a15f9d93 633$capline = '';
634while ($line=fgets($stream, 1024)){
f084f987 635 if (preg_match("/A001.*/",$line)) {
636 break;
637 } else {
638 $capline.=$line;
639 }
a15f9d93 640}
641
642/* don't display capabilities before STARTTLS */
1c4f110f 643if ($use_imap_tls===2 && stristr($capline, 'STARTTLS') === false) {
a15f9d93 644 do_err('Your server doesn\'t support STARTTLS.');
1c4f110f 645} elseif($use_imap_tls===2) {
a15f9d93 646 /* try starting starttls */
647 fwrite($stream,"A002 STARTTLS\r\n");
648 $starttls_line=fgets($stream, 1024);
649 if (! preg_match("/^A002 OK.*/i",$starttls_line)) {
650 $imap_starttls_err = 'IMAP STARTTLS failed. Server replied: '
f084f987 651 .htmlspecialchars($starttls_line);
a15f9d93 652 do_err($imap_starttls_err);
653 } elseif (! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
654 do_err('Failed to enable encryption on IMAP connection.');
655 } else {
656 echo $IND . "IMAP STARTTLS extension looks OK.<br />\n";
657 }
658
659 // get new capability line
660 fwrite($stream,"A003 CAPABILITY\r\n");
661 $capline='';
662 while ($line=fgets($stream, 1024)){
663 if (preg_match("/A003.*/",$line)) {
664 break;
665 } else {
666 $capline.=$line;
667 }
668 }
669}
df758744 670
671echo $IND . 'Capabilities: <tt>'.htmlspecialchars($capline)."</tt><br />\n";
672
673if($imap_auth_mech == 'login' && stristr($capline, 'LOGINDISABLED') !== FALSE) {
674 do_err('Your server doesn\'t allow plaintext logins. '.
f084f987 675 'Try enabling another authentication mechanism like CRAM-MD5, DIGEST-MD5 or TLS-encryption '.
676 'in the SquirrelMail configuration.', FALSE);
df758744 677}
df758744 678
ceb7ad3c 679if (stristr($capline, 'XMAGICTRASH') !== false) {
680 $magic_trash = 'It looks like IMAP_MOVE_EXPUNGE_TO_TRASH option is turned on '
681 .'in your Courier IMAP configuration. Courier does not provide tools that '
682 .'allow to detect folder used for Trash or commands are not documented. '
683 .'SquirrelMail can\'t detect special trash folder. SquirrelMail manages '
684 .'all message deletion or move operations internally and '
685 .'IMAP_MOVE_EXPUNGE_TO_TRASH option can cause errors in message and '
686 .'folder management operations. Please turn off IMAP_MOVE_EXPUNGE_TO_TRASH '
687 .'option in Courier imapd configuration.';
688 do_err($magic_trash,false);
689}
690
0fa9bde7 691/* add warning about IMAP delivery */
692if (stristr($capline, 'XCOURIEROUTBOX') !== false) {
693 $courier_outbox = 'OUTBOX setting is enabled in your Courier imapd '
694 .'configuration. SquirrelMail uses standard SMTP protocol or sendmail '
695 .'binary to send emails. Courier IMAP delivery method is not supported'
696 .' and can create duplicate email messages.';
697 do_err($courier_outbox,false);
698}
699
df758744 700/** OK, close connection */
a15f9d93 701fputs($stream, "A004 LOGOUT\r\n");
df758744 702fclose($stream);
703
17fca61d 704echo "Checking internationalization (i18n) settings...<br />\n";
0ed3bdc3 705echo "$IND gettext - ";
706if (function_exists('gettext')) {
8f186a2a 707 echo 'Gettext functions are available.'
708 .' On some systems you must have appropriate system locales compiled.'
709 ."<br />\n";
fd72907b 710
711 /* optional setlocale() tests. Should work only on glibc systems. */
712 if (sqgetGlobalVar('testlocales',$testlocales,SQ_GET)) {
867fed37 713 include_once(SM_PATH . 'include/languages.php');
fd72907b 714 echo $IND . $IND . 'Testing translations:<br>';
715 foreach ($languages as $lang_code => $lang_data) {
716 /* don't test aliases */
717 if (isset($lang_data['NAME'])) {
718 /* locale can be $lang_code or $lang_data['LOCALE'] */
719 if (isset($lang_data['LOCALE'])) {
720 $setlocale = $lang_data['LOCALE'];
721 } else {
722 $setlocale = $lang_code;
723 }
724 /* prepare information about tested locales */
725 if (is_array($setlocale)) {
726 $display_locale = implode(', ',$setlocale);
727 $locale_count = count($setlocale);
728 } else {
729 $display_locale = $setlocale;
730 $locale_count = 1;
731 }
732 $tested_locales_msg = 'Tested '.htmlspecialchars($display_locale).' '
733 .($locale_count>1 ? 'locales':'locale'). '.';
734
735 echo $IND . $IND .$IND . $lang_data['NAME'].' (' .$lang_code. ') - ';
736 $retlocale = sq_setlocale(LC_ALL,$setlocale);
737 if (is_bool($retlocale)) {
738 echo '<font color="red">unsupported</font>. ';
739 echo $tested_locales_msg;
740 } else {
741 echo 'supported. '
742 .$tested_locales_msg
743 .' setlocale() returned "'.htmlspecialchars($retlocale).'"';
744 }
745 echo "<br />\n";
746 }
747 }
748 echo $IND . $IND . '<a href="configtest.php">Don\'t test translations</a>';
749 } else {
750 echo $IND . $IND . '<a href="configtest.php?testlocales=1">Test translations</a>. '
751 .'This test is not accurate and might work only on some systems.'
752 ."\n";
753 }
754 echo "<br />\n";
755 /* end of translation tests */
0ed3bdc3 756} else {
8f186a2a 757 echo 'Gettext functions are unavailable.'
758 .' SquirrelMail will use slower internal gettext functions.'
759 ."<br />\n";
0ed3bdc3 760}
761echo "$IND mbstring - ";
762if (function_exists('mb_detect_encoding')) {
763 echo "Mbstring functions are available.<br />\n";
764} else {
8f186a2a 765 echo 'Mbstring functions are unavailable.'
766 ." Japanese translation won't work.<br />\n";
0ed3bdc3 767}
768echo "$IND recode - ";
769if (function_exists('recode')) {
770 echo "Recode functions are available.<br />\n";
ba17b6c7 771} elseif (isset($use_php_recode) && $use_php_recode) {
0ed3bdc3 772 echo "Recode functions are unavailable.<br />\n";
773 do_err('Your configuration requires recode support, but recode support is missing.');
774} else {
775 echo "Recode functions are unavailable.<br />\n";
776}
777echo "$IND iconv - ";
778if (function_exists('iconv')) {
779 echo "Iconv functions are available.<br />\n";
ba17b6c7 780} elseif (isset($use_php_iconv) && $use_php_iconv) {
0ed3bdc3 781 echo "Iconv functions are unavailable.<br />\n";
782 do_err('Your configuration requires iconv support, but iconv support is missing.');
783} else {
784 echo "Iconv functions are unavailable.<br />\n";
785}
867fed37 786// same test as in include/init.php + date_default_timezone_set check
0ed3bdc3 787echo "$IND timezone - ";
867fed37 788if ( (!ini_get('safe_mode')) || function_exists('date_default_timezone_set') ||
f084f987 789 !strcmp(ini_get('safe_mode_allowed_env_vars'),'') ||
790 preg_match('/^([\w_]+,)*TZ/', ini_get('safe_mode_allowed_env_vars')) ) {
fd72907b 791 echo "Webmail users can change their time zone settings. \n";
0ed3bdc3 792} else {
fd72907b 793 echo "Webmail users can't change their time zone settings. \n";
4764a7ff 794}
fd72907b 795if (isset($_ENV['TZ'])) {
796 echo 'Default time zone is '.htmlspecialchars($_ENV['TZ']);
797} else {
798 echo 'Current time zone is '.date('T');
799}
800echo ".<br />\n";
d18703d3 801
4764a7ff 802// Pear DB tests
d18703d3 803echo "Checking database functions...<br />\n";
804if($addrbook_dsn || $prefs_dsn || $addrbook_global_dsn) {
134e4174 805 @include_once('DB.php');
806 if (class_exists('DB')) {
807 echo "$IND PHP Pear DB support is present.<br />\n";
808 $db_functions=array(
f084f987 809 'dbase' => 'dbase_open',
810 'fbsql' => 'fbsql_connect',
811 'interbase' => 'ibase_connect',
812 'informix' => 'ifx_connect',
813 'msql' => 'msql_connect',
814 'mssql' => 'mssql_connect',
815 'mysql' => 'mysql_connect',
816 'mysqli' => 'mysqli_connect',
817 'oci8' => 'ocilogon',
818 'odbc' => 'odbc_connect',
819 'pgsql' => 'pg_connect',
820 'sqlite' => 'sqlite_open',
821 'sybase' => 'sybase_connect'
822 );
134e4174 823
824 $dsns = array();
825 if($prefs_dsn) {
826 $dsns['preferences'] = $prefs_dsn;
827 }
828 if($addrbook_dsn) {
829 $dsns['addressbook'] = $addrbook_dsn;
830 }
831 if($addrbook_global_dsn) {
832 $dsns['global addressbook'] = $addrbook_global_dsn;
833 }
834
835 foreach($dsns as $type => $dsn) {
ba17b6c7 836 $aDsn = explode(':', $dsn);
837 $dbtype = array_shift($aDsn);
134e4174 838 if(isset($db_functions[$dbtype]) && function_exists($db_functions[$dbtype])) {
839 echo "$IND$dbtype database support present.<br />\n";
840
841 // now, test this interface:
842
843 $dbh = DB::connect($dsn, true);
844 if (DB::isError($dbh)) {
845 do_err('Database error: '. htmlspecialchars(DB::errorMessage($dbh)) .
f084f987 846 ' in ' .$type .' DSN.');
134e4174 847 }
848 $dbh->disconnect();
849 echo "$IND$type database connect successful.<br />\n";
850
851 } else {
ba17b6c7 852 do_err($dbtype.' database support not present!');
d18703d3 853 }
134e4174 854 }
855 } else {
8f186a2a 856 $db_error='Required PHP PEAR DB support is not available.'
857 .' Is PEAR installed and is the include path set correctly to find <tt>DB.php</tt>?'
858 .' The include path is now:<tt>' . ini_get('include_path') . '</tt>.';
859 do_err($db_error);
134e4174 860 }
4764a7ff 861} else {
d18703d3 862 echo $IND."not using database functionality.<br />\n";
0ed3bdc3 863}
7562c55b 864
865// LDAP DB tests
866echo "Checking LDAP functions...<br />\n";
867if( empty($ldap_server) ) {
134e4174 868 echo $IND."not using LDAP functionality.<br />\n";
7562c55b 869} else {
d0184454 870 if ( !function_exists('ldap_connect') ) {
7562c55b 871 do_err('Required LDAP support is not available.');
872 } else {
134e4174 873 echo "$IND LDAP support present.<br />\n";
7562c55b 874 foreach ( $ldap_server as $param ) {
875
d0184454 876 $linkid = @ldap_connect($param['host'], (empty($param['port']) ? 389 : $param['port']) );
7562c55b 877
878 if ( $linkid ) {
f084f987 879 echo "$IND LDAP connect to ".$param['host']." successful: ".$linkid."<br />\n";
91e0dccc 880
7562c55b 881 if ( !empty($param['protocol']) &&
f084f987 882 !ldap_set_option($linkid, LDAP_OPT_PROTOCOL_VERSION, $param['protocol']) ) {
7562c55b 883 do_err('Unable to set LDAP protocol');
91e0dccc 884 }
7562c55b 885
886 if ( empty($param['binddn']) ) {
d0184454 887 $bind = @ldap_bind($linkid);
7562c55b 888 } else {
d0184454 889 $bind = @ldap_bind($param['binddn'], $param['bindpw']);
7562c55b 890 }
891
892 if ( $bind ) {
893 echo "$IND LDAP Bind Successful <br />";
894 } else {
895 do_err('Unable to Bind to LDAP Server');
896 }
91e0dccc 897
d0184454 898 @ldap_close($linkid);
7562c55b 899 } else {
900 do_err('Connection to LDAP failed');
901 }
902 }
903 }
904}
a2b193bc 905
3a196538 906echo '<hr width="75%" align="center">';
907echo '<h2 align="center">Summary</h2>';
908$footer = '<hr width="75%" align="center">';
909if ($warnings) {
f084f987 910 echo '<p>No fatal errors were found, but there was at least 1 warning. Please check the flagged issue(s) carefully, as correcting them may prevent erratic, undefined, or incorrect behavior (or flat out breakage).</p>';
911 echo $footer;
3a196538 912} else {
f084f987 913 print <<< EOF
d1ae9d4c 914<p>Congratulations, your SquirrelMail setup looks fine to me!</p>
915
13721b47 916<p><a href="login.php">Login now</a></p>
d1ae9d4c 917
918</body>
3a196538 919</html>
920EOF;
f084f987 921 echo $footer;
3a196538 922}
09efeab8 923?>