[pkg-nagios-changes] [Git][nagios-team/pkg-icingaweb2][upstream] New upstream version 2.8.3

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Wed Jul 14 20:38:37 BST 2021



Bas Couwenberg pushed to branch upstream at Debian Nagios Maintainer Group / pkg-icingaweb2


Commits:
86d06174 by Bas Couwenberg at 2021-07-14T21:17:47+02:00
New upstream version 2.8.3
- - - - -


26 changed files:

- CHANGELOG.md
- VERSION
- application/VERSION
- library/Icinga/Application/Version.php
- library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
- library/Icinga/Protocol/Ldap/LdapQuery.php
- library/Icinga/Web/View/Helper/IcingaCheckbox.php
- modules/doc/application/controllers/ModuleController.php
- modules/doc/module.info
- modules/migrate/module.info
- modules/monitoring/application/controllers/ListController.php
- modules/monitoring/application/views/scripts/list/hosts.phtml
- modules/monitoring/application/views/scripts/list/services.phtml
- modules/monitoring/library/Monitoring/Backend/Ido/Query/HostgroupQuery.php
- modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php
- modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php
- modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php
- modules/monitoring/library/Monitoring/Controller.php
- + modules/monitoring/library/Monitoring/Data/CustomvarProtectionIterator.php
- modules/monitoring/library/Monitoring/Object/MonitoredObject.php
- modules/monitoring/module.info
- modules/setup/module.info
- modules/test/module.info
- modules/translation/module.info
- public/css/icinga/layout-structure.less
- public/css/icinga/menu.less


Changes:

=====================================
CHANGELOG.md
=====================================
@@ -4,6 +4,21 @@ Please make sure to always read our [Upgrading](doc/80-Upgrading.md) documentati
 
 ## What's New
 
