[pkg-nagios-changes] [Git][nagios-team/nagvis][upstream] New upstream version 1.9.48

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Wed Dec 3 19:58:28 GMT 2025



Bas Couwenberg pushed to branch upstream at Debian Nagios Maintainer Group / nagvis


Commits:
8edd31ee by Bas Couwenberg at 2025-12-03T20:47:01+01:00
New upstream version 1.9.48
- - - - -


18 changed files:

- .github/workflows/ci.yml
- ChangeLog
- + composer.json
- + composer.lock
- phpstan.neon
- share/frontend/nagvis-js/js/NagVisStatefulObject.js
- share/frontend/nagvis-js/js/ViewMap.js
- share/server/core/classes/CoreLogonMultisite.php
- share/server/core/classes/objects/NagVisStatefulObject.php
- share/server/core/defines/global.php
- share/server/core/defines/matches.php
- share/server/core/sources/general.php
- + share/userfiles/images/iconsets/std_area_error_ack.png
- + share/userfiles/images/iconsets/std_big_error_ack.png
- + share/userfiles/images/iconsets/std_dot_error_ack.png
- + share/userfiles/images/iconsets/std_geo_error_ack.png
- + share/userfiles/images/iconsets/std_medium_error_ack.png
- + share/userfiles/images/iconsets/std_small_error_ack.png


Changes:

=====================================
.github/workflows/ci.yml
=====================================
@@ -7,7 +7,8 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout at v3
-      - name: PHPStan Static Analysis
-        uses: php-actions/phpstan at v3
+      - uses: php-actions/composer at v6
+      - uses: php-actions/phpstan at v3
+        name: PHPStan Static Analysis
         with:
           path: .


