diff options
author | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2010-06-23 07:45:36 +0400 |
---|---|---|
committer | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2010-06-23 07:45:36 +0400 |
commit | 7e1b5d6b762340cbff1bb928d15815980c7649a7 (patch) | |
tree | e07da179b9e1372866d2349777bd1cc6b4c9e8cf /plugins/SecurityInfo/PhpSecInfo/Test/Test.php | |
parent | 999f46479294713104c962bfe7469e9b6e7a4bbf (diff) | |
parent | c98ea06f2cccec81c6ccce49162a583494e44d91 (diff) |
Diffstat (limited to 'plugins/SecurityInfo/PhpSecInfo/Test/Test.php')
-rw-r--r-- | plugins/SecurityInfo/PhpSecInfo/Test/Test.php | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/plugins/SecurityInfo/PhpSecInfo/Test/Test.php b/plugins/SecurityInfo/PhpSecInfo/Test/Test.php new file mode 100644 index 0000000000..5b577dfece --- /dev/null +++ b/plugins/SecurityInfo/PhpSecInfo/Test/Test.php @@ -0,0 +1,571 @@ +<?php +/** + * Skeleton Test class file + * + * @package PhpSecInfo + * @author Ed Finkler <coj@funkatron.com> + */ + +/** + * require the main PhpSecInfo class + */ +require_once(PHPSECINFO_BASE_DIR.'/PhpSecInfo.php'); + + + +define ('PHPSECINFO_TEST_RESULT_OK', -1); + +define ('PHPSECINFO_TEST_RESULT_NOTICE', -2); + +define ('PHPSECINFO_TEST_RESULT_WARN', -4); + +define ('PHPSECINFO_TEST_RESULT_ERROR', -1024); + +define ('PHPSECINFO_TEST_RESULT_NOTRUN', -2048); + +define ('PHPSECINFO_TEST_COMMON_TMPDIR', '/tmp'); + +define ('PHPSECINFO_TEST_MOREINFO_BASEURL', 'http://phpsec.org/projects/phpsecinfo/tests/'); + +/** + * This is a skeleton class for PhpSecInfo tests You should extend this to make a "group" skeleton + * to categorize tests under, then make a subdir with your group name that contains test classes + * extending your group skeleton class. + * @package PhpSecInfo + */ +class PhpSecInfo_Test +{ + + /** + * This value is used to group test results together. + * + * For example, all tests related to the mysql lib should be grouped under "mysql." + * + * @var string + */ + var $test_group = 'misc'; + + + /** + * This should be a <b>unique</b>, human-readable identifier for this test + * + * @var string + */ + var $test_name = 'misc_test'; + + + /** + * This is the recommended value the test will be looking for + * + * @var mixed + */ + var $recommended_value = "bar"; + + + /** + * The result returned from the test + * + * @var integer + */ + var $_result = PHPSECINFO_TEST_RESULT_NOTRUN; + + + /** + * The message corresponding to the result of the test + * + * @var string + */ + var $_message; + + + /** + * the language code. Should be a pointer to the setting in the PhpSecInfo object + * + * @var string + */ + var $_language = PHPSECINFO_LANG_DEFAULT; + + /** + * Enter description here... + * + * @var mixed + */ + var $current_value; + + /** + * This is a hash of messages that correspond to various test result levels. + * + * There are five messages, each corresponding to one of the result constants + * (PHPSECINFO_TEST_RESULT_OK, PHPSECINFO_TEST_RESULT_NOTICE, PHPSECINFO_TEST_RESULT_WARN, + * PHPSECINFO_TEST_RESULT_ERROR, PHPSECINFO_TEST_RESULT_NOTRUN) + * + * + * @var array array + */ + var $_messages = array(); + + + + + /** + * Constructor for Test skeleton class + * + * @return PhpSecInfo_Test + */ + function PhpSecInfo_Test() { + //$this->_setTestValues(); + + $this->_retrieveCurrentValue(); + //$this->setRecommendedValue(); + + $this->_setMessages(); + } + + + /** + * Determines whether or not it's appropriate to run this test (for example, if + * this test is for a particular library, it shouldn't be run if the lib isn't + * loaded). + * + * This is a terrible name, but I couldn't think of a better one atm. + * + * @return boolean + */ + function isTestable() { + + return true; + } + + + /** + * The "meat" of the test. This is where the real test code goes. You should override this when extending + * + * @return integer + */ + function _execTest() { + + return PHPSECINFO_TEST_RESULT_NOTRUN; + } + + + /** + * This function loads up result messages into the $this->_messages array. + * + * Using this method rather than setting $this->_messages directly allows result + * messages to be inherited. This is broken out into a separate function rather + * than the constructor for ease of extension purposes (php4 is whack, man). + * + */ + function _setMessages() { + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_OK, 'en', 'This setting should be safe'); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTICE, 'en', 'This could potentially be a security issue'); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_WARN, 'en', 'This setting may be a serious security problem'); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_ERROR, 'en', 'There was an error running this test'); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTRUN, 'en', 'This test cannot be run'); + } + + + /** + * Placeholder - extend for tests + * + */ + function _retrieveCurrentValue() { + $this->current_value = "foo"; + } + + + + /** + * This is the wrapper that executes the test and sets the result code and message + */ + function test() { + $result = $this->_execTest(); + $this->_setResult($result); + + } + + + + /** + * Retrieves the result + * + * @return integer + */ + function getResult() { + return $this->_result; + } + + + + + /** + * Retrieves the message for the current result + * + * @return string + */ + function getMessage() { + if (!isset($this->_message) || empty($this->_message)) { + $this->_setMessage($this->_result, $this->_language); + } + + return $this->_message; + } + + + + /** + * Sets the message for a given result code and language + * + * <code> + * $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTRUN, 'en', 'This test cannot be run'); + * </code> + * + * @param integer $result_code + * @param string $language_code + * @param string $message + * + */ + function setMessageForResult($result_code, $language_code, $message) { + + if ( !isset($this->_messages[$result_code]) ) { + $this->_messages[$result_code] = array(); + } + + if ( !is_array($this->_messages[$result_code]) ) { + $this->_messages[$result_code] = array(); + } + + $this->_messages[$result_code][$language_code] = $message; + + } + + + + + /** + * returns the current value. This function should be used to access the + * value for display. All values are cast as strings + * + * @return string + */ + function getCurrentTestValue() { + return $this->getStringValue($this->current_value); + } + + /** + * returns the recommended value. This function should be used to access the + * value for display. All values are cast as strings + * + * @return string + */ + function getRecommendedTestValue() { + return $this->getStringValue($this->recommended_value); + } + + + /** + * Sets the result code + * + * @param integer $result_code + */ + function _setResult($result_code) { + $this->_result = $result_code; + } + + + /** + * Sets the $this->_message variable based on the passed result and language codes + * + * @param integer $result_code + * @param string $language_code + */ + function _setMessage($result_code, $language_code) { + $messages = $this->_messages[$result_code]; + $message = $messages[$language_code]; + $this->_message = $message; + } + + + /** + * Returns a link to a page with detailed information about the test + * + * URL is formatted as PHPSECINFO_TEST_MOREINFO_BASEURL + testName + * + * @see PHPSECINFO_TEST_MOREINFO_BASEURL + * + * @return string|boolean + */ + function getMoreInfoURL() { + if ($tn = $this->getTestName()) { + return PHPSECINFO_TEST_MOREINFO_BASEURL.strtolower("{$tn}.html"); + } else { + return false; + } + } + + + + + /** + * This retrieves the name of this test. + * + * If a name has not been set, this returns a formatted version of the class name. + * + * @return string + */ + function getTestName() { + if (isset($this->test_name) && !empty($this->test_name)) { + return $this->test_name; + } else { + return ucwords( + str_replace('_', ' ', + get_class($this) + ) + ); + } + + } + + + /** + * sets the test name + * + * @param string $test_name + */ + function setTestName($test_name) { + $this->test_name = $test_name; + } + + + /** + * Returns the test group this test belongs to + * + * @return string + */ + function getTestGroup() { + return $this->test_group; + } + + + /** + * sets the test group + * + * @param string $test_group + */ + function setTestGroup($test_group) { + $this->test_group = $test_group; + } + + + /** + * This function takes the shorthand notation used in memory limit settings for PHP + * and returns the byte value. Totally stolen from http://us3.php.net/manual/en/function.ini-get.php + * + * <code> + * echo 'post_max_size in bytes = ' . $this->return_bytes(ini_get('post_max_size')); + * </code> + * + * @link http://php.net/manual/en/function.ini-get.php + * @param string $val + * @return integer + */ + function returnBytes($val) { + $val = trim($val); + + if ( (int)$val === 0 ) { + return 0; + } + + $last = strtolower($val{strlen($val)-1}); + switch($last) { + // The 'G' modifier is available since PHP 5.1.0 + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + } + + return $val; + } + + + /** + * This just does the usual PHP string casting, except for + * the boolean FALSE value, where the string "0" is returned + * instead of an empty string + * + * @param mixed $val + * @return string + */ + function getStringValue($val) { + if ($val === FALSE) { + return "0"; + } else { + return (string)$val; + } + } + + + /** + * This method converts the several possible return values from + * allegedly "boolean" ini settings to proper booleans + * + * Properly converted input values are: 'off', 'on', 'false', 'true', '', '0', '1' + * (the last two might not be neccessary, but I'd rather be safe) + * + * If the ini_value doesn't match any of those, the value is returned as-is. + * + * @param string $ini_key the ini_key you need the value of + * @return boolean|mixed + */ + function getBooleanIniValue($ini_key) { + + $ini_val = ini_get($ini_key); + + switch ( strtolower($ini_val) ) { + + case 'off': + return false; + break; + case 'on': + return true; + break; + case 'false': + return false; + break; + case 'true': + return true; + break; + case '0': + return false; + break; + case '1': + return true; + break; + case '': + return false; + break; + default: + return $ini_val; + + } + + } + + /** + * sys_get_temp_dir provides some temp dir detection capability + * that is lacking in versions of PHP that do not have the + * sys_get_temp_dir() function + * + * @return string|NULL + */ + function sys_get_temp_dir() { + // Try to get from environment variable + if ( !empty($_ENV['TMP']) ) { + return realpath( $_ENV['TMP'] ); + } else if ( !empty($_ENV['TMPDIR']) ) { + return realpath( $_ENV['TMPDIR'] ); + } else if ( !empty($_ENV['TEMP']) ) { + return realpath( $_ENV['TEMP'] ); + } else { + return NULL; + } + } + + + /** + * A quick function to determine whether we're running on Windows. + * Uses the PHP_OS constant. + * + * @return boolean + */ + function osIsWindows() { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + return true; + } else { + return false; + } + } + + + /** + * Returns an array of data returned from the UNIX 'id' command + * + * includes uid, username, gid, groupname, and groups (if "exec" + * is enabled). Groups is an array of all the groups the user + * belongs to. Keys are the group ids, values are the group names. + * + * returns FALSE if no suitable function is available to retrieve + * the data + * + * @return array|boolean + */ + function getUnixId() { + + if ($this->osIsWindows()) { + return false; + } + + $success = false; + + + if (function_exists("exec") && !PhpSecInfo_Test::getBooleanIniValue('safe_mode')) { + $id_raw = exec('id'); + // uid=1000(coj) gid=1000(coj) groups=1000(coj),1001(admin) + preg_match( "|uid=(\d+)\((\S+)\)\s+gid=(\d+)\((\S+)\)\s+groups=(.+)|i", + $id_raw, + $matches); + + if (!$matches) { + /** + * for some reason the output from 'id' wasn't as we expected. + * return false so the test doesn't run. + */ + $success = false; + } else { + $id_data = array( 'uid'=>$matches[1], + 'username'=>$matches[2], + 'gid'=>$matches[3], + 'group'=>$matches[4] ); + + if ($matches[5]) { + $gs = $matches[5]; + $gs = explode(',', $gs); + foreach ($gs as $groupstr) { + preg_match("/(\d+)\(([^\)]+)\)/", $groupstr, $subs); + $groups[$subs[1]] = $subs[2]; + } + ksort($groups); + $id_data['groups'] = $groups; + } + $success = true; + } + + } + + if (!$success && function_exists("posix_getpwuid") && function_exists("posix_geteuid") + && function_exists('posix_getgrgid') && function_exists('posix_getgroups') ) { + $data = posix_getpwuid( posix_getuid() ); + $id_data['uid'] = $data['uid']; + $id_data['username'] = $data['name']; + $id_data['gid'] = $data['gid']; + //$group_data = posix_getgrgid( posix_getegid() ); + //$id_data['group'] = $group_data['name']; + $groups = posix_getgroups(); + foreach ( $groups as $gid ) { + //$group_data = posix_getgrgid(posix_getgid()); + $id_data['groups'][$gid] = '<unknown>'; + } + $success = true; + } + + if ($success) { + return $id_data; + } else { + return false; + } + } + +} |