+### What's New in Version 2.8.3
+
+**Notice**: This is a security release. It is recommended to upgrade to this release if you don't plan to upgrade to v2.9.0.
+
+You can find all fixes related to this release on our [Project](https://github.com/Icinga/icingaweb2/projects/7).
+
+#### Security Fixes
+
+This release includes two security related fixes. Both were published as part of a security advisory on Github.
+They allow the circumvention of custom variable protection rules and blacklists as well as a path traversal if
+the `doc` module is enabled. Please check the respective advisory for details.
+
+* Custom variable protection and blacklists can be circumvented [GHSA-2xv9-886q-p7xx](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-2xv9-886q-p7xx)
+* Possible path traversal by use of the `doc` module [GHSA-cmgc-h4cx-3v43](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-cmgc-h4cx-3v43)
+
 ### What's New in Version 2.8.2
 
 **Notice**: This is a security release. It is recommended to immediately upgrade to this release.


=====================================
VERSION
=====================================
@@ -1 +1 @@
-v2.8.2
+v2.8.3


=====================================
application/VERSION
=====================================
@@ -1 +1 @@
-8a89839af94a247ee2149b2336c73b8251b477c0 2020-08-17 16:14:11 +0200
+479f990d5981354c05c362700117fe086cd048a9 2021-07-12 09:58:18 +0200


=====================================
library/Icinga/Application/Version.php
=====================================
@@ -8,7 +8,7 @@ namespace Icinga\Application;
  */
 class Version
 {
-    const VERSION = '2.8.2';
+    const VERSION = '2.8.3';
 
     /**
      * Get the version of this instance of Icinga Web 2


=====================================
library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
=====================================
@@ -654,6 +654,7 @@ class LdapUserGroupBackend extends LdapRepository implements Inspectable, UserGr
         return $this->ds
             ->select()
             ->from('*', array($this->userNameAttribute))
+            ->setUnfoldAttribute($this->userNameAttribute)
             ->setBase($dn)
             ->fetchOne();
     }
@@ -694,8 +695,8 @@ class LdapUserGroupBackend extends LdapRepository implements Inspectable, UserGr
     public function requireQueryColumn($table, $name, RepositoryQuery $query = null)
     {
         $column = parent::requireQueryColumn($table, $name, $query);
-        if ($name === 'user_name' && $query !== null) {
-            $query->getQuery()->setUnfoldAttribute('user_name');
+        if (($name === 'user_name' || $name === 'group_name') && $query !== null) {
+            $query->getQuery()->setUnfoldAttribute($name);
         }
 
         return $column;
@@ -749,6 +750,7 @@ class LdapUserGroupBackend extends LdapRepository implements Inspectable, UserGr
         $groupQuery = $this->ds
             ->select()
             ->from($this->groupClass, array($this->groupNameAttribute))
+            ->setUnfoldAttribute($this->groupNameAttribute)
             ->where($groupMemberAttribute, $queryValue)
             ->setBase($this->groupBaseDn);
         if ($this->groupFilter) {


=====================================
library/Icinga/Protocol/Ldap/LdapQuery.php
=====================================
@@ -215,6 +215,41 @@ class LdapQuery extends SimpleQuery
         }
     }
 
+    public function compare($a, $b, $orderIndex = 0)
+    {
+        if (array_key_exists($orderIndex, $this->order)) {
+            $column = $this->order[$orderIndex][0];
+            $direction = $this->order[$orderIndex][1];
+
+            $flippedColumns = $this->flippedColumns ?: array_flip($this->columns);
+            if (array_key_exists($column, $flippedColumns) && is_string($flippedColumns[$column])) {
+                $column = $flippedColumns[$column];
+            }
+
+            if (is_array($a->$column)) {
+                // rfc2891 states: If a sort key is a multi-valued attribute, and an entry happens to
+                //   have multiple values for that attribute and no other controls are
+                //   present that affect the sorting order, then the server SHOULD use the
+                //   least value (according to the ORDERING rule for that attribute).
+                $a = clone $a;
+                $a->$column = array_reduce($a->$column, function ($carry, $item) use ($direction) {
+                    $result = $carry === null ? 0 : strcmp($item, $carry);
+                    return ($direction === self::SORT_ASC ? $result : $result * -1) < 1 ? $item : $carry;
+                });
+            }
+
+            if (is_array($b->$column)) {
+                $b = clone $b;
+                $b->$column = array_reduce($b->$column, function ($carry, $item) use ($direction) {
+                    $result = $carry === null ? 0 : strcmp($item, $carry);
+                    return ($direction === self::SORT_ASC ? $result : $result * -1) < 1 ? $item : $carry;
+                });
+            }
+        }
+
+        return parent::compare($a, $b, $orderIndex);
+    }
+
     /**
      * Fetch result as tree
      *


=====================================
library/Icinga/Web/View/Helper/IcingaCheckbox.php
=====================================
@@ -22,7 +22,8 @@ class IcingaCheckbox extends \Zend_View_Helper_FormCheckbox
         return $html
             . '<label for="'
             . $attribs['id']
-            . '" class="'
+            . '" aria-hidden="true"'
+            . ' class="'
             . $class
             . '"><span class="toggle-slider"></span></label>';
     }


=====================================
modules/doc/application/controllers/ModuleController.php
=====================================
@@ -139,7 +139,7 @@ class ModuleController extends DocController
         $image = $this->params->getRequired('image');
         $docPath = $this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc'));
         $imagePath = realpath($docPath . '/' . $image);
-        if ($imagePath === false) {
+        if ($imagePath === false || substr($imagePath, 0, strlen($docPath)) !== $docPath) {
             $this->httpNotFound('%s does not exist', $image);
         }
 


=====================================
modules/doc/module.info
=====================================
@@ -1,4 +1,4 @@
 Module: doc
-Version: 2.8.2
+Version: 2.8.3
 Description: Documentation module
  Extracts, shows and exports documentation for Icinga Web 2 and its modules.


=====================================
modules/migrate/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: migrate
-Version: 2.8.2
+Version: 2.8.3
 Description: Migrate module
  This module was introduced with the domain-aware authentication feature in version 2.5.0.
  It helps you migrating users and user configurations according to a given domain.


=====================================
modules/monitoring/application/controllers/ListController.php
=====================================
@@ -4,6 +4,7 @@
 namespace Icinga\Module\Monitoring\Controllers;
 
 use Icinga\Security\SecurityException;
+use Icinga\Util\GlobFilter;
 use Icinga\Web\Form;
 use Zend_Form;
 use Icinga\Data\Filter\Filter;
@@ -768,8 +769,31 @@ class ListController extends Controller
             -1,
             PREG_SPLIT_NO_EMPTY
         );
-        $this->view->addColumns = $columns;
-        return $columns;
+
+        $customVars = [];
+        $additionalCols = [];
+        foreach ($columns as $column) {
+            if (preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $column, $m)) {
+                $customVars[$m[1]]['vars'][$m[2]] = null;
+            } else {
+                $additionalCols[] = $column;
+            }
+        }
+
+        if (! empty($customVars)) {
+            $blacklistedProperties = new GlobFilter(
+                $this->getRestrictions('monitoring/blacklist/properties')
+            );
+            $customVars = $blacklistedProperties->removeMatching($customVars);
+            foreach ($customVars as $type => $vars) {
+                foreach ($vars['vars'] as $var => $_) {
+                    $additionalCols[] = '_' . $type . '_' . $var;
+                }
+            }
+        }
+
+        $this->view->addColumns = $additionalCols;
+        return $additionalCols;
     }
 
     protected function addTitleTab($action, $title, $tip)


=====================================
modules/monitoring/application/views/scripts/list/hosts.phtml
=====================================
@@ -92,7 +92,11 @@ if (! $this->compact): ?>
                 <p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true, $host->host_check_command) ?></p>
             </td>
         <?php foreach($this->addColumns as $col): ?>
+          <?php if ($host->$col && preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $col, $m)): ?>
+            <td><?= $this->escape(\Icinga\Module\Monitoring\Object\MonitoredObject::protectCustomVars([$m[2] => $host->$col])[$m[2]]) ?></td>
+          <?php else: ?>
             <td><?= $this->escape($host->$col) ?></td>
+          <?php endif ?>
         <?php endforeach ?>
         </tr>
     <?php endforeach ?>


=====================================
modules/monitoring/application/views/scripts/list/services.phtml
=====================================
@@ -120,7 +120,11 @@ if (! $this->compact): ?>
                 </div>
             </td>
         <?php foreach($this->addColumns as $col): ?>
+          <?php if ($service->$col && preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $col, $m)): ?>
+            <td><?= $this->escape(\Icinga\Module\Monitoring\Object\MonitoredObject::protectCustomVars([$m[2] => $service->$col])[$m[2]]) ?></td>
+          <?php else: ?>
             <td><?= $this->escape($service->$col) ?></td>
+          <?php endif ?>
         <?php endforeach ?>
         </tr>
     <?php endforeach ?>


=====================================
modules/monitoring/library/Monitoring/Backend/Ido/Query/HostgroupQuery.php
=====================================
@@ -225,15 +225,15 @@ class HostgroupQuery extends IdoQuery
     protected function joinServicegroups()
     {
         $this->requireVirtualTable('services');
-        $this->select->join(
+        $this->select->joinLeft(
             array('sgm' => $this->prefix . 'servicegroup_members'),
             'sgm.service_object_id = s.service_object_id',
             array()
-        )->join(
+        )->joinLeft(
             array('sg' => $this->prefix . 'servicegroups'),
             'sgm.servicegroup_id = sg.servicegroup_id',
             array()
-        )->join(
+        )->joinLeft(
             array('sgo' => $this->prefix . 'objects'),
             'sgo.object_id = sg.servicegroup_object_id AND sgo.is_active = 1 AND sgo.objecttype_id = 4',
             array()
@@ -246,11 +246,11 @@ class HostgroupQuery extends IdoQuery
     protected function joinServices()
     {
         $this->requireVirtualTable('hosts');
-        $this->select->join(
+        $this->select->joinLeft(
             array('s' => $this->prefix . 'services'),
             's.host_object_id = h.host_object_id',
             array()
-        )->join(
+        )->joinLeft(
             array('so' => $this->prefix . 'objects'),
             'so.object_id = s.service_object_id AND so.is_active = 1 AND so.objecttype_id = 2',
             array()


=====================================
modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php
=====================================
@@ -17,6 +17,7 @@ use Icinga\Exception\ProgrammingError;
 use Icinga\Exception\QueryException;
 use Icinga\Web\Session;
 use Icinga\Module\Monitoring\Data\ColumnFilterIterator;
+use Zend_Db_Select;
 
 /**
  * Base class for Ido Queries
@@ -1189,7 +1190,13 @@ abstract class IdoQuery extends DbQuery
     {
         // TODO: This is not generic enough yet
         list($type, $name) = $this->customvarNameToTypeName($customvar);
-        $alias = ($type === 'host' ? 'hcv_' : 'scv_') . $name;
+        $alias = ($type === 'host' ? 'hcv_' : 'scv_') . preg_replace('~[^a-zA-Z0-9_]~', '_', $name);
+
+        // We're replacing any problematic char with an underscore, which will lead to duplicates, this avoids them
+        $from = $this->select->getPart(Zend_Db_Select::FROM);
+        for ($i = 2; array_key_exists($alias, $from); $i++) {
+            $alias = $alias . '_' . $i;
+        }
 
         $this->customVars[strtolower($customvar)] = $alias;
 
@@ -1228,7 +1235,7 @@ abstract class IdoQuery extends DbQuery
     protected function customvarNameToTypeName($customvar)
     {
         $customvar = strtolower($customvar);
-        if (! preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $customvar, $m)) {
+        if (! preg_match('~^_(host|service)_(.+)$~', $customvar, $m)) {
             throw new ProgrammingError(
                 'Got invalid custom var: "%s"',
                 $customvar


=====================================
modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php
=====================================
@@ -192,15 +192,15 @@ class ServicegroupQuery extends IdoQuery
     protected function joinHostgroups()
     {
         $this->requireVirtualTable('services');
-        $this->select->join(
+        $this->select->joinLeft(
             array('hgm' => $this->prefix . 'hostgroup_members'),
             'hgm.host_object_id = s.host_object_id',
             array()
-        )->join(
+        )->joinLeft(
             array('hg' => $this->prefix . 'hostgroups'),
             'hg.hostgroup_id = hgm.hostgroup_id',
             array()
-        )->join(
+        )->joinLeft(
             array('hgo' => $this->prefix . 'objects'),
             'hgo.object_id = hg.hostgroup_object_id AND hgo.objecttype_id = 3 AND hgo.is_active = 1',
             array()


=====================================
modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php
=====================================
@@ -21,7 +21,7 @@ class ServicestatusQuery extends IdoQuery
     /**
      * {@inheritdoc}
      */
-    protected $groupOrigin = array('hostgroups', 'servicegroups');
+    protected $groupOrigin = array('hostgroups', 'servicegroups', 'contacts', 'contactgroups');
 
     protected $subQueryTargets = array(
         'hostgroups'    => 'hostgroup',


=====================================
modules/monitoring/library/Monitoring/Controller.php
=====================================
@@ -3,11 +3,13 @@
 
 namespace Icinga\Module\Monitoring;
 
+use ArrayIterator;
 use Icinga\Exception\ConfigurationError;
 use Icinga\Exception\QueryException;
 use Icinga\Data\Filter\Filter;
 use Icinga\Data\Filterable;
 use Icinga\File\Csv;
+use Icinga\Module\Monitoring\Data\CustomvarProtectionIterator;
 use Icinga\Util\Json;
 use Icinga\Web\Controller as IcingaWebController;
 use Icinga\Web\Url;
@@ -60,7 +62,15 @@ class Controller extends IcingaWebController
                         'Content-Disposition',
                         'inline; filename=' . $this->getRequest()->getActionName() . '.json'
                     )
-                    ->appendBody(Json::sanitize($query->fetchAll()))
+                    ->appendBody(
+                        Json::sanitize(
+                            iterator_to_array(
+                                new CustomvarProtectionIterator(
+                                    new ArrayIterator($query->fetchAll())
+                                )
+                            )
+                        )
+                    )
                     ->sendResponse();
                 exit;
             case 'csv':
@@ -72,7 +82,7 @@ class Controller extends IcingaWebController
                         'Content-Disposition',
                         'attachment; filename=' . $this->getRequest()->getActionName() . '.csv'
                     )
-                    ->appendBody((string) Csv::fromQuery($query))
+                    ->appendBody((string) Csv::fromQuery(new CustomvarProtectionIterator($query)))
                     ->sendResponse();
                 exit;
         }


