[pkg-nagios-changes] [Git][nagios-team/nagvis][upstream] New upstream version 1.9.42
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Tue Jul 16 04:36:56 BST 2024
Bas Couwenberg pushed to branch upstream at Debian Nagios Maintainer Group / nagvis
Commits:
b8c0eb93 by Bas Couwenberg at 2024-07-16T05:30:44+02:00
New upstream version 1.9.42
- - - - -
17 changed files:
- ChangeLog
- share/frontend/nagvis-js/index.php
- share/frontend/nagvis-js/js/ElementHover.js
- share/frontend/nagvis-js/js/nagvis.js
- share/server/core/classes/CoreAuthHandler.php
- share/server/core/classes/CoreAuthModPDO.php
- share/server/core/classes/CoreAuthModule.php
- share/server/core/classes/CoreLogonMultisite.php
- share/server/core/classes/CorePDOHandler.php
- share/server/core/classes/GlobalCore.php
- share/server/core/classes/GlobalMainCfg.php
- share/server/core/classes/ViewManageMaps.php
- share/server/core/defines/global.php
- share/server/core/defines/matches.php
- share/server/core/functions/oldPhpVersionFixes.php
- + share/server/core/functions/passwordCompatibility.php
- share/userfiles/gadgets/std_table.php
Changes:
=====================================
ChangeLog
=====================================
@@ -1,3 +1,19 @@
+1.9.42
+Security:
+ * FIX: Fix XSS in std_table.php gadget
+ * FIX: Fix XSS for malicious graph elements (CVSS core: 5.4)
+ CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
+ * FIX: Fix potential RCE due to being able to upload and configure a malicious map as authorisation_multisite_file.
+ You can no longer upload such maps and the maps path is excluded from the authorisation_multisite_file upload
+ path. (CVSS score 8.8)
+ CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
+ * FIX: Prevent XSS in NagVis for service names and script outputs (CVSS score: 5.4)
+ CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
+ * FIX: Insecure password hashing algorithm for dedicated NagVis users (CVSS score: 5.1)
+ CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
+ * FIX: Leak of installation path in error message
+ * FIX: Make cookie hash comparison timing safe
+
1.9.41
Frontend:
* FIX: Fix PHP 5.4 compatibility issue (syntax error, unexpected 'list')
=====================================
share/frontend/nagvis-js/index.php
=====================================
@@ -32,6 +32,7 @@ require('defines/nagvis-js.php');
// Include functions
require('../../server/core/classes/CoreExceptions.php');
require('../../server/core/functions/autoload.php');
+require('../../server/core/functions/passwordCompatibility.php');
if (PROFILE) profilingStart();
=====================================
share/frontend/nagvis-js/js/ElementHover.js
=====================================
@@ -496,7 +496,7 @@ var ElementHover = Element.extend({
// Replace all normal macros
template_html = template_html.replace(/\[(\w*)\]/g, function() {
- return oMacros[ arguments[1] ] || "";
+ return htmlspecialchars(oMacros[ arguments[1] ] || "");
});
return template_html;
},
=====================================
share/frontend/nagvis-js/js/nagvis.js
=====================================
@@ -687,6 +687,24 @@ function escapeUrlValues(sStr) {
return sStr;
}
+
+/**
+ * Function to map html special characters into their html entities before
+ * printing them to the screen
+ */
+
+function htmlspecialchars(sStr) {
+ const map = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+ };
+ return sStr.replace(/[&<>"']/g, match => map[match]);
+}
+
+
/**
* Function to dumping arrays/objects in javascript for debugging purposes
* Taken from http://refactormycode.com/codes/226-recursively-dump-an-object
@@ -1024,8 +1042,21 @@ function renderNagVisTextbox(id, bgColor, borderColor, x, y, z, w, h, text, cust
aStyle = null;
}
- oLabelSpan.innerHTML = text;
- executeJS(oLabelSpan);
+ let a_regex = /<a href="([^"]*)".*>.*<\/a>/g;
+ let a_match = a_regex.exec(text);
+ let a_schema = a_match ? a_match[1].split(':')[0] : null;
+ const allowed_url_schemas = ['http', 'https'];
+ if (!a_schema || allowed_url_schemas.includes(a_schema)) {
+ oLabelSpan.innerHTML = text;
+ executeJS(oLabelSpan);
+ }
+ else {
+ eventlog(
+ "renderNagVisTextbox",
+ "critical",
+ "Disallowed link schema in textbox: " + a_match[1]
+ );
+ }
oLabelDiv.appendChild(oLabelSpan);
=====================================
share/server/core/classes/CoreAuthHandler.php
=====================================
@@ -174,6 +174,10 @@ class CoreAuthHandler {
return $this->logoutPossible;
}
+ public function usesBcrypt() {
+ return $this->MOD->usesBcrypt($this->getUser());
+ }
+
public function logout($enforce = false) {
if(!$enforce && !$this->logoutSupported())
return false;
=====================================
share/server/core/classes/CoreAuthModPDO.php
=====================================
@@ -87,20 +87,33 @@ abstract class CoreAuthModPDO extends CoreAuthModule {
return $this->DB->count('-user-count', array('name' => $name));
}
- private function checkUserAuth($bTrustUsername = AUTH_NOT_TRUST_USERNAME) {
- if($bTrustUsername === AUTH_NOT_TRUST_USERNAME) {
- $res = $this->DB->query('-user-get-by-pass', array('name' => $this->sUsername, 'password' => $this->sPasswordHash));
- } else {
- $res = $this->DB->query('-user-get-by-name', array('name' => $this->sUsername));
- }
-
- $data = $res->fetch();
+ private function checkUserAuth() {
+ $data = $this->DB->query('-user-get-by-pass', array('name' => $this->sUsername, 'password' => $this->sPasswordHash))->fetch();
+ if (!isset($data['userId']))
+ return 0;
+ return intval($data['userId']);
+ }
+ private function getTrustedUser() {
+ $data = $this->DB->query('-user-get-by-name', array('name' => $this->sUsername))->fetch();
if (!isset($data['userId']))
return 0;
return intval($data['userId']);
}
+ private function checkBcryptAuth() {
+ if ($this->sPassword === '') {
+ return $this->checkUserAuth();
+ }
+ $data = $this->DB->query('-user-get-pw-hash', array('name' => $this->sUsername))->fetch();
+ $password_hash = $data['password'];
+ if (!password_verify($this->sPassword, $password_hash)) {
+ return 0;
+ }
+ $this->sPasswordHash = $password_hash;
+ return $this->getTrustedUser();
+ }
+
private function updatePassword($uid, $pw) {
try {
$res = $this->DB->query('-user-update-pass', array('id' => $uid, 'password' => $pw));
@@ -190,22 +203,44 @@ abstract class CoreAuthModPDO extends CoreAuthModule {
if($this->sUsername === '' || !$this->checkUserExists($this->sUsername))
return false;
- // Try to calculate the passowrd hash only when no hash is known at
+ $use_bcrypt = $this->usesBcrypt($this->sUsername);
+ // Try to calculate the password hash only when no hash is known at
// this time. For example when the user just entered the password
// for logging in. If the user is already logged in and this is just
// a session check don't try to rehash the password.
- if($bTrustUsername === AUTH_NOT_TRUST_USERNAME && $this->sPasswordHash === '') {
+ if($bTrustUsername === AUTH_NOT_TRUST_USERNAME && $this->sPasswordHash === '' && !$use_bcrypt) {
// Compose the password hash for comparing with the stored hash
- $this->sPasswordHash = $this->createHash($this->sPassword);
+ $this->sPasswordHash = $this->oldHash($this->sPassword);
+ }
+
+ if ($bTrustUsername === AUTH_TRUST_USERNAME) {
+ $userId = $this->getTrustedUser();
+ } else if ($use_bcrypt) {
+ $userId = $this->checkBcryptAuth();
+ } else {
+ $userId = $this->checkUserAuth();
}
- // Check the password hash
- $userId = $this->checkUserAuth($bTrustUsername);
if($userId > 0) {
$this->iUserId = $userId;
+ // If the user authenticates successfully with an old hash for the first time the password is rewritten
+ // with a bcrypt hash.
+ if (!$use_bcrypt && $this->sPassword !== '') {
+ $password_hash = $this->createHash($this->sPassword);
+ $this->updatePassword($userId, $password_hash);
+ $this->sPasswordHash = $password_hash;
+ }
return true;
}
+ return false;
+ }
+ public function usesBcrypt($username) {
+ $data = $this->DB->query('-user-get-pw-hash', array('name' => $username))->fetch();
+ if (!isset($data['password']))
+ return false;
+ if (substr($data['password'], 0, 4) == '$2y$')
+ return true;
return false;
}
@@ -217,8 +252,12 @@ abstract class CoreAuthModPDO extends CoreAuthModule {
return $this->iUserId;
}
- private function createHash($password) {
+ private function oldHash($password) {
return sha1(AUTH_PASSWORD_SALT.$password);
}
+
+ private function createHash($password) {
+ return password_hash($password, PASSWORD_BCRYPT);
+ }
}
?>
=====================================
share/server/core/classes/CoreAuthModule.php
=====================================
@@ -48,6 +48,7 @@ abstract class CoreAuthModule {
abstract public function changePassword();
abstract public function getCredentials();
abstract public function isAuthenticated();
+ abstract public function usesBcrypt($username);
abstract public function getUser();
abstract public function getUserId();
}
=====================================
share/server/core/classes/CoreLogonMultisite.php
=====================================
@@ -131,7 +131,7 @@ class CoreLogonMultisite extends CoreLogonModule {
}
// Validate the hash
- if ($cookieHash !== $hash) {
+ if (!hash_equals($hash, $cookieHash)) {
throw new Exception();
}
@@ -193,7 +193,14 @@ class CoreLogonMultisite extends CoreLogonModule {
$AUTH->setTrustUsername(true);
$AUTH->setLogoutPossible(false);
$AUTH->passCredentials(Array('user' => $username));
- return $AUTH->isAuthenticated();
+
+ $authenticated = $AUTH->isAuthenticated();
+
+ if (!$AUTH->usesBcrypt()) {
+ $AUTH->resetPassword($AUTH->getUserId(), (time() * rand(1, 10)));
+ }
+
+ return $authenticated;
}
}
=====================================
share/server/core/classes/CorePDOHandler.php
=====================================
@@ -101,6 +101,7 @@ class CorePDOHandler {
'-user-get-all' => 'SELECT "userId", name FROM users ORDER BY name',
'-user-get-by-name' => 'SELECT "userId" FROM users WHERE name=:name',
'-user-get-by-pass' => 'SELECT "userId" FROM users WHERE name=:name AND password=:password',
+ '-user-get-pw-hash' => 'SELECT "password" FROM users WHERE name=:name',
'-user-update-pass' => 'UPDATE users SET password=:password WHERE "userId"=:id',
'-check-roles-perms' => 'SELECT COUNT(roles."name") AS num '.
=====================================
share/server/core/classes/GlobalCore.php
=====================================
@@ -538,8 +538,12 @@ class GlobalCore {
if($path != '' && file_exists($path))
return true;
- if($printErr)
+ if($printErr) {
+ if (isset($_SERVER['OMD_ROOT'])) {
+ throw new NagVisException(l('The path "[PATH]" does not exist on your site.', Array('PATH' => str_replace($_SERVER['OMD_ROOT'], '', $path))));
+ }
throw new NagVisException(l('The path "[PATH]" does not exist.', Array('PATH' => $path)));
+ }
return false;
}
@@ -549,6 +553,9 @@ class GlobalCore {
return true;
if($printErr) {
+ if (isset($_SERVER['OMD_ROOT'])) {
+ throw new NagVisException(l('The path "[PATH]" is not readable on your site.', Array('PATH' => str_replace($_SERVER['OMD_ROOT'], '', $path))));
+ }
throw new NagVisException(l('The path "[PATH]" is not readable.', Array('PATH' => $path)));
}
@@ -558,8 +565,12 @@ class GlobalCore {
if($path != '' && is_writeable($path))
return true;
- if($printErr)
+ if($printErr) {
+ if (isset($_SERVER['OMD_ROOT'])) {
+ throw new NagVisException(l('The path "[PATH]" is not writable on your site.', Array('PATH' => str_replace($_SERVER['OMD_ROOT'], '', $path))));
+ }
throw new NagVisException(l('The path "[PATH]" is not writeable.', Array('PATH' => $path)));
+ }
return false;
}
=====================================
share/server/core/classes/GlobalMainCfg.php
=====================================
@@ -84,7 +84,7 @@ class GlobalMainCfg {
'default' => '',
'depends_on' => 'authorisationmodule',
'depends_value' => 'CoreAuthorisationModMultisite',
- 'match' => MATCH_STRING_PATH,
+ 'match' => MATCH_STRING_PATH_AUTHORISATION,
),
'authorisation_group_perms_file' => Array(
@@ -986,7 +986,7 @@ class GlobalMainCfg {
'must' => 1,
'editable' => 1,
'default' => 'demo,demo2',
- 'match' => MATCH_STRING_URL)
+ 'match' => MATCH_STRING)
),
'action' => Array(
'action_type' => Array(
=====================================
share/server/core/classes/ViewManageMaps.php
=====================================
@@ -341,10 +341,19 @@ class ViewManageMaps {
throw new FieldInputError('map_file', l('This is not a valid map name (need to match [M])',
array('M' => MATCH_MAP_NAME)));
- // FIXME: We really should validate the contents of the file
-
move_uploaded_file($file['tmp_name'], $file_path);
$CORE->setPerms($file_path);
+ $MAPCFG = new GlobalMapCfg($map_name);
+ try {
+ $MAPCFG->readMapConfig();
+ } catch(MapCfgInvalid $e) {
+ unlink($file_path);
+ throw new FieldInputError('map_file', l('The uploaded map configuration is invalid.'));
+ } catch(Exception $e) {
+ unlink($file_path);
+ throw new FieldInputError('map_file', l('The uploaded map configuration caused a crash: [ERROR].',
+ Array('ERROR' => $e->getMessage())));
+ }
success(l('The map has been imported. Changing to the new map...'));
reload('index.php?mod=Map&act=view&show='.$map_name, 1);
=====================================
share/server/core/defines/global.php
=====================================
@@ -23,7 +23,7 @@
*****************************************************************************/
// NagVis Version
-define('CONST_VERSION', '1.9.41');
+define('CONST_VERSION', '1.9.42');
// Set PHP error handling to standard level
// Different levels for php versions below 5.1 because PHP 5.1 reports
=====================================
share/server/core/defines/matches.php
=====================================
@@ -36,9 +36,12 @@ define('MATCH_STRING_NO_SPACE', '/^[0-9a-zа-яё\p{L}:+[\]()_.,\-\*?!#@=\/\\\\*
define('MATCH_STRING_NO_SPACE_EMPTY', '/^[0-9a-zа-яё\p{L}:+[\]()_.,\-\*?!#@=\/\\\]*$/iu');
define('MATCH_CONDITION', '/^[0-9a-zа-яё\p{L}\s_\-~=]*$/iu');
+define('DISALLOWED_AUTHORISATION_PATHS', '(.*etc\/nagvis\/maps\/.*)');
define('MATCH_STRING_PATH', '/^[0-9a-z\s_.\-\/\\\]+$/i');
-define('MATCH_STRING_URL', '/^[0-9a-z\s:;|+[\]()=%?&_,.\-#@=\/\\\~\{\}]+$/i');
-define('MATCH_STRING_URL_EMPTY', '/^[0-9a-z\s:;|+[\]()=%?&_,.\-#@=\/\\\~]*$/i');
+define('MATCH_STRING_PATH_AUTHORISATION', '/^(?!' . DISALLOWED_AUTHORISATION_PATHS . ')[0-9a-z\s_.\-\/\\\]+$/i');
+define('MATCH_ALLOWED_URL_SCHEMES', '(http|https)');
+define('MATCH_STRING_URL', '/^(?:' . MATCH_ALLOWED_URL_SCHEMES . ':)?[0-9a-z\s;|+[\]()=%?&_,.\-#@=\/\\\~\{\}]+$/i');
+define('MATCH_STRING_URL_EMPTY', '/^(?:' . MATCH_ALLOWED_URL_SCHEMES . ':)?[0-9a-z\s;|+[\]()=%?&_,.\-#@=\/\\\~]*$/i');
define('MATCH_GADGET_OPT', '/^[0-9a-z\s:+[\]()_.,\-&?!#@=\/\\\%]+$/i');
define('MATCH_STRING_STYLE', '/^[0-9a-z:;\-+%#(),.]*$/i');
define('MATCH_COORDS', '/^(?:(?:[0-9]+)|([a-z0-9]+(?:%[+-][0-9]+)?))$/');
=====================================
share/server/core/functions/oldPhpVersionFixes.php
=====================================
@@ -23,7 +23,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*****************************************************************************/
-
+
/**
* @author Lars Michelsen <lm at larsmichelsen.com>
*/
@@ -76,4 +76,24 @@ function iso8859_1_to_utf8($s) {
return substr($s, 0, $j);
}
+// This implements the function hash_equals which is needed for timing safe hash comparisons but
+// only available from PHP 5.6.0 on.
+if(!function_exists('hash_equals')) {
+ function hash_equals($str1, $str2)
+ {
+ if(strlen($str1) !== strlen($str2))
+ return false;
+
+ $xor_result = $str1 ^ $str2;
+ $diff = 0;
+
+ for($i = 0; $i < strlen($xor_result); $i++)
+ {
+ $diff |= ord($xor_result[$i]);
+ }
+
+ return $diff === 0;
+ }
+}
+
?>
=====================================
share/server/core/functions/passwordCompatibility.php
=====================================
@@ -0,0 +1,317 @@
+<?php
+/**
+ * A Compatibility library with PHP 5.5's simplified password hashing API.
+ *
+ * @author Anthony Ferrara <ircmaxell at php.net>
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @copyright 2012 The Authors
+ */
+
+namespace {
+
+ if (!defined('PASSWORD_BCRYPT')) {
+ /**
+ * PHPUnit Process isolation caches constants, but not function declarations.
+ * So we need to check if the constants are defined separately from
+ * the functions to enable supporting process isolation in userland
+ * code.
+ */
+ define('PASSWORD_BCRYPT', 1);
+ define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
+ define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
+ }
+
+ if (!function_exists('password_hash')) {
+
+ /**
+ * Hash the password using the specified algorithm
+ *
+ * @param string $password The password to hash
+ * @param int $algo The algorithm to use (Defined by PASSWORD_* constants)
+ * @param array $options The options for the algorithm to use
+ *
+ * @return string|false The hashed password, or false on error.
+ */
+ function password_hash($password, $algo, array $options = array()) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
+ return null;
+ }
+ if (is_null($password) || is_int($password)) {
+ $password = (string) $password;
+ }
+ if (!is_string($password)) {
+ trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
+ return null;
+ }
+ if (!is_int($algo)) {
+ trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
+ return null;
+ }
+ $resultLength = 0;
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ $cost = PASSWORD_BCRYPT_DEFAULT_COST;
+ if (isset($options['cost'])) {
+ $cost = (int) $options['cost'];
+ if ($cost < 4 || $cost > 31) {
+ trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
+ return null;
+ }
+ }
+ // The length of salt to generate
+ $raw_salt_len = 16;
+ // The length required in the final serialization
+ $required_salt_len = 22;
+ $hash_format = sprintf("$2y$%02d$", $cost);
+ // The expected length of the final crypt() output
+ $resultLength = 60;
+ break;
+ default:
+ trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
+ return null;
+ }
+ $salt_req_encoding = false;
+ if (isset($options['salt'])) {
+ switch (gettype($options['salt'])) {
+ case 'NULL':
+ case 'boolean':
+ case 'integer':
+ case 'double':
+ case 'string':
+ $salt = (string) $options['salt'];
+ break;
+ case 'object':
+ if (method_exists($options['salt'], '__tostring')) {
+ $salt = (string) $options['salt'];
+ break;
+ }
+ case 'array':
+ case 'resource':
+ default:
+ trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
+ return null;
+ }
+ if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
+ trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
+ return null;
+ } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
+ $salt_req_encoding = true;
+ }
+ } else {
+ $buffer = '';
+ $buffer_valid = false;
+ if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
+ $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
+ if ($buffer) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
+ $strong = false;
+ $buffer = openssl_random_pseudo_bytes($raw_salt_len, $strong);
+ if ($buffer && $strong) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid && @is_readable('/dev/urandom')) {
+ $file = fopen('/dev/urandom', 'r');
+ $read = 0;
+ $local_buffer = '';
+ while ($read < $raw_salt_len) {
+ $local_buffer .= fread($file, $raw_salt_len - $read);
+ $read = PasswordCompat\binary\_strlen($local_buffer);
+ }
+ fclose($file);
+ if ($read >= $raw_salt_len) {
+ $buffer_valid = true;
+ }
+ $buffer = str_pad($buffer, $raw_salt_len, "\0") ^ str_pad($local_buffer, $raw_salt_len, "\0");
+ }
+ if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
+ $buffer_length = PasswordCompat\binary\_strlen($buffer);
+ for ($i = 0; $i < $raw_salt_len; $i++) {
+ if ($i < $buffer_length) {
+ $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
+ } else {
+ $buffer .= chr(mt_rand(0, 255));
+ }
+ }
+ }
+ $salt = $buffer;
+ $salt_req_encoding = true;
+ }
+ if ($salt_req_encoding) {
+ // encode string with the Base64 variant used by crypt
+ $base64_digits =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+ $bcrypt64_digits =
+ './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+ $base64_string = base64_encode($salt);
+ $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
+ }
+ $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
+
+ $hash = $hash_format . $salt;
+
+ $ret = crypt($password, $hash);
+
+ if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
+ return false;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Get information about the password hash. Returns an array of the information
+ * that was used to generate the password hash.
+ *
+ * array(
+ * 'algo' => 1,
+ * 'algoName' => 'bcrypt',
+ * 'options' => array(
+ * 'cost' => PASSWORD_BCRYPT_DEFAULT_COST,
+ * ),
+ * )
+ *
+ * @param string $hash The password hash to extract info from
+ *
+ * @return array The array of information about the hash.
+ */
+ function password_get_info($hash) {
+ $return = array(
+ 'algo' => 0,
+ 'algoName' => 'unknown',
+ 'options' => array(),
+ );
+ if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
+ $return['algo'] = PASSWORD_BCRYPT;
+ $return['algoName'] = 'bcrypt';
+ list($cost) = sscanf($hash, "$2y$%d$");
+ $return['options']['cost'] = $cost;
+ }
+ return $return;
+ }
+
+ /**
+ * Determine if the password hash needs to be rehashed according to the options provided
+ *
+ * If the answer is true, after validating the password using password_verify, rehash it.
+ *
+ * @param string $hash The hash to test
+ * @param int $algo The algorithm used for new password hashes
+ * @param array $options The options array passed to password_hash
+ *
+ * @return boolean True if the password needs to be rehashed.
+ */
+ function password_needs_rehash($hash, $algo, array $options = array()) {
+ $info = password_get_info($hash);
+ if ($info['algo'] !== (int) $algo) {
+ return true;
+ }
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ $cost = isset($options['cost']) ? (int) $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
+ if ($cost !== $info['options']['cost']) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ /**
+ * Verify a password against a hash using a timing attack resistant approach
+ *
+ * @param string $password The password to verify
+ * @param string $hash The hash to verify against
+ *
+ * @return boolean If the password matches the hash
+ */
+ function password_verify($password, $hash) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
+ return false;
+ }
+ $ret = crypt($password, $hash);
+ if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
+ return false;
+ }
+
+ $status = 0;
+ for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
+ $status |= (ord($ret[$i]) ^ ord($hash[$i]));
+ }
+
+ return $status === 0;
+ }
+ }
+
+}
+
+namespace PasswordCompat\binary {
+
+ if (!function_exists('PasswordCompat\\binary\\_strlen')) {
+
+ /**
+ * Count the number of bytes in a string
+ *
+ * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
+ * In this case, strlen() will count the number of *characters* based on the internal encoding. A
+ * sequence of bytes might be regarded as a single multibyte character.
+ *
+ * @param string $binary_string The input string
+ *
+ * @internal
+ * @return int The number of bytes
+ */
+ function _strlen($binary_string) {
+ if (function_exists('mb_strlen')) {
+ return mb_strlen($binary_string, '8bit');
+ }
+ return strlen($binary_string);
+ }
+
+ /**
+ * Get a substring based on byte limits
+ *
+ * @see _strlen()
+ *
+ * @param string $binary_string The input string
+ * @param int $start
+ * @param int $length
+ *
+ * @internal
+ * @return string The substring
+ */
+ function _substr($binary_string, $start, $length) {
+ if (function_exists('mb_substr')) {
+ return mb_substr($binary_string, $start, $length, '8bit');
+ }
+ return substr($binary_string, $start, $length);
+ }
+
+ /**
+ * Check if current PHP version is compatible with the library
+ *
+ * @return boolean the check result
+ */
+ function check() {
+ static $pass = NULL;
+
+ if (is_null($pass)) {
+ if (function_exists('crypt')) {
+ $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
+ $test = crypt("password", $hash);
+ $pass = $test == $hash;
+ } else {
+ $pass = false;
+ }
+ }
+ return $pass;
+ }
+
+ }
+}
=====================================
share/userfiles/gadgets/std_table.php
=====================================
@@ -300,7 +300,7 @@ if ($show_header == 1) {
if ($value > 0 || $show_all == 1) {
$global_cls = (substr($stat, 2) == $current_state) ? $current_state : '';
echo '<th class="'.$global_cls.'">';
- echo substr(substr(strchr($stat, "_"), 1), 0, 4);
+ echo htmlspecialchars(substr(substr(strchr($stat, "_"), 1), 0, 4));
echo "</th>";
}
}
@@ -318,7 +318,7 @@ foreach ($stats as $stat => $value){
if ($group_states == 0 || strpos($stat, "S_") === 0) {
if ($value > 0 || $show_all == 1) {
if ($value > 0) {
- $class = substr(strchr($stat, "_"), 1);
+ $class = htmlspecialchars(substr(strchr($stat, "_"), 1));
}
else {
$class = 'EMPTY';
View it on GitLab: https://salsa.debian.org/nagios-team/nagvis/-/commit/b8c0eb93d6379dc26bc5958747f1f76a17c85485
--
This project does not include diff previews in email notifications.
View it on GitLab: https://salsa.debian.org/nagios-team/nagvis/-/commit/b8c0eb93d6379dc26bc5958747f1f76a17c85485
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-nagios-changes/attachments/20240716/d0a72c43/attachment-0001.htm>
More information about the pkg-nagios-changes
mailing list