=====================================
ChangeLog
=====================================
@@ -1,3 +1,12 @@
+1.9.48
+  * FIX: Fix exclude_members related PHP 8.1 compatibility issue (#400 Thanks to ekapsner-ne)
+  * FIX: misaligned labels on state changes
+  * Hide lines of excluded members in automaps (#402 Thanks to ekapsner-ne)
+  * Add support for SVG based icon sets (#405 Thanks to dnelson-nagios)
+  * FIX: session validity: only check cookie for site NagVis is running on
+  * FIX: Fix User enumeration and Cleanup CMK session cookie validation (CVE-2025-39665) (#411 Thanks to Shortfinga)
+      (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N)
+
 1.9.47
   * FIX: Don't show complete backtrace if crashing. Now the backtrace is being logged to the apache error log
   * FIX: Fix potential XSS via WYSIWYG editor. Now the option to edit these such elements is moved to a specific


=====================================
composer.json
=====================================
@@ -0,0 +1,16 @@
+{
+    "name": "nagvis/nagvis",
+    "description": "NagVis is a visualization addon for the well known network management system Nagios.",
+    "type": "project",
+    "license": "GPL-2.0-only",
+    "authors": [
+        {
+            "name": "Lars Michelsen",
+            "email": "lm at larsmichelsen.com"
+        }
+    ],
+    "minimum-stability": "stable",
+    "require-dev": {
+        "phpstan/phpstan": "^2.1"
+    }
+}


=====================================
composer.lock
=====================================
@@ -0,0 +1,77 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "c66e82eb768e45d79b25166eba80d003",
+    "packages": [],
+    "packages-dev": [
+        {
+            "name": "phpstan/phpstan",
+            "version": "2.1.18",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpstan/phpstan.git",
+                "reference": "ee1f390b7a70cdf74a2b737e554f68afea885db7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ee1f390b7a70cdf74a2b737e554f68afea885db7",
+                "reference": "ee1f390b7a70cdf74a2b737e554f68afea885db7",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.4|^8.0"
+            },
+            "conflict": {
+                "phpstan/phpstan-shim": "*"
+            },
+            "bin": [
+                "phpstan",
+                "phpstan.phar"
+            ],
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "PHPStan - PHP Static Analysis Tool",
+            "keywords": [
+                "dev",
+                "static analysis"
+            ],
+            "support": {
+                "docs": "https://phpstan.org/user-guide/getting-started",
+                "forum": "https://github.com/phpstan/phpstan/discussions",
+                "issues": "https://github.com/phpstan/phpstan/issues",
+                "security": "https://github.com/phpstan/phpstan/security/policy",
+                "source": "https://github.com/phpstan/phpstan-src"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/ondrejmirtes",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/phpstan",
+                    "type": "github"
+                }
+            ],
+            "time": "2025-07-17T17:22:31+00:00"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": {},
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {},
+    "platform-dev": {},
+    "plugin-api-version": "2.6.0"
+}


=====================================
phpstan.neon
=====================================
@@ -3,6 +3,7 @@ parameters:
     paths:
         - .
     excludePaths:
+        - vendor
         - share/frontend/nagvis-js/ext
         - share/server/core/ext
         - etc/conf.d/demo.ini.php


=====================================
share/frontend/nagvis-js/js/NagVisStatefulObject.js
=====================================
@@ -445,16 +445,12 @@ var NagVisStatefulObject = NagVisObject.extend({
 
         this.bIsFlashing = show;
         if(show) {
-            oObjIcon.style.border  = "5px solid " + sColor;
+            oObjIcon.style.outline  = "5px solid " + sColor;
             oObjIcon.classList.add(sFlashingClass);
-            oObjIconDiv.style.top  = (this.parseCoord(this.conf.y, 'y') - 5) + 'px';
-            oObjIconDiv.style.left = (this.parseCoord(this.conf.x, 'x') - 5) + 'px';
             oObjIconDiv.classList.add(sFlashingDivClass);
         } else {
-            oObjIcon.style.border  = "none";
+            oObjIcon.style.outline  = "none";
             oObjIcon.classList.remove(sFlashingClass);
-            oObjIconDiv.style.top  = this.parseCoord(this.conf.y, 'y') + 'px';
-            oObjIconDiv.style.left = this.parseCoord(this.conf.x, 'x') + 'px';
             oObjIconDiv.classList.remove(sFlashingDivClass);
         }
 


=====================================
share/frontend/nagvis-js/js/ViewMap.js
=====================================
@@ -221,6 +221,15 @@ var ViewMap = View.extend({
 
     renderObject: function(object_id) {
         var obj = this.objects[object_id];
+        var parents = obj.getParentObjectIds();
+
+        if (parents && usesSource('automap')){
+            for (var parentObjId in parents) {
+                if (!this.objects[parentObjId]){
+                    return;
+                }
+            }
+        }
 
         // FIXME: Are all these steps needed here?
         obj.update();
@@ -234,7 +243,6 @@ var ViewMap = View.extend({
         }
 
         // Store object dependencies
-        var parents = obj.getParentObjectIds();
         if (parents) {
             for (var parentObjId in parents) {
                 if (isset(this.objects[parentObjId])) this.objects[parentObjId].addChild(obj);


=====================================
share/server/core/classes/CoreLogonMultisite.php
=====================================
@@ -24,116 +24,30 @@
  *****************************************************************************/
 
 class CoreLogonMultisite extends CoreLogonModule {
-    private $htpasswdPath;
-    private $serialsPath;
-    private $secretPath;
-    private $cookieVersion;
-    private $authFile;
-
-    public function __construct() {
-        $this->htpasswdPath  = cfg('global', 'logon_multisite_htpasswd');
-        $this->serialsPath   = cfg('global', 'logon_multisite_serials');
-        $this->secretPath    = cfg('global', 'logon_multisite_secret');
-        $this->cookieVersion = intval(cfg('global', 'logon_multisite_cookie_version'));
-
-        // When the auth.serial file exists, use this instead of the htpasswd
-        // for validating the cookie. The structure of the file is equal, so
-        // the same code can be used.
-        if(file_exists($this->serialsPath)) {
-            $this->authFile = 'serial';
-
-        } elseif(file_exists($this->htpasswdPath)) {
-            $this->authFile = 'htpasswd';
-
-        } else {
-            throw new NagVisException(l('LogonMultisite: The htpasswd file "[HTPASSWD]" or '
-                                       .'the authentication serial file "[SERIAL]" do not exist.',
-                          array('HTPASSWD' => $this->htpasswdPath, 'SERIAL' => $this->serialsPath)));
-        }
+    private function isCookiePlausible($username, $sessionId, $cookieHash) {
+        // Mostly meant to check that we don't process malicious cookies, e.g.
+        // data with special chars.
 
-        if(!file_exists($this->secretPath)) {
-            $this->redirectToLogin();
+        if (preg_match('/^[\w$][- at .+\w$]*$/i', $username) !== 1){
+            // See https://github.com/Checkmk/checkmk/blob/1cc2796314508092b18d52d34b932fe0435beba4/packages/cmk-ccc/cmk/ccc/user.py#L52
+            throw new AuthenticationException(l("Malformed username"));
         }
-    }
-
-    private function loadAuthFile($path) {
-        $creds = array();
-        foreach(file($path) AS $line) {
-            if(strpos($line, ':') !== false) {
-                list($username, $secret) = explode(':', $line, 2);
-                $creds[$username] = rtrim($secret);
-            }
+        if (preg_match('/^[-0-9a-f]{36}$/i', $sessionId) !== 1){
+            throw new AuthenticationException(l("Malformed session id"));
+        }
+        if (preg_match('/^[-0-9a-f]{64}$/i', $cookieHash) !== 1){
+            throw new AuthenticationException(l("Malformed hash"));
         }
-        return $creds;
-    }
-
-    private function loadSecret() {
-        return file_get_contents($this->secretPath);
-    }
-
-    private function generateHash($username, $session_id, $user_secret) {
-        $secret = $this->loadSecret();
-        return hash_hmac("sha256", $username . $session_id. $user_secret, $secret);
-    }
-
-    private function generatePre22Hash($username, $session_id, $user_secret) {
-        $secret = $this->loadSecret();
-        return hash("sha256", $username . $session_id. $user_secret . $secret);
-    }
-
-    private function generatePre20Hash($username, $issue_time, $user_secret) {
-        $secret = $this->loadSecret();
-        return md5($username . $issue_time . $user_secret . $secret);
     }
 
     private function checkAuthCookie($cookieName) {
         if(!isset($_COOKIE[$cookieName]) || $_COOKIE[$cookieName] == '') {
             throw new AuthenticationException(l("No auth cookie provided."));
         }
-
-        // Checkmk 1.6+ may add double quotes round the value in some cases
-        // (e.g. when @ signs are found in the value)
-        $cookieValue = trim($_COOKIE[$cookieName], '"');
-
-        // 2nd field is "issue time" in pre 2.0 cookies. Now it's the session ID
+        $cookieValue = $_COOKIE[$cookieName];
         list($username, $sessionId, $cookieHash) = explode(':', $cookieValue, 3);
 
-        if($this->authFile == 'htpasswd')
-            $users = $this->loadAuthFile($this->htpasswdPath);
-        else
-            $users = $this->loadAuthFile($this->serialsPath);
-
-        if(!isset($users[$username])) {
-            throw new AuthenticationException(l("User not found in auth file."));
-        }
-        $user_secret = $users[$username];
-
-	if ($this->cookieVersion < 1) {
-	    // Older Checkmk versions do not set the cookieVersion, therefore we guess based on the length.
-
-            // Checkmk 2.0 changed the following:
-            // a) 2nd field from "issue time" to session ID
-            // b) 3rd field from md5 hash to sha256 hash
-            // NagVis is used with older and newer Checkmk versions. Be compatible
-            // to both cookie formats.
-            $is_pre_20_cookie = strlen($cookieHash) == 32;
-
-            if ($is_pre_20_cookie)
-                $hash = $this->generatePre20Hash($username, $sessionId, (string) $user_secret);
-            else
-                $hash = $this->generatePre22Hash($username, $sessionId, (string) $user_secret);
-	}
-	elseif ($this->cookieVersion == 1) {
-            $hash = $this->generateHash($username, $sessionId, (string) $user_secret);
-	}
-	else {
-            throw new NagVisException(l('The Multisite Cookie version is not supported'));
-	}
-
-        // Validate the hash
-        if (!hash_equals($hash, $cookieHash)) {
-            throw new Exception();
-        }
+        $this->isCookiePlausible($username, $sessionId, $cookieHash);
 
         // Check session periods validity
         $site = getenv('OMD_SITE');
@@ -156,7 +70,7 @@ class CoreLogonMultisite extends CoreLogonModule {
 
         $context = stream_context_create($contextOptions);
         if(filter_var(ini_get('allow_url_fopen'), FILTER_VALIDATE_BOOLEAN)) {
-            $result = file_get_contents($url, false, $context);
+            $result = @ file_get_contents($url, false, $context);
             if ($result === false) {
                 throw new AuthenticationException(l("Cookie is invalid."));
             }
@@ -185,7 +99,7 @@ class CoreLogonMultisite extends CoreLogonModule {
         // Loop all cookies trying to fetch a valid authentication
         // cookie for this installation
         foreach(array_keys($_COOKIE) AS $cookieName) {
-            if(substr($cookieName, 0, 5) != 'auth_') {
+            if($cookieName != 'auth_' . getenv('OMD_SITE')) {
                 continue;
             }
             try {


=====================================
share/server/core/classes/objects/NagVisStatefulObject.php
=====================================
@@ -360,9 +360,9 @@ class NagVisStatefulObject extends NagVisObject {
     public function getExcludeFilterKey($isCount) {
         // When this is a count use the exclude_member_states over the 
         // exclude_members
-        if($isCount && $this->exclude_member_states !== '')
+        if($isCount && $this->exclude_member_states != '')
             return 'exclude_member_states';
-        elseif($this->exclude_members !== '')
+        elseif($this->exclude_members != '')
             return 'exclude_members';
         else
             return '';


=====================================
share/server/core/defines/global.php
=====================================
@@ -23,7 +23,7 @@
  *****************************************************************************/
  
 // NagVis Version
-define('CONST_VERSION', '1.9.47');
+define('CONST_VERSION', '1.9.48');
 
 // 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
=====================================
@@ -71,7 +71,7 @@ define('MATCH_PNG_GIF_JPG_FILE_OR_URL', '/^((.+)\.(png|gif|jpg)|\[[0-9a-z\s:+[\]
 define('MATCH_ROTATION_STEP_TYPES_EMPTY', '/^(?:map|url)?$/');
 define('MATCH_LANGUAGE_EMPTY', '/^[a-zA-Z0-9\-_]*$/');
 define('MATCH_LANGUAGE_FILE', '/^([^.].*)/');
-define('MATCH_ICONSET', '/^(.+)_ok.(png|gif|jpg)$/u');
+define('MATCH_ICONSET', '/^(.+)_ok.(png|gif|jpg|svg)$/u');
 define('MATCH_BACKEND_FILE', '/^GlobalBackend([^MI].+)\.php$/');
 define('MATCH_BACKEND_ID', '/^[0-9a-z._-]*$/iu');
 define('MATCH_DOC_DIR', '/^([a-z]{2}_[A-Z]{2})/');


=====================================
share/server/core/sources/general.php
=====================================
@@ -50,14 +50,51 @@ function iconset_size($iconset) {
     $fileType = $CORE->getIconsetFiletype($iconset);
     $iconPath      = path('sys',  'global', 'icons').'/'.$iconset.'_ok.'.$fileType;
     $iconPathLocal = path('sys',  'local',  'icons').'/'.$iconset.'_ok.'.$fileType;
-    if(file_exists($iconPathLocal))
-        return getimagesize($iconPathLocal);
-    elseif(file_exists($iconPath))
-        return getimagesize($iconPath);
+    if(file_exists($iconPathLocal)) {
+        if($fileType == "svg") {
+            return svg_size($iconPathLocal);
+        }
+        else {
+            return getimagesize($iconPathLocal);
+        }
+    }
+    elseif(file_exists($iconPath)){
+        if($fileType == "svg") {
+            return svg_size($iconPath);
+        }
+        else {
+            return getimagesize($iconPath);
+        }
+    }
     else
         return array(0, 0);
 }
 
+function svg_size($filepath) {
+    if (!file_exists($filepath)) {
+        return array(0, 0);
+    }
+
+    $doc = new DOMDocument();
+    $doc->load($filepath);
+
+    $svg = $doc->getElementsByTagName('svg')->item(0);
+    $width = $svg->getAttribute('width');
+    $height = $svg->getAttribute('height');
+
+    // Fallback to viewBox
+    if (empty($width) || empty($height)) {
+        $viewBox = $svg->getAttribute('viewBox');
+        $parts = preg_split('/[\s,]+/', $viewBox);
+        if (count($parts) === 4) {
+            $width = $parts[2];
+            $height = $parts[3];
+        }
+    }
+
+    return array(floatval($width), floatval($height));
+}
+
 function shape_size($icon) {
     $iconPath      = path('sys',  'global', 'shapes').'/'.$icon;
     $iconPathLocal = path('sys',  'local',  'shapes').'/'.$icon;


=====================================
share/userfiles/images/iconsets/std_area_error_ack.png
=====================================
Binary files /dev/null and b/share/userfiles/images/iconsets/std_area_error_ack.png differ


=====================================
share/userfiles/images/iconsets/std_big_error_ack.png
=====================================
Binary files /dev/null and b/share/userfiles/images/iconsets/std_big_error_ack.png differ


=====================================
share/userfiles/images/iconsets/std_dot_error_ack.png
=====================================
Binary files /dev/null and b/share/userfiles/images/iconsets/std_dot_error_ack.png differ


=====================================
share/userfiles/images/iconsets/std_geo_error_ack.png
=====================================
Binary files /dev/null and b/share/userfiles/images/iconsets/std_geo_error_ack.png differ


=====================================
share/userfiles/images/iconsets/std_medium_error_ack.png
=====================================
Binary files /dev/null and b/share/userfiles/images/iconsets/std_medium_error_ack.png differ


=====================================
share/userfiles/images/iconsets/std_small_error_ack.png
=====================================
Binary files /dev/null and b/share/userfiles/images/iconsets/std_small_error_ack.png differ



View it on GitLab: https://salsa.debian.org/nagios-team/nagvis/-/commit/8edd31ee4526fd4eccd790a4015ce8a1f52791a8

-- 
View it on GitLab: https://salsa.debian.org/nagios-team/nagvis/-/commit/8edd31ee4526fd4eccd790a4015ce8a1f52791a8
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/20251203/aa4c1bfd/attachment-0001.htm>


More information about the pkg-nagios-changes mailing list