aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorPeter Wu2014-07-20 23:30:49 +0200
committerPeter Wu2014-07-20 23:30:49 +0200
commit4a737bc1abdbef7e0698b006704a26583a4c61df (patch)
tree7d5f51f76acd43d1aeda601dd7201e2c158bdae4
parentsecurity: Add missing input validation for plugin (diff)
downloadapt-panopticon_cgp-4a737bc1abdbef7e0698b006704a26583a4c61df.zip
apt-panopticon_cgp-4a737bc1abdbef7e0698b006704a26583a4c61df.tar.gz
apt-panopticon_cgp-4a737bc1abdbef7e0698b006704a26583a4c61df.tar.bz2
apt-panopticon_cgp-4a737bc1abdbef7e0698b006704a26583a4c61df.tar.xz
Use a more secure command line building method
Previously, a command is built by string concatenation. Here, the distinction between a value and multiple params got lost. Solve this by using an array for shell arguments. As the escaping is now removed from the `rrd_gen_graph` function, the canvas style needs to manually add those quotes to make the JS code still work. That only supports double-quotes, so hopefully nobody creates a name with a double quote as that would break the fragile JS command line parser. Separate the rrdtool options from the rrdtool graph command to make the `$graph_type == 'canvas'` option work (it would otherwise not understand the `rrdtool graph - -a PNG` option). Merge the SVG and PNG cases as they are the same except for the Content-Type header. Fix a missing html escape in a debug style.
Diffstat (limited to '')
-rw-r--r--conf/config.php4
-rw-r--r--graph.php11
-rw-r--r--plugin/cpu.json2
-rw-r--r--type/Base.class.php104
-rw-r--r--type/Default.class.php10
-rw-r--r--type/GenericIO.class.php20
-rw-r--r--type/GenericStacked.class.php10
-rw-r--r--type/Uptime.class.php12
8 files changed, 100 insertions, 73 deletions
diff --git a/conf/config.php b/conf/config.php
index 30eaaf9..57a0188 100644
--- a/conf/config.php
+++ b/conf/config.php
@@ -12,8 +12,8 @@ $CONFIG['typesdb'][] = '/usr/share/collectd/types.db';
12# rrdtool executable 12# rrdtool executable
13$CONFIG['rrdtool'] = '/usr/bin/rrdtool'; 13$CONFIG['rrdtool'] = '/usr/bin/rrdtool';
14 14
15# rrdtool special options 15# rrdtool special command-line options
16$CONFIG['rrdtool_opts'] = ''; 16$CONFIG['rrdtool_opts'] = [];
17 17
18# category of hosts to show on main page 18# category of hosts to show on main page
19#$CONFIG['cat']['category1'] = array('host1', 'host2'); 19#$CONFIG['cat']['category1'] = array('host1', 'host2');
diff --git a/graph.php b/graph.php
index 1727c1b..3e33b92 100644
--- a/graph.php
+++ b/graph.php
@@ -86,7 +86,16 @@ if (isset($plugin_json[$type]['vertical'])) {
86} 86}
87 87
88if (isset($plugin_json[$type]['rrdtool_opts'])) { 88if (isset($plugin_json[$type]['rrdtool_opts'])) {
89 $obj->rrdtool_opts[] = $plugin_json[$type]['rrdtool_opts']; 89 $rrdtool_extra_opts = $plugin_json[$type]['rrdtool_opts'];
90 # compatibility with plugins which specify arguments as string
91 if (is_string($rrdtool_extra_opts)) {
92 $rrdtool_extra_opts = explode(' ', $rrdtool_extra_opts);
93 }
94
95 $obj->rrdtool_opts = array_merge(
96 $obj->rrdtool_opts,
97 $rrdtool_extra_opts
98 );
90} 99}
91 100
92if (isset($plugin_json[$type]['datasize']) and $plugin_json[$type]['datasize']) 101if (isset($plugin_json[$type]['datasize']) and $plugin_json[$type]['datasize'])
diff --git a/plugin/cpu.json b/plugin/cpu.json
index 50254f8..34e021d 100644
--- a/plugin/cpu.json
+++ b/plugin/cpu.json
@@ -2,7 +2,7 @@
2 "cpu": { 2 "cpu": {
3 "title": "CPU-{{PI}} usage", 3 "title": "CPU-{{PI}} usage",
4 "vertical": "Jiffies", 4 "vertical": "Jiffies",
5 "rrdtool_opts": "-u 100", 5 "rrdtool_opts": ["-u", "100"],
6 "type": "stacked", 6 "type": "stacked",
7 "legend": { 7 "legend": {
8 "idle": { 8 "idle": {
diff --git a/type/Base.class.php b/type/Base.class.php
index 1f42f4f..72ce437 100644
--- a/type/Base.class.php
+++ b/type/Base.class.php
@@ -36,8 +36,14 @@ class Type_Base {
36 function __construct($config, $_get) { 36 function __construct($config, $_get) {
37 $this->datadir = $config['datadir']; 37 $this->datadir = $config['datadir'];
38 $this->rrdtool = $config['rrdtool']; 38 $this->rrdtool = $config['rrdtool'];
39 if (!empty($config['rrdtool_opts'])) 39 if (!empty($config['rrdtool_opts'])) {
40 $this->rrdtool_opts[] = $config['rrdtool_opts']; 40 if (is_array($config['rrdtool_opts'])) {
41 $this->rrdtool_opts = $config['rrdtool_opts'];
42 } else {
43 $this->rrdtool_opts = explode(' ',
44 $config['rrdtool_opts']);
45 }
46 }
41 $this->cache = $config['cache']; 47 $this->cache = $config['cache'];
42 $this->parse_get($_get); 48 $this->parse_get($_get);
43 $this->rrd_title = sprintf( 49 $this->rrd_title = sprintf(
@@ -200,78 +206,90 @@ class Type_Base {
200 $this->rainbow_colors(); 206 $this->rainbow_colors();
201 $this->colors = $colors + $this->colors; 207 $this->colors = $colors + $this->colors;
202 208
203 $graphdata = $this->rrd_gen_graph(); 209 $graphoptions = $this->rrd_gen_graph();
210 # $shellcmd contains escaped rrdtool arguments
211 $shellcmd = array();
212 foreach ($graphoptions as $arg)
213 $shellcmd[] = escapeshellarg($arg);
204 214
205 $style = $debug !== false ? $debug : $this->graph_type; 215 $style = $debug !== false ? $debug : $this->graph_type;
206 switch ($style) { 216 switch ($style) {
207 case 'cmd': 217 case 'cmd':
208 print '<pre>'; 218 print '<pre>';
209 foreach ($graphdata as $d) { 219 foreach ($shellcmd as $d) {
210 printf("%s \\\n", htmlentities($d)); 220 printf("%s \\\n", htmlentities($d));
211 } 221 }
212 print '</pre>'; 222 print '</pre>';
213 break; 223 break;
214 case 'canvas': 224 case 'canvas':
215 printf('<canvas id="%s" class="rrd">', sha1(serialize($graphdata))); 225 printf('<canvas id="%s" class="rrd">', sha1(serialize($graphoptions)));
216 foreach ($graphdata as $d) { 226 foreach ($graphoptions as $d) {
217 printf("%s\n", htmlentities($d)); 227 printf("\"%s\"\n", htmlentities($d));
218 } 228 }
219 print '</canvas>'; 229 print '</canvas>';
220 break; 230 break;
221 case 'debug': 231 case 'debug':
222 case 1: 232 case 1:
223 print '<pre>'; 233 print '<pre>';
224 print_r($graphdata); 234 htmlentities(print_r($shellcmd, TRUE));
225 print '</pre>'; 235 print '</pre>';
226 break; 236 break;
227 case 'svg': 237 case 'svg':
228 # caching
229 if (is_numeric($this->cache) && $this->cache > 0)
230 header("Expires: " . date(DATE_RFC822,strtotime($this->cache." seconds")));
231 header("content-type: image/svg+xml");
232 $graphdata = implode(' ', $graphdata);
233 echo `$graphdata`;
234 break;
235 case 'png': 238 case 'png':
236 default: 239 default:
237 # caching 240 # caching
238 if (is_numeric($this->cache) && $this->cache > 0) 241 if (is_numeric($this->cache) && $this->cache > 0)
239 header("Expires: " . date(DATE_RFC822,strtotime($this->cache." seconds"))); 242 header("Expires: " . date(DATE_RFC822,strtotime($this->cache." seconds")));
240 header("content-type: image/png"); 243
241 $graphdata = implode(' ', $graphdata); 244 if ($style === 'svg')
242 echo `$graphdata`; 245 header("content-type: image/svg+xml");
246 else
247 header("content-type: image/png");
248
249 $shellcmd = array_merge(
250 $this->rrd_graph_command($style),
251 $shellcmd
252 );
253 $shellcmd = implode(' ', $shellcmd);
254 passthru($shellcmd);
243 break; 255 break;
244 } 256 }
245 } 257 }
246 258
259 function rrd_graph_command($imgformat) {
260 if (!in_array($imgformat, array('png', 'svg')))
261 $imgformat = 'png';
262
263 return array(
264 $this->rrdtool,
265 'graph',
266 '-',
267 '-a', strtoupper($imgformat)
268 );
269 }
270
247 function rrd_options() { 271 function rrd_options() {
248 switch ($this->graph_type) { 272 $rrdgraph = array();
249 case 'png': 273 foreach($this->rrdtool_opts as $opt)
250 case 'hybrid': 274 $rrdgraph[] = $opt;
251 $rrdgraph[] = $this->rrdtool;
252 $rrdgraph[] = 'graph - -a PNG';
253 break;
254 case 'svg':
255 $rrdgraph[] = $this->rrdtool;
256 $rrdgraph[] = 'graph - -a SVG';
257 break;
258 default:
259 break;
260 }
261 if (!empty($this->rrdtool_opts))
262 foreach($this->rrdtool_opts as $opt)
263 $rrdgraph[] = $opt;
264 if ($this->graph_smooth) 275 if ($this->graph_smooth)
265 $rrdgraph[] = '-E'; 276 $rrdgraph[] = '-E';
266 if ($this->base) 277 if ($this->base) {
267 $rrdgraph[] = '--base '.$this->base; 278 $rrdgraph[] = '--base';
268 $rrdgraph[] = sprintf('-w %d', is_numeric($this->width) ? $this->width : 400); 279 $rrdgraph[] = $this->base;
269 $rrdgraph[] = sprintf('-h %d', is_numeric($this->height) ? $this->height : 175); 280 }
270 $rrdgraph[] = '-l 0'; 281 $rrdgraph = array_merge($rrdgraph, array(
271 $rrdgraph[] = sprintf('-t "%s on %s"', $this->rrd_title, $this->args['host']); 282 '-w', is_numeric($this->width) ? $this->width : 400,
272 if ($this->rrd_vertical) 283 '-h', is_numeric($this->height) ? $this->height : 175,
273 $rrdgraph[] = sprintf('-v "%s"', $this->rrd_vertical); 284 '-l', '0',
274 $rrdgraph[] = sprintf('-s e-%d', is_numeric($this->seconds) ? $this->seconds : 86400); 285 '-t', "{$this->rrd_title} on {$this->args['host']}"
286 ));
287 if ($this->rrd_vertical) {
288 $rrdgraph[] = '-v';
289 $rrdgraph[] = $this->rrd_vertical;
290 }
291 $rrdgraph[] = '-s';
292 $rrdgraph[] = sprintf('e-%d', is_numeric($this->seconds) ? $this->seconds : 86400);
275 293
276 return $rrdgraph; 294 return $rrdgraph;
277 } 295 }
diff --git a/type/Default.class.php b/type/Default.class.php
index 6e7efd9..4cb9ff7 100644
--- a/type/Default.class.php
+++ b/type/Default.class.php
@@ -48,11 +48,11 @@ class Type_Default extends Type_Base {
48 foreach ($sources as $source) { 48 foreach ($sources as $source) {
49 $legend = empty($this->legend[$source]) ? $source : $this->legend[$source]; 49 $legend = empty($this->legend[$source]) ? $source : $this->legend[$source];
50 $color = is_array($this->colors) ? (isset($this->colors[$source])?$this->colors[$source]:$this->colors[$c++]): $this->colors; 50 $color = is_array($this->colors) ? (isset($this->colors[$source])?$this->colors[$source]:$this->colors[$c++]): $this->colors;
51 $rrdgraph[] = sprintf('"LINE1:avg_%s#%s:%s"', crc32hex($source), $this->validate_color($color), $this->rrd_escape($legend)); 51 $rrdgraph[] = sprintf('LINE1:avg_%s#%s:%s', crc32hex($source), $this->validate_color($color), $this->rrd_escape($legend));
52 $rrdgraph[] = sprintf('"GPRINT:min_%s:MIN:%s Min,"', crc32hex($source), $this->rrd_format); 52 $rrdgraph[] = sprintf('GPRINT:min_%s:MIN:%s Min,', crc32hex($source), $this->rrd_format);
53 $rrdgraph[] = sprintf('"GPRINT:avg_%s:AVERAGE:%s Avg,"', crc32hex($source), $this->rrd_format); 53 $rrdgraph[] = sprintf('GPRINT:avg_%s:AVERAGE:%s Avg,', crc32hex($source), $this->rrd_format);
54 $rrdgraph[] = sprintf('"GPRINT:max_%s:MAX:%s Max,"', crc32hex($source), $this->rrd_format); 54 $rrdgraph[] = sprintf('GPRINT:max_%s:MAX:%s Max,', crc32hex($source), $this->rrd_format);
55 $rrdgraph[] = sprintf('"GPRINT:avg_%s:LAST:%s Last\\l"', crc32hex($source), $this->rrd_format); 55 $rrdgraph[] = sprintf('GPRINT:avg_%s:LAST:%s Last\\l', crc32hex($source), $this->rrd_format);
56 } 56 }
57 57
58 return $rrdgraph; 58 return $rrdgraph;
diff --git a/type/GenericIO.class.php b/type/GenericIO.class.php
index cab5220..20029a1 100644
--- a/type/GenericIO.class.php
+++ b/type/GenericIO.class.php
@@ -59,21 +59,21 @@ class Type_GenericIO extends Type_Base {
59 $i = 0; 59 $i = 0;
60 foreach($sources as $source) { 60 foreach($sources as $source) {
61 $legend = empty($this->legend[$source]) ? $source : $this->legend[$source]; 61 $legend = empty($this->legend[$source]) ? $source : $this->legend[$source];
62 $rrdgraph[] = sprintf('"LINE1:avg_%s%s#%s:%s"', crc32hex($source), $i == 1 ? '_neg' : '', $this->colors[$source], $this->rrd_escape($legend)); 62 $rrdgraph[] = sprintf('LINE1:avg_%s%s#%s:%s', crc32hex($source), $i == 1 ? '_neg' : '', $this->colors[$source], $this->rrd_escape($legend));
63 $rrdgraph[] = sprintf('"GPRINT:min_%s:MIN:%s Min,"', crc32hex($source), $this->rrd_format); 63 $rrdgraph[] = sprintf('GPRINT:min_%s:MIN:%s Min,', crc32hex($source), $this->rrd_format);
64 $rrdgraph[] = sprintf('"GPRINT:avg_%s:AVERAGE:%s Avg,"', crc32hex($source), $this->rrd_format); 64 $rrdgraph[] = sprintf('GPRINT:avg_%s:AVERAGE:%s Avg,', crc32hex($source), $this->rrd_format);
65 $rrdgraph[] = sprintf('"GPRINT:max_%s:MAX:%s Max,"', crc32hex($source), $this->rrd_format); 65 $rrdgraph[] = sprintf('GPRINT:max_%s:MAX:%s Max,', crc32hex($source), $this->rrd_format);
66 $rrdgraph[] = sprintf('"GPRINT:avg_%s:LAST:%s Last"', crc32hex($source), $this->rrd_format); 66 $rrdgraph[] = sprintf('GPRINT:avg_%s:LAST:%s Last', crc32hex($source), $this->rrd_format);
67 $rrdgraph[] = sprintf('"GPRINT:tot_%s:%s Total\l"',crc32hex($source), $this->rrd_format); 67 $rrdgraph[] = sprintf('GPRINT:tot_%s:%s Total\l',crc32hex($source), $this->rrd_format);
68 $i++; 68 $i++;
69 } 69 }
70 70
71 if ($this->percentile) { 71 if ($this->percentile) {
72 $rrdgraph[] = sprintf('"COMMENT: \l"'); 72 $rrdgraph[] = 'COMMENT: \l';
73 foreach($sources as $source) { 73 foreach($sources as $source) {
74 $legend = empty($this->legend[$source]) ? $source : $this->legend[$source]; 74 $legend = empty($this->legend[$source]) ? $source : $this->legend[$source];
75 $rrdgraph[] = sprintf('"HRULE:pct_%s#%s:%sth Percentile %s"', crc32hex($source), $this->get_faded_color($this->colors[$source], '000000', 0.6), $this->percentile, $this->rrd_escape($legend)); 75 $rrdgraph[] = sprintf('HRULE:pct_%s#%s:%sth Percentile %s', crc32hex($source), $this->get_faded_color($this->colors[$source], '000000', 0.6), $this->percentile, $this->rrd_escape($legend));
76 $rrdgraph[] = sprintf('"GPRINT:pct_%s:%s\l"', crc32hex($source), $this->rrd_format); 76 $rrdgraph[] = sprintf('GPRINT:pct_%s:%s\l', crc32hex($source), $this->rrd_format);
77 } 77 }
78 } 78 }
79 79
diff --git a/type/GenericStacked.class.php b/type/GenericStacked.class.php
index a74ff18..d41c2ab 100644
--- a/type/GenericStacked.class.php
+++ b/type/GenericStacked.class.php
@@ -51,11 +51,11 @@ class Type_GenericStacked extends Type_Base {
51 foreach ($sources as $source) { 51 foreach ($sources as $source) {
52 $legend = empty($this->legend[$source]) ? $source : $this->legend[$source]; 52 $legend = empty($this->legend[$source]) ? $source : $this->legend[$source];
53 $color = is_array($this->colors) ? (isset($this->colors[$source])?$this->colors[$source]:$this->colors[$c++]) : $this->colors; 53 $color = is_array($this->colors) ? (isset($this->colors[$source])?$this->colors[$source]:$this->colors[$c++]) : $this->colors;
54 $rrdgraph[] = sprintf('"LINE1:area_%s#%s:%s"', crc32hex($source), $this->validate_color($color), $this->rrd_escape($legend)); 54 $rrdgraph[] = sprintf('LINE1:area_%s#%s:%s', crc32hex($source), $this->validate_color($color), $this->rrd_escape($legend));
55 $rrdgraph[] = sprintf('"GPRINT:min_%s:MIN:%s Min,"', crc32hex($source), $this->rrd_format); 55 $rrdgraph[] = sprintf('GPRINT:min_%s:MIN:%s Min,', crc32hex($source), $this->rrd_format);
56 $rrdgraph[] = sprintf('"GPRINT:avg_%s:AVERAGE:%s Avg,"', crc32hex($source), $this->rrd_format); 56 $rrdgraph[] = sprintf('GPRINT:avg_%s:AVERAGE:%s Avg,', crc32hex($source), $this->rrd_format);
57 $rrdgraph[] = sprintf('"GPRINT:max_%s:MAX:%s Max,"', crc32hex($source), $this->rrd_format); 57 $rrdgraph[] = sprintf('GPRINT:max_%s:MAX:%s Max,', crc32hex($source), $this->rrd_format);
58 $rrdgraph[] = sprintf('"GPRINT:avg_%s:LAST:%s Last\\l"', crc32hex($source), $this->rrd_format); 58 $rrdgraph[] = sprintf('GPRINT:avg_%s:LAST:%s Last\\l', crc32hex($source), $this->rrd_format);
59 } 59 }
60 60
61 return $rrdgraph; 61 return $rrdgraph;
diff --git a/type/Uptime.class.php b/type/Uptime.class.php
index e57df0b..52af3a4 100644
--- a/type/Uptime.class.php
+++ b/type/Uptime.class.php
@@ -45,16 +45,16 @@ class Type_Uptime extends Type_Base {
45 $color = is_array($this->colors) ? (isset($this->colors[$source])?$this->colors[$source]:$this->colors[$c++]) : $this->colors; 45 $color = is_array($this->colors) ? (isset($this->colors[$source])?$this->colors[$source]:$this->colors[$c++]) : $this->colors;
46 46
47 //current value 47 //current value
48 $rrdgraph[] = sprintf('"LINE1:area_%s#%s:%s"', crc32hex($source), $this->validate_color($color), $this->rrd_escape($legend)); 48 $rrdgraph[] = sprintf('LINE1:area_%s#%s:%s', crc32hex($source), $this->validate_color($color), $this->rrd_escape($legend));
49 $rrdgraph[] = sprintf('"GPRINT:c_avg_%s:LAST:%s days\\l"', crc32hex($source), $this->rrd_format); 49 $rrdgraph[] = sprintf('GPRINT:c_avg_%s:LAST:%s days\\l', crc32hex($source), $this->rrd_format);
50 50
51 //max value 51 //max value
52 $rrdgraph[] = sprintf('"LINE1:v_max_%s#FF0000:Maximum:dashes"', crc32hex($source)); 52 $rrdgraph[] = sprintf('LINE1:v_max_%s#FF0000:Maximum:dashes', crc32hex($source));
53 $rrdgraph[] = sprintf('"GPRINT:v_max_%s:%s days\\l"', crc32hex($source), $this->rrd_format); 53 $rrdgraph[] = sprintf('GPRINT:v_max_%s:%s days\\l', crc32hex($source), $this->rrd_format);
54 54
55 //avg value 55 //avg value
56 $rrdgraph[] = sprintf('"LINE1:v_avg_%s#0000FF:Average:dashes"', crc32hex($source)); 56 $rrdgraph[] = sprintf('LINE1:v_avg_%s#0000FF:Average:dashes', crc32hex($source));
57 $rrdgraph[] = sprintf('"GPRINT:v_avg_%s:%s days\\l"', crc32hex($source), $this->rrd_format); 57 $rrdgraph[] = sprintf('GPRINT:v_avg_%s:%s days\\l', crc32hex($source), $this->rrd_format);
58 } 58 }
59 59
60 return $rrdgraph; 60 return $rrdgraph;