Subversion Repositories ggsysinfo

[/] [modules/] [sysinfo/] [lib/] [PhpSecInfo/] [Test/] [Test.php] - Blame information for rev 123

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 123 gg
<?php
2
/**
3
 * Skeleton Test class file
4
 *
5
 * @package PhpSecInfo
6
 * @author Ed Finkler <coj@funkatron.com>
7
 */
8
 
9
/**
10
 * require the main PhpSecInfo class
11
 */
12
require_once(PHPSECINFO_BASE_DIR.'/PhpSecInfo.php');
13
 
14
 
15
 
16
define ('PHPSECINFO_TEST_RESULT_OK', -1);
17
 
18
define ('PHPSECINFO_TEST_RESULT_NOTICE', -2);
19
 
20
define ('PHPSECINFO_TEST_RESULT_WARN', -4);
21
 
22
define ('PHPSECINFO_TEST_RESULT_ERROR', -1024);
23
 
24
define ('PHPSECINFO_TEST_RESULT_NOTRUN', -2048);
25
 
26
define ('PHPSECINFO_TEST_COMMON_TMPDIR', '/tmp');
27
 
28
define ('PHPSECINFO_TEST_MOREINFO_BASEURL', 'http://phpsec.org/projects/phpsecinfo/tests/');
29
 
30
/**
31
 * This is a skeleton class for PhpSecInfo tests  You should extend this to make a "group" skeleton
32
 * to categorize tests under, then make a subdir with your group name that contains test classes
33
 * extending your group skeleton class.
34
 * @package PhpSecInfo
35
 */
36
class PhpSecInfo_Test
37
{
38
 
39
        /**
40
         * This value is used to group test results together.
41
         *
42
         * For example, all tests related to the mysql lib should be grouped under "mysql."
43
         *
44
         * @var string
45
         */
46
        var $test_group = 'misc';
47
 
48
 
49
        /**
50
         * This should be a <b>unique</b>, human-readable identifier for this test
51
         *
52
         * @var string
53
         */
54
        var $test_name  = 'misc_test';
55
 
56
 
57
        /**
58
         * This is the recommended value the test will be looking for
59
         *
60
         * @var mixed
61
         */
62
        var $recommended_value = "bar";
63
 
64
 
65
        /**
66
         * The result returned from the test
67
         *
68
         * @var integer
69
         */
70
        var $_result = PHPSECINFO_TEST_RESULT_NOTRUN;
71
 
72
 
73
        /**
74
         * The message corresponding to the result of the test
75
         *
76
         * @var string
77
         */
78
        var $_message;
79
 
80
 
81
        /**
82
         * the language code.  Should be a pointer to the setting in the PhpSecInfo object
83
         *
84
         * @var string
85
         */
86
        var $_language = PHPSECINFO_LANG_DEFAULT;
87
 
88
        /**
89
         * Enter description here...
90
         *
91
         * @var mixed
92
         */
93
        var $current_value;
94
 
95
        /**
96
         * This is a hash of messages that correspond to various test result levels.
97
         *
98
         * There are five messages, each corresponding to one of the result constants
99
         * (PHPSECINFO_TEST_RESULT_OK, PHPSECINFO_TEST_RESULT_NOTICE, PHPSECINFO_TEST_RESULT_WARN,
100
         * PHPSECINFO_TEST_RESULT_ERROR, PHPSECINFO_TEST_RESULT_NOTRUN)
101
         *
102
         *
103
         * @var array array
104
         */
105
        var $_messages = array();
106
 
107
 
108
 
109
 
110
        /**
111
         * Constructor for Test skeleton class
112
         *
113
         * @return PhpSecInfo_Test
114
         */
115
        function PhpSecInfo_Test() {
116
                //$this->_setTestValues();
117
 
118
                $this->_retrieveCurrentValue();
119
                //$this->setRecommendedValue();
120
 
121
                $this->_setMessages();
122
        }
123
 
124
 
125
        /**
126
         * Determines whether or not it's appropriate to run this test (for example, if
127
         * this test is for a particular library, it shouldn't be run if the lib isn't
128
         * loaded).
129
         *
130
         * This is a terrible name, but I couldn't think of a better one atm.
131
         *
132
         * @return boolean
133
         */
134
        function isTestable() {
135
 
136
                return true;
137
        }
138
 
139
 
140
        /**
141
         * The "meat" of the test.  This is where the real test code goes.  You should override this when extending
142
         *
143
         * @return integer
144
         */
145
        function _execTest() {
146
 
147
                return PHPSECINFO_TEST_RESULT_NOTRUN;
148
        }
149
 
150
 
151
        /**
152
         * This function loads up result messages into the $this->_messages array.
153
         *
154
         * Using this method rather than setting $this->_messages directly allows result
155
         * messages to be inherited.  This is broken out into a separate function rather
156
         * than the constructor for ease of extension purposes (php4 is whack, man).
157
         *
158
         */
159
        function _setMessages() {
160
                $this->setMessageForResult(PHPSECINFO_TEST_RESULT_OK,           'en', 'This setting should be safe');
161
                $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTICE,       'en', 'This could potentially be a security issue');
162
                $this->setMessageForResult(PHPSECINFO_TEST_RESULT_WARN, 'en', 'This setting may be a serious security problem');
163
                $this->setMessageForResult(PHPSECINFO_TEST_RESULT_ERROR,        'en', 'There was an error running this test');
164
                $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTRUN,       'en', 'This test cannot be run');
