Skip to content
Commits on Source (3)
1.9.17
* FIX: Fix PHP 5.3 incompatibility introduced with 1.9.16
* FIX: Fix IE 11 incompatibility on worldmaps in relation to lines
which was introduced with 1.9.13
* FIX: Fix incompatibility with Check 1.6 auth cookies of users with special
characters in the user ID
1.9.16
Core:
* Add support for Encrypted livestatus. You can now configure "tcp-tls:[address]:[port]"
as socket address and control the TLS verification using the new backend specific
settings "verify_tls_peer" and "verify_tls_ca_path".
1.9.15
Core:
* FIX: "You are not permitted to access this page (ChangePassword/view/)" for users (issue #215)
Frontend:
* FIX: Fix IE 11 incompatibility regression introduced with 1.9.13
1.9.14
Core:
* MKBI backend: Use "htmlcgi" URL/path for building links to the Checkmk GUI
(Aggregations used the base_url, which should not be used for user URLs)
Worldmap:
* Consistent page reloads: center + zoom of the map kept in URL
* Memory and performance optimization: line rendering - clip long lines protruding out of viewport
* Memory and performance optimization: fix getMapObject SQL query (lng/lat rectangle)
Frontend
* FIX: Fix creating users when mbstring extension is not available
1.9.13
Worldmap:
* Configurable OpenStreetMap tile server URL (worldmap_tiles_{url,attribution})
* OpenStreetMap tile colors can now be dimmed using the
worldmap_tiles_saturate configuration option so that larger colorful
backgrounds do not interfere with the map objects.
* Optional 2nd map layer (satellite imagery)
* FIX: Worldmap textbox visibility per zoom level
* FIX: The "clone object" functionality did sometimes break with an error
message like "Invalid argument supplied for foreach()"
(Thanks to Vojtech Pithart for taking the time to improve the NagVis worldmap!)
1.9.12
Core:
* FIX: Allow "*" character to be part of backend dbpass values
* Multisite Snapin: Reworked data export API to snapin. The new API is
compatible with Checkmk 1.6b2 and newer.
Frontend
* FIX: Fixed incompatibility with PHP 7.2 (count(STRING)) when creating roles
Geomap:
* Improved error handling of CSV lines with less than 4 fields
1.9.11
Frontend
* FIX: Weathermap lines now respect the configured error colors
......
nagvis (1:1.9.11-2) UNRELEASED; urgency=medium
nagvis (1:1.9.17-1) unstable; urgency=medium
[ Debian Janitor ]
* Trim trailing whitespace.
......@@ -12,7 +12,10 @@ nagvis (1:1.9.11-2) UNRELEASED; urgency=medium
[ Bas Couwenberg ]
* Add Bug-* fields to upstream metadata.
-- Debian Janitor <janitor@jelmer.uk> Wed, 11 Dec 2019 00:49:40 +0000
[ Adam Cecile ]
* New upstream release (Closes: #949387).
-- Adam Cecile <acecile@le-vert.net> Mon, 20 Jan 2020 16:02:56 +0100
nagvis (1:1.9.11-1) unstable; urgency=medium
......
......@@ -26,7 +26,21 @@
<tr>
<td>socket</td>
<td>unix:/usr/local/nagios/var/rw/live</td>
<td><p>The socket to connect to can be a local unix socket or a tcp socket. You have to define the type at the beginning of the string. Set &quot;unix:&quot; for unix sockets or &quot;tcp:&quot; for tcp sockets.</p> <p>In case of the unix socket you need to specify the path of the livestatus unix socket to connect to.</p> <p>When using a tcp socket you have to enter a host address and a tcp port using the following scheme: &lt;host>:&lt;port>. The host address can be an IP address or an FQDN.</p></td>
<td><p>The socket to connect to can be a local unix socket or a tcp
socket. You have to define the type at the beginning of the string.
Set &quot;unix:&quot; for unix sockets or &quot;tcp:&quot; for tcp
sockets.</p>
<p><font color="#f00">New in 1.9.16</font>:Since Checkmk 1.6.0 it is possible to encrypt the Livestatus
channel using TLS. To connnect to such a channel use &quot;tcp-tls:&quot;.</p>
<p>In case of the unix socket you need to specify the
path of the livestatus unix socket to connect to.</p>
<p>When using a tcp socket you have to enter a host address and a
tcp port using the following scheme: &lt;host>:&lt;port>. The host address can
be an IP address or an FQDN.</p>
</td>
</tr><tr>
<td>timeout</td>
<td>5</td>
......@@ -35,6 +49,25 @@
This is just a fallback. To prevent timeouts when accessing remote sites you really should configure a statushost for the backend.
For details take a look at the general backend parameters documented in the <a href="nagvis_config_format_description.html#backend">backend section</a>
of the main configuration format description.</a></td>
</tr><tr>
<td>verify_tls_peer</td>
<td>1</td>
<td>
<font color="#f00">New in 1.9.16</font>: Only relevant when you connect to a Livestatus TLS encrypted socket.
This can be used to turn off the peer certificate verification. In case it is enabled, you will have to
set the <tt>verify_tls_ca_path</tt> option.
</td>
</tr><tr>
<td>verify_tls_ca_path</td>
<td></td>
<td>
<font color="#f00">New in 1.9.16</font>: Configure an absolute
path that points to a CA chain file which is then used to verify the
certificate of the Livestatus TLS server. You can, for example in Checkmk
sites, point it to the, "Trusted certificate authorities file of Checkmk
(/omd/sites/[site-id]/var/ssl/ca-certificates.crt) to use the same trust
configuration in NagVis and Checkmk.
</td>
</tr>
</table>
<p>There are also some general parameters. You can read about them in <a href="nagvis_config_format_description.html#backend">main configuration format description</a>.</p>
......
......@@ -102,6 +102,28 @@
<td>The server to use as source for the NagVis geomaps. Must implement the API which can be found <a href="http://pafciu17.dev.openstreetmap.org/">here</a></td>
</tr>
<tr>
<td>worldmap_tiles_url <font color="#ff0000">(new in 1.9.13)</font></td>
<td>https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png</td>
<td>Worldmap uses OpenStreetMap tiles as default map background. The URL specifies where to GET the PNG tile images from.</td>
</tr>
<tr>
<td>worldmap_tiles_attribution <font color="#ff0000">(new in 1.9.13)</font></td>
<td>&copy; &lt;a href="http://www.openstreetmap.org/copyright"&gt;OpenStreetMap&lt;/a&gt;</td>
<td>Map tiles attribution text (shown in bottom right corner)</td>
</tr>
<tr>
<td>worldmap_satellite_tiles_url<br>
worldmap_satellite_tiles_attribution<br>
<font color="#ff0000">(new in 1.9.13)</font>
</td>
<td></td>
<td>Secondary map background tiles (satellite images) URL and attribution.
When used, the <a href="https://leafletjs.com/reference-1.5.0.html#control-layers">layers control</a>
appears on top right corner of the map.
</td>
</tr>
<tr>
<td>http_proxy <font color="#ff0000">(new in 1.6)</font></td>
<td></td>
......
......@@ -22,11 +22,12 @@
<h2>Prerequisites</h2>
<p>There is no special software needed on the NagVis server, but there is one special requirement. To
be able to use this feature, the browser opening NagVis worldmaps needs to be able to fetch the background
images (map tiles) from the internet. In most corporate environments this means that your client needs
images (map tiles) from the internet, or a local mirror, see below. In most corporate environments this means that your client needs
to have a proxy server configured.</p>
<p>The worldmaps currently use the official tile servers of Open Street Map
(<code>https://{s}.tile.openstreetmap.org/</code>). This is currently hardcoded, but might be made configurable
in the future.</p>
<p>The worldmaps use the official tile servers of Open Street Map (<code>https://{s}.tile.openstreetmap.org/</code>) as a default.
Alternative tile server (local mirror) may be set in configuration, for example: <code>worldmap_tiles_url="http://my-tiles.local/{z}/{x}/{y}.png"</code> </p>
<p>The <a href="https://switch2osm.org/serving-tiles/">switch2osm guides</a> might help you to spin up your local OpenStreetMap mirror.</p>
<h2>The first call</h2>
<p>NagVis comes with a demo worldmap called "demo-worldmap". If your NagVis is configured correctly
......@@ -48,6 +49,7 @@
sources=worldmap
worldmap_center=50.86837814203458,10.21728515625
worldmap_zoom=6
worldmap_tiles_saturate=33
}</pre>
<p>Only the last three attributes are worldmap specific definitions, all of them are mandatory for
......@@ -62,6 +64,8 @@
<p>The <code>worldmap_zoom=6</code> specifies the initial zoom level to be used when rendering the worldmap.
NagVis allows zoom levels from 2 to 18.</p>
<p>The <code>worldmap_tiles_saturate=33</code> dims the colors of default OpenStreetMap so that red motorways or
large green forests don't interfere with actual map objects. Possible values are 0 (no colors, grayscale) through 100 (full colors).</p>
<h2>Create your own worldmap</h2>
......
......@@ -6,6 +6,7 @@ define global {
backend_id=demo
worldmap_center=50.86837814203458,10.21728515625
worldmap_zoom=6
worldmap_tiles_saturate=33
iconset=std_geo
icon_size=32
}
......@@ -71,6 +71,14 @@
; can be found on http://pafciu17.dev.openstreetmap.org/
;geomap_server="http://geomap.nagvis.org/"
;
; Public or private mirror of OpenStreetMap tiles server
;worldmap_tiles_url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
;worldmap_tiles_attribution="&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>"
;
; Secondary "satellite" tiles server
;worldmap_satellite_tiles_url=""
;worldmap_satellite_tiles_attribution=""
;
; In some cases NagVis needs to open connections to the internet. The cases are:
; - The new geomap needs access to openstreetmap webservices to be able to fetch
; mapping information
......
......@@ -716,7 +716,7 @@ var ElementHover = Element.extend({
var regex = getRegEx('loopChild', "<!--\\sBEGIN\\sloop_child\\s-->(.+?)<!--\\sEND\\sloop_child\\s-->");
if(this.template_html.search(regex) !== -1)
this.template_html = this.template_html.replace(regex, '<!-- BEGIN loop_child -->'
+ g_hover_template_childs[this.obj.hover_template]
+ g_hover_template_childs[this.obj.conf.hover_template]
+ '<!-- END loop_child -->');
// Search for images and append current timestamp to src (prevent caching of
......
......@@ -340,6 +340,16 @@ var ElementLine = Element.extend({
var xEnd = x[x.length - 1];
var yEnd = y[y.length - 1];
let adjustedPoints = this.cutLineBeyondViewport(xStart, yStart, xEnd, yEnd);
if (adjustedPoints === null) {
return; // Line won't be visible -> this.parts left empty -> no rendering
}
xStart = adjustedPoints[0];
yStart = adjustedPoints[1];
xEnd = adjustedPoints[2];
yEnd = adjustedPoints[3];
var width = addZoomFactor(this.obj.conf.line_width);
if (width <= 0)
width = 1; // minimal width for lines
......@@ -422,6 +432,10 @@ var ElementLine = Element.extend({
},
renderLine: function() {
if (this.parts.length === 0) {
return;
}
var allX = [], allY = [];
for (var i = 0, len = this.parts.length; i < len; i++) {
allX = allX.concat(this.parts[i][2]);
......@@ -948,6 +962,147 @@ var ElementLine = Element.extend({
]);
}
return parsed;
},
/*
* There is a rectangle: viewport (current Leaflet map shown) + 10% on each side.
* This function cuts the lines protruding beyond the rectangle.
* Shortened lines prevent renderLine() from generating many vast <canvas> (10000-ish pixels) which eventually lead
* to memory exhaustion or crash the browser
*
* Returns:
* either: [xA, yA, xB, yB] - original or adjusted line A/B coordinates,
* or: null - line out of a rectangle, don't render
*/
cutLineBeyondViewport: function(xA, yA, xB, yB) {
if (!g_map)
return([xA, yA, xB, yB]); // no viewport - no clipping
let viewport_size = g_map.getSize();
const xMax = viewport_size.x; // 1920
const yMax = viewport_size.y; // 1080
const xTolerance = xMax * 0.1; // 192 (10%)
const yTolerance = yMax * 0.1; // 108 (10%)
// Cohen-Sutherland algorithm
// region codes
const INSIDE = 0; // 0000
const LEFT = 1; // 0001
const RIGHT = 2; // 0010
const BOTTOM = 4; // 0100
const TOP = 8; // 1000
// boundaries
const x_min = -xTolerance;
const x_max = xMax + xTolerance;
const y_min = -yTolerance;
const y_max = yMax + yTolerance;
// Function to compute region code
let regionCode = function (x, y)
{
let code = INSIDE;
if (x < x_min) // to the left of rectangle
code |= LEFT;
else if (x > x_max) // to the right of rectangle
code |= RIGHT;
if (y < y_min) // below the rectangle
code |= BOTTOM;
else if (y > y_max) // above the rectangle
code |= TOP;
return code;
}
let cohenSutherlandClip = function (x1, y1, x2, y2) {
let code1 = regionCode(x1, y1);
let code2 = regionCode(x2, y2);
let accept = false;
while (true)
{
if ((code1 == 0) && (code2 == 0))
{
// If both endpoints lie within rectangle
accept = true;
break;
}
else if (code1 & code2)
{
// If both endpoints are outside rectangle,
// in same region
break;
}
else
{
// Some segment of line lies within the
// rectangle
let code_out;
let x, y;
// At least one endpoint is outside the
// rectangle, pick it.
if (code1 != 0)
code_out = code1;
else
code_out = code2;
// Find intersection point;
// using formulas y = y1 + slope * (x - x1),
// x = x1 + (1 / slope) * (y - y1)
if (code_out & TOP)
{
// point is above the clip rectangle
x = x1 + (x2 - x1) * (y_max - y1) / (y2 - y1);
y = y_max;
}
else if (code_out & BOTTOM)
{
// point is below the rectangle
x = x1 + (x2 - x1) * (y_min - y1) / (y2 - y1);
y = y_min;
}
else if (code_out & RIGHT)
{
// point is to the right of rectangle
y = y1 + (y2 - y1) * (x_max - x1) / (x2 - x1);
x = x_max;
}
else if (code_out & LEFT)
{
// point is to the left of rectangle
y = y1 + (y2 - y1) * (x_min - x1) / (x2 - x1);
x = x_min;
}
// Now intersection point x,y is found
// We replace point outside rectangle
// by intersection point
if (code_out == code1)
{
x1 = x;
y1 = y;
code1 = regionCode(x1, y1);
}
else
{
x2 = x;
y2 = y;
code2 = regionCode(x2, y2);
}
}
}
if (accept)
return([x1, y1, x2, y2]);
else
return null;
}
return cohenSutherlandClip(xA, yA, xB, yB);
},
});
......@@ -436,20 +436,33 @@ var NagVisStatefulObject = NagVisObject.extend({
var sColor = oStates[this.conf.summary_state].color;
// Use these classes (icon-flashing-<state>) in your custom css to customise flashing icons
// e.g. icon-flashing-critical, icondiv-flashing-critical
// Note you may need to use '!important' to override the inline default
//
var sFlashingClass = 'icon-flashing-' + this.conf.summary_state.toLowerCase();
var sFlashingDivClass = 'icondiv-flashing-' + this.conf.summary_state.toLowerCase();
this.bIsFlashing = show;
if(show) {
oObjIcon.style.border = "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.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);
}
sColor = null;
sFlashingClass = null;
sFlashingDivClass = null;
oObjIconDiv = null;
oObjIcon = null;
},
}
});
......@@ -55,16 +55,41 @@ var ViewWorldmap = ViewMap.extend({
initWorldmap: function() {
L.Icon.Default.imagePath = oGeneralProperties.path_base+'/frontend/nagvis-js/images/leaflet';
var layers = {
"map": L.tileLayer(oGeneralProperties.worldmap_tiles_url, {
attribution: oGeneralProperties.worldmap_tiles_attribution,
noWrap: true, // don't repeat the world on horizontal axis
detectRetina: true, // look nice on high resolution screens
maxZoom: 20,
}),
}
if(oGeneralProperties.worldmap_satellite_tiles_url) {
layers.satellite = L.tileLayer(oGeneralProperties.worldmap_satellite_tiles_url, {
attribution: oGeneralProperties.worldmap_satellite_tiles_attribution,
noWrap: true, // don't repeat the world on horizontal axis
detectRetina: true, // look nice on high resolution screens
maxZoom: 20,
})
}
g_map = L.map('map', {
markerZoomAnimation: false,
maxBounds: [ [-85,-180.0], [85,180.0] ],
minZoom: 2
}).setView(getViewParam('worldmap_center').split(','), parseInt(getViewParam('worldmap_zoom')));
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
noWrap: true, // don't repeat the world on horizontal axe
detectRetina: true, // look nice on high resolution screens
}).addTo(g_map);
minZoom: 2,
layers: [layers.map]
})
let restored_coordinates = window.location.hash.substr(1).split('/');
if (restored_coordinates.length === 3) {
// place the map view according to location hash (#lat/lon/zoom) - consistent page reloads
g_map.setView([restored_coordinates[1], restored_coordinates[0]], restored_coordinates[2]);
} else {
// or default (map-defined) view
g_map.setView(getViewParam('worldmap_center').split(','), parseInt(getViewParam('worldmap_zoom')));
}
if (layers.satellite)
L.control.layers(layers).addTo(g_map);
g_map_objects = L.layerGroup().addTo(g_map);
......@@ -80,6 +105,12 @@ var ViewWorldmap = ViewMap.extend({
if (typeof checkHideMenu !== "undefined")
g_map.on('mousedown', checkHideMenu);
g_map.on('mousedown', context_handle_global_mousedown);
// dim the colors of map background so that red motorways don't distract
let saturate_percentage = getViewParam('worldmap_tiles_saturate');
let ltp = document.getElementsByClassName('leaflet-tile-pane');
if (ltp && saturate_percentage !== '')
ltp[0].style.filter = "saturate("+saturate_percentage+"%)";
},
handleMoveStart: function(lEvent) {
......@@ -94,6 +125,10 @@ var ViewWorldmap = ViewMap.extend({
setViewParam('worldmap_zoom', g_map.getZoom());
this.render(); // re-render the whole map
// Put the new map view coords into URL (location) - consistent reloads
new_center = g_map.getCenter();
window.location.hash = new_center.lng + "/" + new_center.lat + "/" + g_map.getZoom();
},
saveView: function() {
......
......@@ -79,7 +79,11 @@ class CoreLogonMultisite extends CoreLogonModule {
throw new Exception();
}
list($username, $issueTime, $cookieHash) = explode(':', $_COOKIE[$cookieName], 3);
// 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], '"');
list($username, $issueTime, $cookieHash) = explode(':', $cookieValue, 3);
if($this->authFile == 'htpasswd')
$users = $this->loadAuthFile($this->htpasswdPath);
......
......@@ -39,15 +39,25 @@ class CoreModMultisite extends CoreModule {
if(!$this->offersAction($this->sAction))
return '';
$maps = array();
switch($this->sAction) {
case 'getMaps':
if (cfg('global', 'multisite_snapin_layout') == 'tree') {
return $this->renderTree();
$maps = array(
"type" => "tree",
"maps" => $this->renderTree(),
);
} else {
return $this->renderTable();
$maps = array(
"type" => "table",
"maps" => $this->renderTable(),
);
}
break;
}
return json_encode($maps);
}
private function renderTree() {
......@@ -55,102 +65,38 @@ class CoreModMultisite extends CoreModule {
$childs = array();
foreach ($this->getMapsCached() as $map) {
if($map['parent_map'] === '')
$maps[$map['name']] = $map;
$maps[$map['name']] = $this->getMapForMultisite($map);
else {
if(!isset($childs[$map['parent_map']]))
$childs[$map['parent_map']] = Array();
$childs[$map['parent_map']][$map['name']] = $map;
}
}
$s = '<ul>'.$this->renderTreeNodes($maps, $childs).'</ul>';
// FIXME: check_mk/tree_state.py?tree=nagvis holen
// evaluieren
// alles was auf off steht per toggle_foldable_container schließen
return $s.$this->renderFootnotelinks();
$childs[$map['parent_map']][$map['name']] = $this->getMapForMultisite($map);
}
private function renderTreeNodes($maps, $childs) {
$s = '';
foreach($maps AS $map) {
// this copies the foldable_container code provided in Check_MK htmllib
// assume always open by default
$s .= '<li>';
$map_url = cfg('paths', 'htmlbase').'/index.php?mod=Map&act=view&show='.$map['name'];
if(isset($childs[$map['name']])) {
$act = 'onclick="toggle_foldable_container(\'nagvis\', \''.$map['name'].'\')" '
. 'onmouseover="this.style.cursor=\'pointer\';" '
. 'onmouseout="this.style.cursor=\'auto\';"';
$s .= '<img align=absbottom class="treeangle" id="treeimg.nagvis.'.$map['name'].'" '
. 'src="images/tree_90.png" '.$act.' />';
$s .= '<a href="'.$map_url.'" target="main"><b class="treeangle title" class=treeangle>';
$s .= $map['alias'];
$s .= '</b></a><br>';
$s .= '<ul class="treeangle open" style="padding-left:0;" id="tree.nagvis.'.$map['name'].'">';
$s .= $this->renderTreeNodes($childs[$map['name']], $childs);
$s .= '</ul>';
} else {
$s .= '<a target="main" href="'.$map_url.'">'.$map['alias'].'</a>';
}
$s .= '</li>';
}
return $s;
return array(
"maps" => $maps,
"childs" => $childs,
);
}
private function renderTable() {
$code = '<table class="allhosts"><tbody>';
$maps = array();
foreach ($this->getMapsCached() as $map) {
switch($map['summary_state']) {
case 'OK':
case 'UP':
$state = '0';
break;
case 'WARNING':
$state = '1';
break;
case 'CRITICAL':
case 'DOWN':
case 'UNREACHABLE':
$state = '2';
break;
default:
$state = '3';
break;
}
$title = $map['summary_state'];
if ($map['summary_in_downtime']) {
$state .= ' stated';
$title .= ' (Downtime)';
}
elseif ($map['summary_problem_has_been_acknowledged']) {
$state .= ' statea';
$title .= ' (Acknowledged)';
$maps[] = $this->getMapForMultisite($map);
}
if ($map['summary_stale']) {
$state .= ' stale';
$title .= ' (Stale)';
return $maps;
}
$code .= '<tr><td>';
$code .= '<div class="statebullet state'.$state.'" title="'.$title.'">&nbsp;</div>';
$code .= '<a href="'.cfg('paths', 'htmlbase').'/index.php?mod=Map&act=view&show='.$map['name'].'" ';
$code .= 'class="link" target="main">'.$map['alias'].'</a>';
$code .= '</td></tr>';
}
$code .= '</tbody></table>';
return $code.$this->renderFootnotelinks();
}
private function renderFootnoteLinks() {
$url = cfg('paths', 'htmlbase');
return "<div class=footnotelink>"
."<a onfocus=\"if (this.blur) this.blur();\" target=\"main\" class=\"link\" href=\"".$url."/\">EDIT</a>"
."</div>";
private function getMapForMultisite($map) {
return array(
"name" => $map["name"],
"title" => $map['summary_state'],
"alias" => $map['alias'],
"url" => cfg('paths', 'htmlbase').'/index.php?mod=Map&act=view&show='.$map['name'],
"summary_state" => $map["summary_state"],
"summary_in_downtime" => $map['summary_in_downtime'],
"summary_problem_has_been_acknowledged" => $map['summary_problem_has_been_acknowledged'],
"summary_stale" => $map['summary_stale'],
);
}
// Wraps the getMaps() function by applying a short livetime cache based
......
......@@ -63,6 +63,7 @@ class CorePDOHandler {
.'WHERE users2roles."userId" = :id',
'-perm-rename-map' => 'UPDATE perms SET obj=:new_name '.
' WHERE "mod"=\'Map\' AND obj=:old_name',
'-perm-change-act' => 'UPDATE perms SET act=:new_act WHERE mod=:mod and act=:old_act',
'-role-add' => 'INSERT INTO roles (name) VALUES (:name)',
'-role-add-with-id' => 'INSERT INTO roles ("roleId", name) VALUES (:roleId, :name)',
......@@ -128,6 +129,10 @@ class CorePDOHandler {
),
'updates' => array(
'1091500' => array(
array('-perm-change-act', array('mod' => 'ChangePassword', 'old_act' => 'change', 'new_act' => '*'))
),
'1080600' => array(
array('-perm-add', array('mod' => 'Url', 'act' => 'view', 'obj' => '*')),
array('-create-pop-roles-perms-3', array(
......@@ -261,6 +266,7 @@ class CorePDOHandler {
}
$drv_data = self::$DRIVERS[$driver];
$dsn = "$driver:".$drv_data['build_dsn']($params);
$this->dsn = $dsn;
try {
$this->DB = new PDO($dsn, $username, $password, array(
......@@ -270,12 +276,12 @@ class CorePDOHandler {
));
} catch(PDOException $e) {
error_log('Could not initialize a database connection: '.$e->getMessage());
$this->lastErrorInfo = $e->getMessage();
return false;
}
if($this->DB === false || $this->DB === null)
return false;
$this->dsn = $dsn;
$this->driver = $driver;
$this->data = $drv_data;
$this->updating = false;
......@@ -286,6 +292,7 @@ class CorePDOHandler {
$res = $this->DB->exec($q);
if($res === false) {
$this->DB = null;
$this->lastErrorInfo = "Initial DB query ($q) failed";
return false;
}
}
......@@ -356,7 +363,7 @@ class CorePDOHandler {
if (isset($this->lastErrorInfo))
return $this->lastErrorInfo;
else
return $this->DB->errorInfo();
return $this->DB ? $this->DB->errorInfo() : '';
}
public function errorString() {
......@@ -460,7 +467,7 @@ class CorePDOHandler {
try {
ksort(self::$DRIVERS['_common']['updates']);
foreach (self::$DRIVERS['_common']['updates'] as $ver => $queries) {
if (intval($ver) <= $dbVersion)
if (intval($ver) < $dbVersion)
continue;
if (!$this->inTrans) {
......@@ -583,7 +590,7 @@ class CorePDOHandler {
$this->queryFatal('-perm-add', array('mod' => 'User', 'act' => 'setOption', 'obj' => '*'));
// Access controll: Change own password
$this->queryFatal('-perm-add', array('mod' => 'ChangePassword', 'act' => 'change', 'obj' => '*'));
$this->queryFatal('-perm-add', array('mod' => 'ChangePassword', 'act' => '*', 'obj' => '*'));
// Access controll: View maps via multisite
$this->queryFatal('-perm-add', array('mod' => 'Multisite', 'act' => 'getMaps', 'obj' => '*'));
......
......@@ -127,7 +127,8 @@ class GlobalBackendmkbi implements GlobalBackendInterface {
}
private function aggrUrl($name) {
return $this->baseUrl.'view.py?view_name=aggr_single&aggr_name='.$name.'&po_aggr_expand=1';
$html_cgi = cfg('backend_'.$this->backendId, 'htmlcgi');
return $html_cgi.'/view.py?view_name=aggr_single&aggr_name='.$name.'&po_aggr_expand=1';
}
/**
......
......@@ -37,6 +37,7 @@
class GlobalBackendmklivestatus implements GlobalBackendInterface {
private $backendId = '';
private $CONNECT_ERR = "";
private $CONNECT_EXC = null;
private $SOCKET = null;
private $socketType = '';
......@@ -52,6 +53,19 @@ class GlobalBackendmklivestatus implements GlobalBackendInterface {
'default' => 'unix:/usr/local/nagios/var/rw/live',
'match' => MATCH_SOCKET,
),
'verify_tls_peer' => Array(
'must' => 0,
'editable' => 1,
'default' => 1,
'match' => MATCH_BOOLEAN,
'field_type' => 'boolean',
),
'verify_tls_ca_path' => Array(
'must' => 0,
'editable' => 1,
'default' => '',
'match' => MATCH_STRING_PATH,
),
'timeout' => Array(
'must' => 1,
'editable' => 1,
......@@ -118,7 +132,7 @@ class GlobalBackendmklivestatus implements GlobalBackendInterface {
if($type === 'unix') {
$this->socketType = $type;
$this->socketPath = $address;
} elseif($type === 'tcp') {
} elseif($type === 'tcp' || $type === 'tcp-tls') {
$this->socketType = $type;
// Extract address and port
......@@ -126,6 +140,7 @@ class GlobalBackendmklivestatus implements GlobalBackendInterface {
$this->socketAddress = $address;
$this->socketPort = $port;
} else {
throw new BackendConnectionProblem(
l('Unknown socket type given in backend [BACKENDID]',
......@@ -170,31 +185,77 @@ class GlobalBackendmklivestatus implements GlobalBackendInterface {
if($this->CONNECT_EXC != null)
throw $this->CONNECT_EXC;
set_error_handler(array($this, 'connectErrorHandler'), E_WARNING | E_NOTICE);
// Connect to the socket
// don't want to see the connection error messages - want to handle the
// errors later with an own error message
// FIXME: Maybe use pfsockopen in the future to use persistent connections
if($this->socketType === 'unix') {
$oldLevel = error_reporting(0);
$this->SOCKET = fsockopen('unix://'.$this->socketPath, NULL, $errno, $errstr, (float) cfg('backend_'.$this->backendId, 'timeout'));
error_reporting($oldLevel);
} elseif($this->socketType === 'tcp-tls') {
if (cfg('backend_'.$this->backendId, 'verify_tls_peer') == true) {
$ssl_options = Array(
'verify_peer' => true,
'verify_peer_name' => false,
'verify_depth' => 1,
);
$ca_path = cfg('backend_'.$this->backendId, 'verify_tls_ca_path');
if ($ca_path)
$ssl_options['cafile'] = $ca_path;
$context = stream_context_create(Array(
'ssl' => $ssl_options
));
} else {
$context = stream_context_create(Array(
'ssl' => Array(
'verify_peer' => false,
'verify_peer_name' => false
)
));
}
$this->SOCKET= stream_socket_client(
"tls://" . $this->socketAddress . ":" . $this->socketPort, $errno, $errstr,
(float) cfg('backend_'.$this->backendId, 'timeout'), STREAM_CLIENT_CONNECT,
$context);
} elseif($this->socketType === 'tcp') {
$oldLevel = error_reporting(0);
$this->SOCKET = fsockopen($this->socketAddress, $this->socketPort, $errno, $errstr, (float) cfg('backend_'.$this->backendId, 'timeout'));
error_reporting($oldLevel);
$this->SOCKET = fsockopen($this->socketAddress, $this->socketPort, $errno, $errstr,
(float) cfg('backend_'.$this->backendId, 'timeout'));
}
restore_error_handler();
if(!$this->SOCKET) {
if ($errno === 0)
$error_msg = $this->CONNECT_ERR;
else
$error_msg = $errstr;
$this->SOCKET = null;
$this->CONNECT_EXC = new BackendConnectionProblem(
l('Unable to connect to the [SOCKET] in backend [BACKENDID]: [MSG]',
Array('BACKENDID' => $this->backendId,
'SOCKET' => $this->socketPath,
'MSG' => $errstr)));
'MSG' => $error_msg)));
throw $this->CONNECT_EXC;
}
}
/**
* Catch PHP errors occured during connect
*/
public function connectErrorHandler($errno, $errstr) {
if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) {
return false; // use default error handler
}
$this->CONNECT_ERR .= $errstr . "\n";
return true;
}
/*private function verifyLivestatusVersion() {
$result = $this->queryLivestatusSingleColumn("GET status\nColumns: livestatus_version\n");
$result[0] = '1.1.7rc1';
......
......@@ -154,6 +154,27 @@ class GlobalMainCfg {
'match' => MATCH_STRING_URL,
),
'worldmap_tiles_url' => array(
'must' => 0,
'default' => 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'match' => MATCH_STRING_URL,
),
'worldmap_tiles_attribution' => array(
'must' => 0,
'default' => '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
'match' => MATCH_ALL
),
'worldmap_satellite_tiles_url' => array(
'must' => 0,
'default' => '',
'match' => MATCH_STRING_URL,
),
'worldmap_satellite_tiles_attribution' => array(
'must' => 0,
'default' => '',
'match' => MATCH_ALL
),
'http_proxy' => array(
'must' => 0,
'default' => null,
......@@ -2184,6 +2205,11 @@ class GlobalMainCfg {
'internal_title' => $this->getValue('internal', 'title'),
'header_show_states' => intval($this->getValue('defaults', 'header_show_states')),
'zoom_scale_objects' => intval($this->getValue('defaults', 'zoom_scale_objects')),
'worldmap_tiles_url' => $this->getValue('global', 'worldmap_tiles_url'),
'worldmap_tiles_attribution' => $this->getValue('global', 'worldmap_tiles_attribution'),
'worldmap_satellite_tiles_url' => $this->getValue('global', 'worldmap_satellite_tiles_url'),
'worldmap_satellite_tiles_attribution' => $this->getValue('global', 'worldmap_satellite_tiles_attribution'),
// Add custom action configuration
);
// Add custom action configuration
......
......@@ -35,7 +35,7 @@ class ViewManageRoles {
if (!$name)
throw new FieldInputError('name', l('Please specify a name'));
if (count($name) > AUTH_MAX_ROLENAME_LENGTH)
if (strlen($name) > AUTH_MAX_ROLENAME_LENGTH)
throw new FieldInputError('name', l('This name is too long'));
if (!preg_match(MATCH_ROLE_NAME, $name))
......
......@@ -35,7 +35,7 @@ class ViewManageUsers {
if (!$name)
throw new FieldInputError('name', l('Please specify a name.'));
if (mb_strlen($name) > AUTH_MAX_USERNAME_LENGTH)
if (strlen($name) > AUTH_MAX_USERNAME_LENGTH)
throw new FieldInputError('name', l('This name is too long.'));
if (!preg_match(MATCH_USER_NAME, $name))
......@@ -49,7 +49,7 @@ class ViewManageUsers {
if (!$password1)
throw new FieldInputError('password1', l('Please specify a password.'));
if (mb_strlen($password1) > AUTH_MAX_PASSWORD_LENGTH)
if (strlen($password1) > AUTH_MAX_PASSWORD_LENGTH)
throw new FieldInputError('password1', l('This password is too long.'));
$password2 = post('password2');
......@@ -254,7 +254,7 @@ class ViewManageUsers {
if (!$password1)
throw new FieldInputError('password1', l('Please specify a password.'));
if (mb_strlen($password1) > AUTH_MAX_PASSWORD_LENGTH)
if (strlen($password1) > AUTH_MAX_PASSWORD_LENGTH)
throw new FieldInputError('password1', l('This password is too long.'));
$password2 = post('password2');
......