[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