165
        }
166
 
167
 
168
        /**
169
         * Placeholder - extend for tests
170
         *
171
         */
172
        function _retrieveCurrentValue() {
173
                $this->current_value = "foo";
174
        }
175
 
176
 
177
 
178
        /**
179
         * This is the wrapper that executes the test and sets the result code and message
180
         */
181
        function test() {
182
                $result = $this->_execTest();
183
                $this->_setResult($result);
184
 
185
        }
186
 
187
 
188
 
189
        /**
190
         * Retrieves the result
191
         *
192
         * @return integer
193
         */
194
        function getResult() {
195
                return $this->_result;
196
        }
197
 
198
 
199
 
200
 
201
        /**
202
         * Retrieves the message for the current result
203
         *
204
         * @return string
205
         */
206
        function getMessage() {
207
                if (!isset($this->_message) || empty($this->_message)) {
208
                        $this->_setMessage($this->_result, $this->_language);
209
                }
210
 
211
                return $this->_message;
212
        }
213
 
214
 
215
 
216
        /**
217
         * Sets the message for a given result code and language
218
         *
219
         * <code>
220
         * $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTRUN,    'en', 'This test cannot be run');
221
         * </code>
222
         *
223
         * @param integer $result_code
224
         * @param string $language_code
225
         * @param string $message
226
         *
227
         */
228
        function setMessageForResult($result_code, $language_code, $message) {
229
 
230
                if ( !isset($this->_messages[$result_code]) ) {
231
                        $this->_messages[$result_code] = array();
232
                }
233
 
234
                if ( !is_array($this->_messages[$result_code]) ) {
235
                        $this->_messages[$result_code] = array();
236
                }
237
 
238
                $this->_messages[$result_code][$language_code] = $message;
239
 
240
        }
241
 
242
 
243
 
244
 
245
        /**
246
         * returns the current value.  This function should be used to access the
247
         * value for display.  All values are cast as strings
248
         *
249
         * @return string
250
         */
251
        function getCurrentTestValue() {
252
                return $this->getStringValue($this->current_value);
253
        }
254
 
255
        /**
256
         * returns the recommended value.  This function should be used to access the
257
         * value for display.  All values are cast as strings
258
         *
259
         * @return string
260
         */
261
        function getRecommendedTestValue() {
262
                return $this->getStringValue($this->recommended_value);
263
        }
264
 
265
 
266
        /**
267
         * Sets the result code
268
         *
269
         * @param integer $result_code
270
         */
271
        function _setResult($result_code) {
272
                $this->_result = $result_code;
273
        }
274
 
275
 
276
        /**
277
         * Sets the $this->_message variable based on the passed result and language codes
278
         *
279
         * @param integer $result_code
280
         * @param string $language_code
281
         */
282
        function _setMessage($result_code, $language_code) {
283
                $messages = $this->_messages[$result_code];
284
                $message  = $messages[$language_code];
285
                $this->_message = $message;
286
        }
287
 
288
 