=====================================
modules/monitoring/library/Monitoring/Data/CustomvarProtectionIterator.php
=====================================
@@ -0,0 +1,25 @@
+<?php
+/* Icinga Web 2 | (c) 2021 Icinga GmbH | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Data;
+
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+use IteratorIterator;
+
+class CustomvarProtectionIterator extends IteratorIterator
+{
+    const IS_CV_RE = '~^_(host|service)_([a-zA-Z0-9_]+)$~';
+
+    public function current()
+    {
+        $row = parent::current();
+
+        foreach ($row as $col => $val) {
+            if (preg_match(self::IS_CV_RE, $col, $m)) {
+                $row->$col = MonitoredObject::protectCustomVars([$m[2] => $val])[$m[2]];
+            }
+        }
+
+        return $row;
+    }
+}


=====================================
modules/monitoring/library/Monitoring/Object/MonitoredObject.php
=====================================
@@ -418,19 +418,6 @@ abstract class MonitoredObject implements Filterable
      */
     public function fetchCustomvars()
     {
-        $blacklist = array();
-        $blacklistPattern = '';
-
-        if (($blacklistConfig = Config::module('monitoring')->get('security', 'protected_customvars', '')) !== '') {
-            foreach (explode(',', $blacklistConfig) as $customvar) {
-                $nonWildcards = array();
-                foreach (explode('*', $customvar) as $nonWildcard) {
-                    $nonWildcards[] = preg_quote($nonWildcard, '/');
-                }
-                $blacklist[] = implode('.*', $nonWildcards);
-            }
-            $blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
-        }
 
         if ($this->type === self::TYPE_SERVICE) {
             $this->fetchServiceVariables();
@@ -442,10 +429,7 @@ abstract class MonitoredObject implements Filterable
 
         $this->customvars = $customvars;
         $this->hideBlacklistedProperties();
-
-        if ($blacklistPattern) {
-            $this->customvars = $this->obfuscateCustomVars($this->customvars, $blacklistPattern);
-        }
+        $this->customvars = $this->obfuscateCustomVars($this->customvars, null);
 
         return $this;
     }
@@ -454,22 +438,48 @@ abstract class MonitoredObject implements Filterable
      * Obfuscate custom variables recursively
      *
      * @param stdClass|array    $customvars         The custom variables to obfuscate
-     * @param string            $blacklistPattern   Which custom variables to obfuscate
      *
      * @return stdClass|array                       The obfuscated custom variables
      */
-    protected function obfuscateCustomVars($customvars, $blacklistPattern)
+    protected function obfuscateCustomVars($customvars, $_)
     {
-        $obfuscatedCustomVars = array();
-        foreach ($customvars as $name => $value) {
-            if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
-                $obfuscatedCustomVars[$name] = '***';
-            } else {
-                $obfuscatedCustomVars[$name] = $value instanceof stdClass || is_array($value)
-                    ? $this->obfuscateCustomVars($value, $blacklistPattern)
-                    : $value;
+        return self::protectCustomVars($customvars);
+    }
+
+    public static function protectCustomVars($customvars)
+    {
+        $blacklist = [];
+        $blacklistPattern = '';
+
+        if (($blacklistConfig = Config::module('monitoring')->get('security', 'protected_customvars', '')) !== '') {
+            foreach (explode(',', $blacklistConfig) as $customvar) {
+                $nonWildcards = array();
+                foreach (explode('*', $customvar) as $nonWildcard) {
+                    $nonWildcards[] = preg_quote($nonWildcard, '/');
+                }
+                $blacklist[] = implode('.*', $nonWildcards);
             }
+            $blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
+        }
+
+        if (! $blacklistPattern) {
+            return $customvars;
         }
+
+        $obfuscatedCustomVars = [];
+        $obfuscator = function ($vars) use ($blacklistPattern, &$obfuscatedCustomVars, &$obfuscator) {
+            foreach ($vars as $name => $value) {
+                if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
+                    $obfuscatedCustomVars[$name] = '***';
+                } else {
+                    $obfuscatedCustomVars[$name] = $value instanceof stdClass || is_array($value)
+                        ? $obfuscator($value)
+                        : $value;
+                }
+            }
+        };
+        $obfuscator($customvars);
+
         return $customvars instanceof stdClass ? (object) $obfuscatedCustomVars : $obfuscatedCustomVars;
     }
 


=====================================
modules/monitoring/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: monitoring
-Version: 2.8.2
+Version: 2.8.3
 Description: Icinga monitoring module
  IDO accessor and UI for your monitoring. This is the initial instalment for a
  graphical presentation of Icinga environments. The predecessor of Icinga DB.


=====================================
modules/setup/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: setup
-Version: 2.8.2
+Version: 2.8.3
 Description: Setup module
  Web based wizard for setting up Icinga Web 2 and its modules.
  This includes the data backends (e.g. relational database, LDAP),


=====================================
modules/test/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: test
-Version: 2.8.2
+Version: 2.8.3
 Description: Translation module
  This module allows developers to run (unit) tests against Icinga Web 2 and
  any of its modules. Usually you do not need to enable this.


=====================================
modules/translation/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: translation
-Version: 2.8.2
+Version: 2.8.3
 Description: Translation module
  This module allows developers and translators to translate Icinga Web 2 and
  its modules for multiple languages. You do not need this module to run an


=====================================
public/css/icinga/layout-structure.less
=====================================
@@ -133,17 +133,20 @@ body {
 
 /*
  * Class to hide content from users but available for screen reader
- * @todo(mh): Replace .audible class
+ * Based on: https://cloudfour.com/thinks/see-no-evil-hidden-content-and-accessibility/
  */
 .sr-only {
   border: 0;
   clip: rect(0 0 0 0);
+  clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
+  -webkit-clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
   height: 1px;
   margin: -1px;
   overflow: hidden;
   padding: 0;
-  position: absolute;
+  position: fixed; // absolute causes view port glitches in chrome (#4310)
   width: 1px;
+  white-space: nowrap;
 }
 
 // Hide non-javascript elements if javascript is enabled


=====================================
public/css/icinga/menu.less
=====================================
@@ -107,7 +107,7 @@
   }
 }
 
-ul:not(.nav-level-2) > .selected > a {
+#menu ul:not(.nav-level-2) > .selected > a {
   background-color: @menu-highlight-color;
   color: @text-color-inverted;
 



View it on GitLab: https://salsa.debian.org/nagios-team/pkg-icingaweb2/-/commit/86d061743b9c40448d1e349f64841fafe566d0c6

-- 
View it on GitLab: https://salsa.debian.org/nagios-team/pkg-icingaweb2/-/commit/86d061743b9c40448d1e349f64841fafe566d0c6
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/20210714/f2bf4416/attachment-0001.htm>


More information about the pkg-nagios-changes mailing list