1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* ****************************************************************************** |
5
|
|
|
* Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 |
6
|
|
|
* and GN4-2 consortia |
7
|
|
|
* |
8
|
|
|
* License: see the web/copyright.php file in the file structure |
9
|
|
|
* ****************************************************************************** |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* |
14
|
|
|
* |
15
|
|
|
* This is the definition of the CAT class implementing various configuration |
16
|
|
|
* tests. |
17
|
|
|
* Each test is implemented as a priviate method which needs to be named "test_name_test". |
18
|
|
|
* The test returns the results by calling the test_return method, this passing the return |
19
|
|
|
* code and the explanatory message. Multiple calls to test_return are allowed. |
20
|
|
|
* |
21
|
|
|
* An individual test can be run by the "test" method which takes the test name as an argument |
22
|
|
|
* multiple tests should be run by the run_all_tests method which takes an array as an argument |
23
|
|
|
* see method descriptions for more information. |
24
|
|
|
* |
25
|
|
|
* The results of the tests are passed within the $test_result array |
26
|
|
|
* |
27
|
|
|
* Some configuration of this class is required, see further down. |
28
|
|
|
* @author Stefan Winter <[email protected]> |
29
|
|
|
* @author Tomasz Wolniewicz <[email protected]> |
30
|
|
|
* |
31
|
|
|
* @license see LICENSE file in root directory |
32
|
|
|
* |
33
|
|
|
* @package Utilities |
34
|
|
|
*/ |
35
|
|
|
|
36
|
|
|
namespace core; |
37
|
|
|
|
38
|
|
|
use GeoIp2\Database\Reader; |
39
|
|
|
use \Exception; |
40
|
|
|
|
41
|
|
|
require_once(dirname(dirname(__FILE__)) . "/config/_config.php"); |
42
|
|
|
require_once(dirname(dirname(__FILE__)) . "/core/PHPMailer/src/PHPMailer.php"); |
43
|
|
|
require_once(dirname(dirname(__FILE__)) . "/core/PHPMailer/src/SMTP.php"); |
44
|
|
|
|
45
|
|
|
class SanityTests extends CAT { |
46
|
|
|
/* in this section set current CAT requirements */ |
47
|
|
|
|
48
|
|
|
/* $php_needversion sets the minumum required php version */ |
49
|
|
|
|
50
|
|
|
// because of bug: |
51
|
|
|
// Fixed bug #74005 (mail.add_x_header causes RFC-breaking lone line feed). |
52
|
|
|
private $php_needversion = '7.0.17'; |
53
|
|
|
|
54
|
|
|
/* List all required NSIS modules below */ |
55
|
|
|
private $NSIS_Modules = [ |
56
|
|
|
"nsArray.nsh", |
57
|
|
|
"FileFunc.nsh", |
58
|
|
|
"LogicLib.nsh", |
59
|
|
|
"WordFunc.nsh", |
60
|
|
|
"FileFunc.nsh", |
61
|
|
|
"x64.nsh", |
62
|
|
|
]; |
63
|
|
|
|
64
|
|
|
/* set $profile_option_ct to the number of rows returned by "SELECT * FROM profile_option_dict" */ |
65
|
|
|
private $profile_option_ct = 33; |
66
|
|
|
/* set $view_admin_ct to the number of rows returned by "desc view_admin" */ |
67
|
|
|
private $view_admin_ct = 8; |
68
|
|
|
|
69
|
|
|
/* end of config */ |
70
|
|
|
public $out; |
71
|
|
|
public $name; |
72
|
|
|
|
73
|
|
|
public function __construct() { |
74
|
|
|
parent::__construct(); |
75
|
|
|
$this->test_result = []; |
76
|
|
|
$this->test_result['global'] = 0; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* The single test wrapper |
81
|
|
|
* @param string $test the test name |
82
|
|
|
*/ |
83
|
|
|
public function test($test) { |
84
|
|
|
$this->out[$test] = []; |
85
|
|
|
$this->name = $test; |
86
|
|
|
$m_name = $test . '_test'; |
87
|
|
|
$this->test_result[$test] = 0; |
88
|
|
|
if (!method_exists($this, $m_name)) { |
89
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Configuration error, no test configured for <strong>$test</strong>."); |
90
|
|
|
return; |
91
|
|
|
} |
92
|
|
|
$this->$m_name(); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* The multiple tests wrapper |
97
|
|
|
* @param array $Tests the tests array. |
98
|
|
|
* |
99
|
|
|
* The $Tests is a simple string array, where each entry is a test name |
100
|
|
|
* the test names can also be given in the format "test=>subtest", which |
101
|
|
|
* defines a conditional execution of the "subtest" if the "test" was run earier |
102
|
|
|
* and returned a success. |
103
|
|
|
*/ |
104
|
|
|
public function run_tests($Tests) { |
105
|
|
|
foreach ($Tests as $testName) { |
106
|
|
|
$matchArray = []; |
107
|
|
|
if (preg_match('/(.+)=>(.+)/', $testName, $matchArray)) { |
108
|
|
|
$tst = $matchArray[1]; |
109
|
|
|
$subtst = $matchArray[2]; |
110
|
|
|
if ($this->test_result[$tst] < \core\common\Entity::L_ERROR) { |
111
|
|
|
$this->test($subtst); |
112
|
|
|
} |
113
|
|
|
} else { |
114
|
|
|
$this->test($testName); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
public function get_test_names() { |
120
|
|
|
$T = get_class_methods($this); |
121
|
|
|
$out = []; |
122
|
|
|
foreach ($T as $t) { |
123
|
|
|
if (preg_match('/^(.*)_test$/', $t, $m)) { |
124
|
|
|
$out[] = $m[1]; |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
return $out; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* This array is used to return the test results. |
132
|
|
|
* As the 'global' entry it returns the maximum return value |
133
|
|
|
* from all tests. |
134
|
|
|
* Individual tests results are teturned as separate entires |
135
|
|
|
* indexed by test names; each value is an array passing "level" and "message" |
136
|
|
|
* from each of the tests. |
137
|
|
|
* $test_result is set by the test_return method |
138
|
|
|
* |
139
|
|
|
* @var array $test_result |
140
|
|
|
*/ |
141
|
|
|
public $test_result; |
142
|
|
|
|
143
|
|
|
private function test_return($level, $message) { |
144
|
|
|
$this->out[$this->name][] = ['level' => $level, 'message' => $message]; |
145
|
|
|
$this->test_result[$this->name] = max($this->test_result[$this->name], $level); |
146
|
|
|
$this->test_result['global'] = max($this->test_result['global'], $level); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
private function get_exec_path($pathToCheck) { |
150
|
|
|
$the_path = ""; |
151
|
|
|
$exec_is = "UNDEFINED"; |
152
|
|
|
foreach ([CONFIG, CONFIG_CONFASSISTANT, CONFIG_DIAGNOSTICS] as $config) { |
153
|
|
|
if (!empty($config['PATHS'][$pathToCheck])) { |
154
|
|
|
$matchArray = []; |
155
|
|
|
preg_match('/([^ ]+) ?/', $config['PATHS'][$pathToCheck], $matchArray); |
156
|
|
|
$exe = $matchArray[1]; |
157
|
|
|
$the_path = exec("which " . $config['PATHS'][$pathToCheck]); |
158
|
|
|
if ($the_path == $exe) { |
159
|
|
|
$exec_is = "EXPLICIT"; |
160
|
|
|
} else { |
161
|
|
|
$exec_is = "IMPLICIT"; |
162
|
|
|
} |
163
|
|
|
return(['exec' => $the_path, 'exec_is' => $exec_is]); |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
return(['exec' => $the_path, 'exec_is' => $exec_is]); |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Test for php version |
171
|
|
|
*/ |
172
|
|
|
private function php_test() { |
173
|
|
|
if (version_compare(phpversion(), $this->php_needversion, '>=')) { |
174
|
|
|
$this->test_return(\core\common\Entity::L_OK, "<strong>PHP</strong> is sufficiently recent. You are running " . phpversion() . "."); |
175
|
|
|
} else { |
176
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "<strong>PHP</strong> is too old. We need at least $this->php_needversion, but you only have " . phpversion() . "."); |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* set for cat_base_url setting |
182
|
|
|
*/ |
183
|
|
|
private function cat_base_url_test() { |
184
|
|
|
$rootUrl = substr(CONFIG['PATHS']['cat_base_url'], -1) === '/' ? substr(CONFIG['PATHS']['cat_base_url'], 0, -1) : CONFIG['PATHS']['cat_base_url']; |
185
|
|
|
preg_match('/(^.*)\/admin\/112365365321.php/', $_SERVER['SCRIPT_NAME'], $m); |
186
|
|
|
if ($rootUrl === $m[1]) { |
187
|
|
|
$this->test_return(\core\common\Entity::L_OK, "<strong>cat_base_url</strong> set correctly"); |
188
|
|
|
} else { |
189
|
|
|
$rootFromScript = $m[1] === '' ? '/' : $m[1]; |
190
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "<strong>cat_base_url</strong> is set to <strong>" . CONFIG['PATHS']['cat_base_url'] . "</strong> and should be <strong>$rootFromScript</strong>"); |
191
|
|
|
} |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* test for simpleSAMLphp |
196
|
|
|
*/ |
197
|
|
|
private function ssp_test() { |
198
|
|
|
if (!is_file(CONFIG['AUTHENTICATION']['ssp-path-to-autoloader'])) { |
199
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "SS<strong>simpleSAMLphp</strong> not found!"); |
200
|
|
|
} else { |
201
|
|
|
$this->test_return(\core\common\Entity::L_OK, "<strong>simpleSAMLphp</strong> autoloader found."); |
202
|
|
|
} |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* test for security setting |
207
|
|
|
*/ |
208
|
|
|
private function security_test() { |
209
|
|
|
if (in_array("I do not care about security!", CONFIG['SUPERADMINS'])) { |
210
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "You do not care about security. This page should be made accessible to the CAT admin only! See config.php 'Superadmins'!"); |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* test if zip is available |
216
|
|
|
*/ |
217
|
|
|
private function zip_test() { |
218
|
|
View Code Duplication |
if (exec("which zip") != "") { |
219
|
|
|
$this->test_return(\core\common\Entity::L_OK, "<strong>zip</strong> binary found."); |
220
|
|
|
} else { |
221
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "<strong>zip</strong> not found in your \$PATH!"); |
222
|
|
|
} |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* test if eapol_test is availabe and reacent enough |
227
|
|
|
*/ |
228
|
|
|
private function eapol_test_test() { |
229
|
|
|
exec(CONFIG_DIAGNOSTICS['PATHS']['eapol_test'], $out, $retval); |
230
|
|
|
if ($retval == 255) { |
231
|
|
|
$o = preg_grep('/-o<server cert/', $out); |
232
|
|
View Code Duplication |
if (count($o) > 0) { |
233
|
|
|
$this->test_return(\core\common\Entity::L_OK, "<strong>eapol_test</strong> script found."); |
234
|
|
|
} else { |
235
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "<strong>eapol_test</strong> found, but is too old!"); |
236
|
|
|
} |
237
|
|
|
} else { |
238
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "<strong>eapol_test</strong> not found!"); |
239
|
|
|
} |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* test if logdir exists and is writable |
244
|
|
|
*/ |
245
|
|
|
private function logdir_test() { |
246
|
|
|
if (fopen(CONFIG['PATHS']['logdir'] . "/debug.log", "a") == FALSE) { |
247
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "Log files in <strong>" . CONFIG['PATHS']['logdir'] . "</strong> are not writable!"); |
248
|
|
|
} else { |
249
|
|
|
$this->test_return(\core\common\Entity::L_OK, "Log directory is writable."); |
250
|
|
|
} |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* test for required PHP modules |
255
|
|
|
*/ |
256
|
|
|
private function phpModules_test() { |
257
|
|
|
if (function_exists('idn_to_ascii')) { |
258
|
|
|
$this->test_return(\core\common\Entity::L_OK, "PHP can handle internationalisation."); |
259
|
|
|
} else { |
260
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP can <strong>NOT</strong> handle internationalisation (idn_to_ascii() from php7.0-intl)."); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
if (function_exists('gettext')) { |
264
|
|
|
$this->test_return(\core\common\Entity::L_OK, "PHP extension <strong>GNU Gettext</strong> is installed."); |
265
|
|
|
} else { |
266
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GNU Gettext</strong> not found!"); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
if (function_exists('openssl_sign')) { |
270
|
|
|
$this->test_return(\core\common\Entity::L_OK, "PHP extension <strong>OpenSSL</strong> is installed."); |
271
|
|
|
} else { |
272
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>OpenSSL</strong> not found!"); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
if (class_exists('\Imagick')) { |
276
|
|
|
$this->test_return(\core\common\Entity::L_OK, "PHP extension <strong>Imagick</strong> is installed."); |
277
|
|
|
} else { |
278
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>Imagick</strong> not found! Get it from your distribution or <a href='http://pecl.php.net/package/imagick'>here</a>."); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
if (function_exists('ImageCreate')) { |
282
|
|
|
$this->test_return(\core\common\Entity::L_OK, "PHP extension <strong>GD</strong> is installed."); |
283
|
|
|
} else { |
284
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GD</strong> not found!</a>."); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
if (function_exists('mysqli_connect')) { |
288
|
|
|
$this->test_return(\core\common\Entity::L_OK, "PHP extension <strong>MySQL</strong> is installed."); |
289
|
|
|
} else { |
290
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>MySQL</strong> not found!"); |
291
|
|
|
} |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* test if GeoIP is installed correctly |
296
|
|
|
*/ |
297
|
|
|
private function geoip_test() { |
298
|
|
|
$host_4 = '145.0.2.50'; |
299
|
|
|
$host_6 = '2001:610:188:444::50'; |
300
|
|
|
switch (CONFIG['GEOIP']['version']) { |
301
|
|
|
case 0: |
302
|
|
|
$this->test_return(\core\common\Entity::L_REMARK, "As set in the config, no geolocation service will be used"); |
303
|
|
|
break; |
304
|
|
|
case 1: |
305
|
|
|
if (!function_exists('geoip_record_by_name')) { |
306
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GeoIP</strong> (legacy) not found! Get it from your distribution or <a href='http://pecl.php.net/package/geoip'>here</a> or better install GeoIP2 from <a href='https://github.com/maxmind/GeoIP2-php'>here</a>."); |
307
|
|
|
return; |
308
|
|
|
} |
309
|
|
|
$record = geoip_record_by_name($host_4); |
310
|
|
|
if ($record === FALSE) { |
311
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GeoIP</strong> (legacy) found but not working properly, perhaps you need to download the databases. See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly."); |
312
|
|
|
return; |
313
|
|
|
} |
314
|
|
|
if ($record['city'] != 'Utrecht') { |
315
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GeoIP</strong> (legacy) found but not working properly, perhaps you need to download the databases. See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly."); |
316
|
|
|
return; |
317
|
|
|
} |
318
|
|
|
$this->test_return(\core\common\Entity::L_REMARK, "PHP extension <strong>GeoIP</strong> (legacy) is installed and working. See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly. We stronly advise to replace the legacy GeoIP with GeoIP2 from <a href='https://github.com/maxmind/GeoIP2-php'>here</a>."); |
319
|
|
|
break; |
320
|
|
|
case 2: |
321
|
|
View Code Duplication |
if (!is_file(CONFIG['GEOIP']['geoip2-path-to-autoloader'])) { |
|
|
|
|
322
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GeoIP2</strong> not found! Get it from <a href='https://github.com/maxmind/GeoIP2-php'>here</a>."); |
323
|
|
|
return; |
324
|
|
|
} |
325
|
|
View Code Duplication |
if (!is_file(CONFIG['GEOIP']['geoip2-path-to-db'])) { |
|
|
|
|
326
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "<strong>GeoIP2 database</strong> not found! See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly."); |
327
|
|
|
return; |
328
|
|
|
} |
329
|
|
|
require_once CONFIG['GEOIP']['geoip2-path-to-autoloader']; |
330
|
|
|
$reader = new Reader(CONFIG['GEOIP']['geoip2-path-to-db']); |
331
|
|
|
try { |
332
|
|
|
$record = $reader->city($host_4); |
333
|
|
|
} catch (Exception $e) { |
334
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GeoIP2</strong> found but not working properly, perhaps you need to download the databases. See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly."); |
335
|
|
|
return; |
336
|
|
|
} |
337
|
|
|
if ($record->city->name != 'Utrecht') { |
338
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GeoIP2</strong> found but not working properly, perhaps you need to download the databases. See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly."); |
339
|
|
|
return; |
340
|
|
|
} |
341
|
|
|
try { |
342
|
|
|
$record = $reader->city($host_6); |
343
|
|
|
} catch (Exception $e) { |
344
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GeoIP2</strong> found but not working properly with IPv6, perhaps you need to download the databases. See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly."); |
345
|
|
|
return; |
346
|
|
|
} |
347
|
|
|
if ($record->city->name != 'Utrecht') { |
348
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "PHP extension <strong>GeoIP2</strong> found but not working properly with IPv6, perhaps you need to download the databases. See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly."); |
349
|
|
|
return; |
350
|
|
|
} |
351
|
|
|
$this->test_return(\core\common\Entity::L_OK, "PHP extension <strong>GeoIP2</strong> is installed and working. See utils/GeoIP-update.sh in the CAT distribution and use it tu update the GeoIP database regularly."); |
352
|
|
|
break; |
353
|
|
|
default: |
354
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, 'Check CONFIG[\'GEOIP\'][\'version\'], it must be set to either 1 or 2'); |
355
|
|
|
break; |
356
|
|
|
} |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* test if openssl is available |
361
|
|
|
*/ |
362
|
|
|
private function openssl_test() { |
363
|
|
|
$A = $this->get_exec_path('openssl'); |
364
|
|
|
if ($A['exec'] != "") { |
365
|
|
|
$t = exec($A['exec'] . ' version'); |
366
|
|
View Code Duplication |
if ($A['exec_is'] == "EXPLICIT") { |
|
|
|
|
367
|
|
|
$this->test_return(\core\common\Entity::L_OK, "<strong>$t</strong> was found and is configured explicitly in your config."); |
368
|
|
|
} else { |
369
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "<strong>$t</strong> was found, but is not configured with an absolute path in your config."); |
370
|
|
|
} |
371
|
|
|
} else { |
372
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "<strong>openssl</strong> was not found on your system!"); |
373
|
|
|
} |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* test if makensis is available |
378
|
|
|
*/ |
379
|
|
|
private function makensis_test() { |
380
|
|
|
if (!is_numeric(CONFIG_CONFASSISTANT['NSIS_VERSION'])) { |
381
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "NSIS_VERSION needs to be numeric!"); |
382
|
|
|
return; |
383
|
|
|
} |
384
|
|
|
if (CONFIG_CONFASSISTANT['NSIS_VERSION'] < 2) { |
385
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "NSIS_VERSION needs to be at least 2!"); |
386
|
|
|
return; |
387
|
|
|
} |
388
|
|
|
$A = $this->get_exec_path('makensis'); |
389
|
|
|
if ($A['exec'] != "") { |
390
|
|
|
$t = exec($A['exec'] . ' -VERSION'); |
391
|
|
View Code Duplication |
if ($A['exec_is'] == "EXPLICIT") { |
|
|
|
|
392
|
|
|
$this->test_return(\core\common\Entity::L_OK, "<strong>makensis $t</strong> was found and is configured explicitly in your config."); |
393
|
|
|
} else { |
394
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "<strong>makensis $t</strong> was found, but is not configured with an absolute path in your config."); |
395
|
|
|
} |
396
|
|
|
exec($A['exec'] . ' -HELP', $t); |
397
|
|
|
$t1 = count(preg_grep('/INPUTCHARSET/', $t)); |
398
|
|
View Code Duplication |
if ($t1 == 1 && CONFIG_CONFASSISTANT['NSIS_VERSION'] == 2) { |
|
|
|
|
399
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Declared NSIS_VERSION does not seem to match the file pointed to by PATHS['makensis']!"); |
400
|
|
|
} |
401
|
|
View Code Duplication |
if ($t1 == 0 && CONFIG_CONFASSISTANT['NSIS_VERSION'] >= 3) { |
|
|
|
|
402
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Declared NSIS_VERSION does not seem to match the file pointed to by PATHS['makensis']!"); |
403
|
|
|
} |
404
|
|
|
} else { |
405
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "<strong>makensis</strong> was not found on your system!"); |
406
|
|
|
} |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* test if all required NSIS modules are available |
411
|
|
|
*/ |
412
|
|
|
private function NSISmodules_test() { |
413
|
|
|
$tmp_dir = $this->createTemporaryDirectory('installer', 0)['dir']; |
414
|
|
|
if (!chdir($tmp_dir)) { |
415
|
|
|
$this->loggerInstance->debug(2, "Cannot chdir to $tmp_dir\n"); |
416
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "NSIS modules test - problem with temporary directory permissions, cannot continue"); |
417
|
|
|
return; |
418
|
|
|
} |
419
|
|
|
$exe = 'tt.exe'; |
420
|
|
|
$NSIS_Module_status = []; |
421
|
|
|
foreach ($this->NSIS_Modules as $module) { |
422
|
|
|
unset($out); |
423
|
|
|
exec(CONFIG_CONFASSISTANT['PATHS']['makensis'] . " -V1 '-X!include $module' '-XOutFile $exe' '-XSection X' '-XSectionEnd'", $out, $retval); |
424
|
|
|
if ($retval > 0) { |
425
|
|
|
$NSIS_Module_status[$module] = 0; |
426
|
|
|
} else { |
427
|
|
|
$NSIS_Module_status[$module] = 1; |
428
|
|
|
} |
429
|
|
|
} |
430
|
|
|
if (is_file($exe)) { |
431
|
|
|
unlink($exe); |
432
|
|
|
} |
433
|
|
|
foreach ($NSIS_Module_status as $module => $status) { |
434
|
|
|
if ($status == 1) { |
435
|
|
|
$this->test_return(\core\common\Entity::L_OK, "NSIS module <strong>$module</strong> was found."); |
436
|
|
|
} else { |
437
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "NSIS module <strong>$module</strong> was not found or is not working correctly."); |
438
|
|
|
} |
439
|
|
|
} |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
/** |
443
|
|
|
* test access to dowloads directories |
444
|
|
|
*/ |
445
|
|
|
private function directories_test() { |
446
|
|
|
$Dir1 = $this->createTemporaryDirectory('installer', 0); |
447
|
|
|
$dir1 = $Dir1['dir']; |
448
|
|
|
$base1 = $Dir1['base']; |
449
|
|
|
if ($dir1) { |
450
|
|
|
$this->test_return(\core\common\Entity::L_OK, "Installer cache directory is writable."); |
451
|
|
|
\core\common\Entity::rrmdir($dir1); |
452
|
|
|
} else { |
453
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Installer cache directory $base1 does not exist or is not writable!"); |
454
|
|
|
} |
455
|
|
|
$Dir2 = $this->createTemporaryDirectory('test', 0); |
456
|
|
|
$dir2 = $Dir2['dir']; |
457
|
|
|
$base2 = $Dir2['base']; |
458
|
|
|
if ($dir2) { |
459
|
|
|
$this->test_return(\core\common\Entity::L_OK, "Test directory is writable."); |
460
|
|
|
\core\common\Entity::rrmdir($dir2); |
461
|
|
|
} else { |
462
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Test directory $base2 does not exist or is not writable!"); |
463
|
|
|
} |
464
|
|
|
$Dir3 = $this->createTemporaryDirectory('logo', 0); |
465
|
|
|
$dir3 = $Dir3['dir']; |
466
|
|
|
$base3 = $Dir3['base']; |
467
|
|
|
if ($dir3) { |
468
|
|
|
$this->test_return(\core\common\Entity::L_OK, "Logos cache directory is writable."); |
469
|
|
|
\core\common\Entity::rrmdir($dir3); |
470
|
|
|
} else { |
471
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Logos cache directory $base3 does not exist or is not writable!"); |
472
|
|
|
} |
473
|
|
|
} |
474
|
|
|
|
475
|
|
|
/** |
476
|
|
|
* test if all required locales are enabled |
477
|
|
|
*/ |
478
|
|
|
private function locales_test() { |
479
|
|
|
$locales = shell_exec("locale -a"); |
480
|
|
|
$allthere = ""; |
481
|
|
|
foreach (CONFIG['LANGUAGES'] as $onelanguage) { |
482
|
|
|
if (preg_match("/" . $onelanguage['locale'] . "/", $locales) == 0) { |
483
|
|
|
$allthere .= $onelanguage['locale'] . " "; |
484
|
|
|
} |
485
|
|
|
} |
486
|
|
View Code Duplication |
if ($allthere == "") { |
487
|
|
|
$this->test_return(\core\common\Entity::L_OK, "All of your configured locales are available on your system."); |
488
|
|
|
} else { |
489
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "Some of your configured locales (<strong>$allthere</strong>) are not installed and will not be displayed correctly!"); |
490
|
|
|
} |
491
|
|
|
} |
492
|
|
|
|
493
|
|
|
const DEFAULTS = [ |
494
|
|
|
["SETTING" => CONFIG['APPEARANCE']['from-mail'], |
495
|
|
|
"DEFVALUE" => "[email protected]", |
496
|
|
|
"COMPLAINTSTRING" => "APPEARANCE/from-mail "], |
497
|
|
|
["SETTING" => CONFIG['APPEARANCE']['support-contact']['url'], |
498
|
|
|
"DEFVALUE" => "[email protected]?body=Only%20English%20language%20please!", |
499
|
|
|
"COMPLAINTSTRING" => "APPEARANCE/support-contact/url "], |
500
|
|
|
["SETTING" => CONFIG['APPEARANCE']['support-contact']['display'], |
501
|
|
|
"DEFVALUE" => "[email protected]", |
502
|
|
|
"COMPLAINTSTRING" => "APPEARANCE/support-contact/display "], |
503
|
|
|
["SETTING" => CONFIG['APPEARANCE']['support-contact']['developer-mail'], |
504
|
|
|
"DEFVALUE" => "[email protected]", |
505
|
|
|
"COMPLAINTSTRING" => "APPEARANCE/support-contact/mail "], |
506
|
|
|
["SETTING" => CONFIG['APPEARANCE']['abuse-mail'], |
507
|
|
|
"DEFVALUE" => "[email protected]", |
508
|
|
|
"COMPLAINTSTRING" => "APPEARANCE/abuse-mail "], |
509
|
|
|
["SETTING" => CONFIG['APPEARANCE']['MOTD'], |
510
|
|
|
"DEFVALUE" => "Release Candidate. All bugs to be shot on sight!", |
511
|
|
|
"COMPLAINTSTRING" => "APPEARANCE/MOTD "], |
512
|
|
|
["SETTING" => CONFIG['APPEARANCE']['webcert_CRLDP'], |
513
|
|
|
"DEFVALUE" => ['list', 'of', 'CRL', 'pointers'], |
514
|
|
|
"COMPLAINTSTRING" => "APPEARANCE/webcert_CRLDP "], |
515
|
|
|
["SETTING" => CONFIG['DB']['INST']['host'], |
516
|
|
|
"DEFVALUE" => "db.host.example", |
517
|
|
|
"COMPLAINTSTRING" => "DB/INST "], |
518
|
|
|
["SETTING" => CONFIG['DB']['INST']['host'], |
519
|
|
|
"DEFVALUE" => "db.host.example", |
520
|
|
|
"COMPLAINTSTRING" => "DB/USER "], |
521
|
|
|
]; |
522
|
|
|
|
523
|
|
|
/** |
524
|
|
|
* test if defaults in the config have been replaced with some real values |
525
|
|
|
*/ |
526
|
|
|
private function defaults_test() { |
527
|
|
|
$defaultvalues = ""; |
528
|
|
|
$missingvalues = ""; |
529
|
|
|
// all the checks for equality with a shipped default value |
530
|
|
|
foreach (SanityTests::DEFAULTS as $oneCheckItem) { |
531
|
|
|
if ($oneCheckItem['SETTING'] == $oneCheckItem["DEFVALUE"]) { |
532
|
|
|
$defaultvalues .= $oneCheckItem["COMPLAINTSTRING"]; |
533
|
|
|
} |
534
|
|
|
} |
535
|
|
|
// additional checks for defaults, which are not simple equality checks |
536
|
|
|
if (empty(CONFIG['APPEARANCE']['webcert_OCSP'])) { |
537
|
|
|
$missingvalues .= "APPEARANCE/webcert_OCSP "; |
538
|
|
|
} elseif (CONFIG['APPEARANCE']['webcert_OCSP'] == ['list', 'of', 'OCSP', 'pointers']) { |
539
|
|
|
$defaultvalues .= "APPEARANCE/webcert_OCSP "; |
540
|
|
|
} |
541
|
|
|
if (isset(CONFIG_DIAGNOSTICS['RADIUSTESTS']['UDP-hosts'][0]) && CONFIG_DIAGNOSTICS['RADIUSTESTS']['UDP-hosts'][0]['ip'] == "192.0.2.1") { |
542
|
|
|
$defaultvalues .= "RADIUSTESTS/UDP-hosts "; |
543
|
|
|
} |
544
|
|
|
if (!empty(CONFIG['DB']['EXTERNAL']) && CONFIG['DB']['EXTERNAL']['host'] == "customerdb.otherhost.example") { |
545
|
|
|
$defaultvalues .= "DB/EXTERNAL "; |
546
|
|
|
} |
547
|
|
|
$files = []; |
548
|
|
|
foreach (CONFIG_DIAGNOSTICS['RADIUSTESTS']['TLS-clientcerts'] as $cadata) { |
549
|
|
|
foreach ($cadata['certificates'] as $cert_files) { |
550
|
|
|
$files[] = $cert_files['public']; |
551
|
|
|
$files[] = $cert_files['private']; |
552
|
|
|
} |
553
|
|
|
} |
554
|
|
|
|
555
|
|
|
foreach ($files as $file) { |
556
|
|
|
$handle = fopen(ROOT . "/config/cli-certs/" . $file, 'r'); |
557
|
|
|
if (!$handle) { |
558
|
|
|
$defaultvalues .= "CERTIFICATE/$file "; |
559
|
|
|
} else { |
560
|
|
|
fclose($handle); |
561
|
|
|
} |
562
|
|
|
} |
563
|
|
View Code Duplication |
if ($defaultvalues != "") { |
564
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "Your configuration in config/config.php contains unchanged default values or links to inexistent files: <strong>$defaultvalues</strong>!"); |
565
|
|
|
} else { |
566
|
|
|
$this->test_return(\core\common\Entity::L_OK, "Your configuration does not contain any unchanged defaults, which is a good sign."); |
567
|
|
|
} |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
/** |
571
|
|
|
* test access to databases |
572
|
|
|
*/ |
573
|
|
|
private function databases_test() { |
574
|
|
|
$databaseName1 = 'INST'; |
575
|
|
|
$db1 = mysqli_connect(CONFIG['DB'][$databaseName1]['host'], CONFIG['DB'][$databaseName1]['user'], CONFIG['DB'][$databaseName1]['pass'], CONFIG['DB'][$databaseName1]['db']); |
576
|
|
View Code Duplication |
if (!$db1) { |
|
|
|
|
577
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Connection to the $databaseName1 database failed"); |
578
|
|
|
} else { |
579
|
|
|
$r = mysqli_query($db1, 'select * from profile_option_dict'); |
580
|
|
|
if ($r->num_rows == $this->profile_option_ct) { |
581
|
|
|
$this->test_return(\core\common\Entity::L_OK, "The $databaseName1 database appears to be OK."); |
582
|
|
|
} else { |
583
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "The $databaseName1 database is reacheable but probably not updated to this version of CAT."); |
584
|
|
|
} |
585
|
|
|
} |
586
|
|
|
$databaseName2 = 'USER'; |
587
|
|
|
$db2 = mysqli_connect(CONFIG['DB'][$databaseName2]['host'], CONFIG['DB'][$databaseName2]['user'], CONFIG['DB'][$databaseName2]['pass'], CONFIG['DB'][$databaseName2]['db']); |
588
|
|
View Code Duplication |
if (!$db2) { |
|
|
|
|
589
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Connection to the $databaseName2 database failed"); |
590
|
|
|
} else { |
591
|
|
|
$r = mysqli_query($db2, 'desc view_admin'); |
592
|
|
|
if ($r->num_rows == $this->view_admin_ct) { |
593
|
|
|
$this->test_return(\core\common\Entity::L_OK, "The $databaseName2 database appears to be OK."); |
594
|
|
|
} else { |
595
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "The $databaseName2 is reacheable but there is something wrong with the schema"); |
596
|
|
|
} |
597
|
|
|
} |
598
|
|
|
$databaseName3 = 'EXTERNAL'; |
599
|
|
|
if (!empty(CONFIG['DB'][$databaseName3])) { |
600
|
|
|
$db3 = mysqli_connect(CONFIG['DB'][$databaseName3]['host'], CONFIG['DB'][$databaseName3]['user'], CONFIG['DB'][$databaseName3]['pass'], CONFIG['DB'][$databaseName3]['db']); |
601
|
|
View Code Duplication |
if (!$db3) { |
|
|
|
|
602
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Connection to the $databaseName3 database failed"); |
603
|
|
|
} else { |
604
|
|
|
$r = mysqli_query($db3, 'desc view_admin'); |
605
|
|
|
if ($r->num_rows == $this->view_admin_ct) { |
606
|
|
|
$this->test_return(\core\common\Entity::L_OK, "The $databaseName3 database appears to be OK."); |
607
|
|
|
} else { |
608
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "The $databaseName3 is reacheable but there is something wrong with the schema"); |
609
|
|
|
} |
610
|
|
|
} |
611
|
|
|
} |
612
|
|
|
} |
613
|
|
|
|
614
|
|
|
/** |
615
|
|
|
* test devices.php for the no_cache option |
616
|
|
|
*/ |
617
|
|
|
private function device_cache_test() { |
618
|
|
|
if ((!empty(\devices\Devices::$Options['no_cache'])) && \devices\Devices::$Options['no_cache']) { |
619
|
|
|
$global_no_cache = 1; |
620
|
|
|
} else { |
621
|
|
|
$global_no_cache = 0; |
622
|
|
|
} |
623
|
|
|
|
624
|
|
|
if ($global_no_cache == 1) { |
625
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "Devices no_cache global option is set, this is not a good idea in a production setting\n"); |
626
|
|
|
} |
627
|
|
|
$Devs = \devices\Devices::listDevices(); |
628
|
|
|
$no_cache_dev = ''; |
629
|
|
|
$no_cache_dev_count = 0; |
630
|
|
|
if ($global_no_cache) { |
631
|
|
View Code Duplication |
foreach ($Devs as $dev => $D) { |
|
|
|
|
632
|
|
|
if (empty($D['options']['no_cache']) || $D['options']['no_cache'] != 0) { |
633
|
|
|
$no_cache_dev .= $dev . " "; |
634
|
|
|
$no_cache_dev_count++; |
635
|
|
|
} |
636
|
|
|
} |
637
|
|
|
} else { |
638
|
|
View Code Duplication |
foreach ($Devs as $dev => $D) { |
|
|
|
|
639
|
|
|
if (!empty($D['options']['no_cache']) && $D['options']['no_cache'] != 0) { |
640
|
|
|
$no_cache_dev .= $dev . " "; |
641
|
|
|
$no_cache_dev_count++; |
642
|
|
|
} |
643
|
|
|
} |
644
|
|
|
} |
645
|
|
|
|
646
|
|
|
|
647
|
|
|
if ($no_cache_dev_count > 1) { |
648
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "The following devices will not be cached: $no_cache_dev"); |
649
|
|
|
} |
650
|
|
|
if ($no_cache_dev_count == 1) { |
651
|
|
|
$this->test_return(\core\common\Entity::L_WARN, "The following device will not be cached: $no_cache_dev"); |
652
|
|
|
} |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
/** |
656
|
|
|
* test if mailer works |
657
|
|
|
*/ |
658
|
|
|
private function mailer_test() { |
659
|
|
|
if (empty(CONFIG['APPEARANCE']['abuse-mail']) || CONFIG['APPEARANCE']['abuse-mail'] == "[email protected]") { |
660
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "Your abuse-mail has not been set, cannot continue with mailer tests."); |
661
|
|
|
return; |
662
|
|
|
} |
663
|
|
|
$mail = new \PHPMailer\PHPMailer\PHPMailer(); |
664
|
|
|
$mail->isSMTP(); |
665
|
|
|
$mail->Port = 587; |
666
|
|
|
$mail->SMTPAuth = true; |
667
|
|
|
$mail->SMTPSecure = 'tls'; |
668
|
|
|
$mail->Host = CONFIG['MAILSETTINGS']['host']; |
669
|
|
|
$mail->Username = CONFIG['MAILSETTINGS']['user']; |
670
|
|
|
$mail->Password = CONFIG['MAILSETTINGS']['pass']; |
671
|
|
|
$mail->WordWrap = 72; |
672
|
|
|
$mail->isHTML(FALSE); |
673
|
|
|
$mail->CharSet = 'UTF-8'; |
674
|
|
|
$mail->From = CONFIG['APPEARANCE']['from-mail']; |
675
|
|
|
$mail->FromName = CONFIG['APPEARANCE']['productname'] . " Invitation System"; |
676
|
|
|
$mail->addAddress(CONFIG['APPEARANCE']['abuse-mail']); |
677
|
|
|
$mail->Subject = "testing CAT configuration mail"; |
678
|
|
|
$mail->Body = "Testing CAT mailing\n"; |
679
|
|
|
$sent = $mail->send(); |
680
|
|
|
if ($sent) { |
681
|
|
|
$this->test_return(\core\common\Entity::L_OK, "mailer settings appear to be working, check " . CONFIG['APPEARANCE']['abuse-mail'] . " mailbox if the message was receiced."); |
682
|
|
|
} else { |
683
|
|
|
$this->test_return(\core\common\Entity::L_ERROR, "mailer settings failed, check the Config::MAILSETTINGS"); |
684
|
|
|
} |
685
|
|
|
} |
686
|
|
|
|
687
|
|
|
/** |
688
|
|
|
* TODO test if RADIUS connections work |
689
|
|
|
*/ |
690
|
|
|
private function UDPhosts_test() { |
691
|
|
|
// if(empty) |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
} |
695
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.