289
        /**
290
         * Returns a link to a page with detailed information about the test
291
         *
292
         * URL is formatted as PHPSECINFO_TEST_MOREINFO_BASEURL + testName
293
         *
294
         * @see PHPSECINFO_TEST_MOREINFO_BASEURL
295
         *
296
         * @return string|boolean
297
         */
298
        function getMoreInfoURL() {
299
                if ($tn = $this->getTestName()) {
300
                        return PHPSECINFO_TEST_MOREINFO_BASEURL.strtolower("{$tn}.html");
301
                } else {
302
                        return false;
303
                }
304
        }
305
 
306
 
307
 
308
 
309
        /**
310
         * This retrieves the name of this test.
311
         *
312
         * If a name has not been set, this returns a formatted version of the class name.
313
         *
314
         * @return string
315
         */
316
        function getTestName() {
317
                if (isset($this->test_name) && !empty($this->test_name)) {
318
                        return $this->test_name;
319
                } else {
320
                        return ucwords(
321
                        str_replace('_', ' ',
322
                        get_class($this)
323
                        )
324
                        );
325
                }
326
 
327
        }
328
 
329
 
330
        /**
331
         * sets the test name
332
         *
333
         * @param string $test_name
334
         */
335
        function setTestName($test_name) {
336
                $this->test_name = $test_name;
337
        }
338
 
339
 
340
        /**
341
         * Returns the test group this test belongs to
342
         *
343
         * @return string
344
         */
345
        function getTestGroup() {
346
                return $this->test_group;
347
        }
348
 
349
 
350
        /**
351
         * sets the test group
352
         *
353
         * @param string $test_group
354
         */
355
        function setTestGroup($test_group) {
356
                $this->test_group = $test_group;
357
        }
358
 
359
 
360
        /**
361
         * This function takes the shorthand notation used in memory limit settings for PHP
362
         * and returns the byte value.  Totally stolen from http://us3.php.net/manual/en/function.ini-get.php
363
         *
364
         * <code>
365
         * echo 'post_max_size in bytes = ' . $this->return_bytes(ini_get('post_max_size'));
366
         * </code>
367
         *
368
         * @link http://php.net/manual/en/function.ini-get.php
369
         * @param string $val
370
         * @return integer
371
         */
372
        function returnBytes($val) {
373
                $val = trim($val);
374
 
375
                if ( (int)$val === 0 ) {
376
                        return 0;
377
                }
378
 
379
                $last = strtolower($val{strlen($val)-1});
380
                switch($last) {
381
                        // The 'G' modifier is available since PHP 5.1.0
382
                        case 'g':
383
                                $val *= 1024;
384
                        case 'm':
385
                                $val *= 1024;
386
                        case 'k':
387
                                $val *= 1024;
388
                }
389
 
390
                return $val;
391
        }
392
 
393
 
394
        /**
395
         * This just does the usual PHP string casting, except for
396
         * the boolean FALSE value, where the string "0" is returned
397
         * instead of an empty string
398
         *
399
         * @param mixed $val
400
         * @return string
401
         */
402
        function getStringValue($val) {
403
                if ($val === FALSE) {
404
                        return "0";
405
                } else {
406
                        return (string)$val;
407
                }
408
        }
409
 
410
 
411
        /**
412
         * This method converts the several possible return values from
413
         * allegedly "boolean" ini settings to proper booleans
414
         *
415
         * Properly converted input values are: 'off', 'on', 'false', 'true', '', '0', '1'
416
         * (the last two might not be neccessary, but I'd rather be safe)
417
         *
418
         * If the ini_value doesn't match any of those, the value is returned as-is.
419
         *
420
         * @param string $ini_key   the ini_key you need the value of
421
         * @return boolean|mixed
422
         */
423
        function getBooleanIniValue($ini_key) {
424
 
425
                $ini_val = ini_get($ini_key);
426
 
427
                switch ( strtolower($ini_val) ) {
428
 
429
                        case 'off':
430
                                return false;
431
                                break;
432
                        case 'on':
433
                                return true;
434
                                break;
435
                        case 'false':
436
                                return false;
437
                                break;
438
                        case 'true':
439
                                return true;
440
                                break;
441
                        case '0':
442
                                return false;
443
                                break;
444
                        case '1':
445
                                return true;
446
                                break;
447
                        case '':
448
                                return false;
449
                                break;
450
                        default:
451
                                return $ini_val;
452
 
453
                }
454
 
455
        }
456
 
457
        /**
458
         * sys_get_temp_dir provides some temp dir detection capability
459
         * that is lacking in versions of PHP that do not have the
460
         * sys_get_temp_dir() function
461
         *
462
         * @return string|NULL
463
         */
464
        function sys_get_temp_dir() {
465
                // Try to get from environment variable
466
                $vars = array('TMP', 'TMPDIR', 'TEMP');
467
                foreach($vars as $var) {
468
                        $tmp = getenv($var);
469
                        if ( !empty($tmp) ) {
470
                                return realpath( $tmp );
471
                        }
472
                }
473
                return NULL;
474
        }
475
 
476
 
477
        /**
478
         * A quick function to determine whether we're running on Windows.
479
         * Uses the PHP_OS constant.
480
         *
481
         * @return boolean
482
         */
483
        function osIsWindows() {
484
                if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
485
                        return true;
486
                } else {
487
                        return false;
488
                }
489
        }
490
 
491
 
492
        /**
493
         * Returns an array of data returned from the UNIX 'id' command
494
         *
495
         * includes uid, username, gid, groupname, and groups (if "exec"
496
         * is enabled). Groups is an array of all the groups the user
497
         * belongs to.  Keys are the group ids, values are the group names.
498
         *
499
         * returns FALSE if no suitable function is available to retrieve
500
         * the data
501
         *
502
         * @return array|boolean
503
         */
504
        function getUnixId() {
505
 
506
                if ($this->osIsWindows()) {
507
                        return false;
508
                }
509
 
510
                $success = false;
511
 
512
 
513
                if (function_exists("exec") && !PhpSecInfo_Test::getBooleanIniValue('safe_mode')) {
514
                        $id_raw = exec('id');
515
                        // uid=1000(coj) gid=1000(coj) groups=1000(coj),1001(admin)
516
                        preg_match( "|uid=(\d+)\((\S+)\)\s+gid=(\d+)\((\S+)\)\s+groups=(.+)|i",
517
                                                $id_raw,
518
                                                $matches);
519
 
520
                        if (!$matches) {
521
                                /**
522
                                 * for some reason the output from 'id' wasn't as we expected.
523
                                 * return false so the test doesn't run.
524
                                 */
525
                                $success = false;
526
                        } else {
527
                                $id_data = array(       'uid'=>$matches[1],
528
                                                                        'username'=>$matches[2],
529
                                                                        'gid'=>$matches[3],
530
                                                                        'group'=>$matches[4] );
531
 
532
                                $groups = array();
533
                                if ($matches[5]) {
534
                                        $gs = $matches[5];
535
                                        $gs = explode(',', $gs);
536
                                        foreach ($gs as $groupstr) {
537
                                                preg_match("/(\d+)\(([^\)]+)\)/", $groupstr, $subs);
538
                                                $groups[$subs[1]] = $subs[2];
539
                                        }
540
                                        ksort($groups);
541
                                }
542
                                $id_data['groups'] = $groups;
543
                                $success = true;
544
                        }
545
 
546
                }
547
 
548
                if (!$success && function_exists("posix_getpwuid") && function_exists("posix_geteuid")
549
                        && function_exists('posix_getgrgid') && function_exists('posix_getgroups') ) {
550
                        $data = posix_getpwuid( posix_getuid() );
551
                        $id_data['uid'] = $data['uid'];
552
                        $id_data['username'] = $data['name'];
553
                        $id_data['gid'] = $data['gid'];
554
                        //$group_data = posix_getgrgid( posix_getegid() );
555
                        //$id_data['group'] = $group_data['name'];
556
                        $id_data['groups'] = array();
557
                        $groups = posix_getgroups();
558
                        foreach ( $groups as $gid ) {
559
                                //$group_data = posix_getgrgid(posix_getgid());
560
                                $id_data['groups'][$gid] = '<unknown>';
561
                        }
562
                        $success = true;
563
                }
564
 
565
                if ($success) {
566
                        return $id_data;
567
                } else {
568
                        return false;
569
                }
570
        }
571
 
572
}