Escape SNMP & IPMI shell commands (#9537)

hopefully doesn't break anything
Mostly issues with snmp oids and options containing spaces.  Try to remove all of those.

DO NOT DELETE THIS TEXT

#### Please note

> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.

- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)

#### Testers

If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
After you are done testing, you can remove the changes with `./scripts/github-remove`.  If there are schema changes, you can ask on discord how to revert.
This commit is contained in:
Tony Murray
2018-12-16 07:42:50 -06:00
committed by Neil Lathwood
parent e0e3e08bf6
commit fad0bffc43
152 changed files with 353 additions and 357 deletions

View File

@@ -101,23 +101,23 @@ function mibdir($mibdir = null, $device = [])
return rtrim($dir, '/');
}, $dirs)));
return " -M " . implode(':', $dirs);
return implode(':', $dirs);
}//end mibdir()
/**
* Generate an snmpget command
*
* @param array $device the we will be connecting to
* @param string $oids the oids to fetch, separated by spaces
* @param string $options extra snmp command options, usually this is output options
* @param array|string $oids the oids to fetch, separated by spaces
* @param array|string $options extra snmp command options, usually this is output options
* @param string $mib an additional mib to add to this command
* @param string $mibdir a mib directory to search for mibs, usually prepended with +
* @return string the fully assembled command, ready to run
* @return array the fully assembled command, ready to run
*/
function gen_snmpget_cmd($device, $oids, $options = null, $mib = null, $mibdir = null)
{
global $config;
$snmpcmd = $config['snmpget'];
$snmpcmd = [$config['snmpget']];
return gen_snmp_cmd($snmpcmd, $device, $oids, $options, $mib, $mibdir);
} // end gen_snmpget_cmd()
@@ -125,22 +125,22 @@ function gen_snmpget_cmd($device, $oids, $options = null, $mib = null, $mibdir =
* Generate an snmpwalk command
*
* @param array $device the we will be connecting to
* @param string $oids the oids to fetch, separated by spaces
* @param string $options extra snmp command options, usually this is output options
* @param array|string $oids the oids to fetch, separated by spaces
* @param array|string $options extra snmp command options, usually this is output options
* @param string $mib an additional mib to add to this command
* @param string $mibdir a mib directory to search for mibs, usually prepended with +
* @return string the fully assembled command, ready to run
* @return array the fully assembled command, ready to run
*/
function gen_snmpwalk_cmd($device, $oids, $options = null, $mib = null, $mibdir = null)
{
global $config;
if ($device['snmpver'] == 'v1' || (isset($device['os'], $config['os'][$device['os']]['nobulk']) && $config['os'][$device['os']]['nobulk'])) {
$snmpcmd = $config['snmpwalk'];
$snmpcmd = [$config['snmpwalk']];
} else {
$snmpcmd = $config['snmpbulkwalk'];
$snmpcmd = [$config['snmpbulkwalk']];
$max_repeaters = get_device_max_repeaters($device);
if ($max_repeaters > 0) {
$snmpcmd .= " -Cr$max_repeaters ";
$snmpcmd[] = "-Cr$max_repeaters";
}
}
return gen_snmp_cmd($snmpcmd, $device, $oids, $options, $mib, $mibdir);
@@ -149,38 +149,35 @@ function gen_snmpwalk_cmd($device, $oids, $options = null, $mib = null, $mibdir
/**
* Generate an snmp command
*
* @param string $cmd the snmp command to run, like snmpget
* @param array $cmd the snmp command to run, like snmpget plus any additional arguments in an array
* @param array $device the we will be connecting to
* @param string $oids the oids to fetch, separated by spaces
* @param string $options extra snmp command options, usually this is output options
* @param array|string $oids the oids to fetch, separated by spaces
* @param array|string $options extra snmp command options, usually this is output options
* @param string $mib an additional mib to add to this command
* @param string $mibdir a mib directory to search for mibs, usually prepended with +
* @return string the fully assembled command, ready to run
* @return array the fully assembled command, ready to run
*/
function gen_snmp_cmd($cmd, $device, $oids, $options = null, $mib = null, $mibdir = null)
{
global $debug;
// populate timeout & retries values from configuration
$timeout = prep_snmp_setting($device, 'timeout');
$retries = prep_snmp_setting($device, 'retries');
if (!isset($device['transport'])) {
$device['transport'] = 'udp';
}
$cmd .= snmp_gen_auth($device);
$cmd .= " $options";
$cmd .= $mib ? " -m $mib" : '';
$cmd .= mibdir($mibdir, $device);
$cmd .= isset($timeout) ? " -t $timeout" : '';
$cmd .= isset($retries) ? " -r $retries" : '';
$cmd .= ' '.$device['transport'].':'.$device['hostname'].':'.$device['port'];
$cmd .= " $oids";
if (!$debug) {
$cmd .= ' 2>/dev/null';
$cmd = snmp_gen_auth($device, $cmd);
$cmd = $options ? array_merge($cmd, (array)$options) : $cmd;
if ($mib) {
array_push($cmd, '-m', $mib);
}
array_push($cmd, '-M', mibdir($mibdir, $device));
if ($timeout = prep_snmp_setting($device, 'timeout')) {
array_push($cmd, '-t', $timeout);
}
if ($retries = prep_snmp_setting($device, 'retries')) {
array_push($cmd, '-r', $retries);
}
$cmd[] = $device['transport'].':'.$device['hostname'].':'.$device['port'];
$cmd = array_merge($cmd, (array)$oids);
return $cmd;
} // end gen_snmp_cmd()
@@ -189,8 +186,8 @@ function snmp_get_multi($device, $oids, $options = '-OQUs', $mib = null, $mibdir
{
$time_start = microtime(true);
if (is_array($oids)) {
$oids = implode(' ', $oids);
if (!is_array($oids)) {
$oids = explode(' ', $oids);
}
$cmd = gen_snmpget_cmd($device, $oids, $options, $mib, $mibdir);
@@ -229,8 +226,7 @@ function snmp_get_multi_oid($device, $oids, $options = '-OUQn', $mib = null, $mi
$data = [];
foreach (array_chunk($oids, $oid_limit) as $chunk) {
$partial_oids = implode(' ', $chunk);
$cmd = gen_snmpget_cmd($device, $partial_oids, $options, $mib, $mibdir);
$cmd = gen_snmpget_cmd($device, $chunk, $options, $mib, $mibdir);
$result = trim(external_exec($cmd));
if ($result) {
$data = array_merge($data, explode("\n", $result));
@@ -261,6 +257,16 @@ function snmp_get_multi_oid($device, $oids, $options = '-OUQn', $mib = null, $mi
return $array;
}//end snmp_get_multi_oid()
/**
* Simple snmpget, returns the output of the get or false if the get failed.
*
* @param array $device
* @param array|string $oid
* @param array|string $options
* @param string $mib
* @param string $mibdir
* @return bool|string
*/
function snmp_get($device, $oid, $options = null, $mib = null, $mibdir = null)
{
$time_start = microtime(true);
@@ -287,8 +293,8 @@ function snmp_get($device, $oid, $options = null, $mib = null, $mibdir = null)
* For example instead of get sysName.0, you can getnext sysName to get the .0 value.
*
* @param array $device Target device
* @param string $oid The oid to getnext
* @param string $options Options to pass to snmpgetnext (-Oqv for example)
* @param array|string $oid The oid to getnext
* @param array|string $options Options to pass to snmpgetnext (-Oqv for example)
* @param string $mib The MIB to use
* @param string $mibdir Optional mib directory to search
* @return string|false the output or false if the data could not be fetched
@@ -297,7 +303,7 @@ function snmp_getnext($device, $oid, $options = null, $mib = null, $mibdir = nul
{
$time_start = microtime(true);
$snmpcmd = Config::get('snmpgetnext', 'snmpgetnext');
$snmpcmd = [Config::get('snmpgetnext', 'snmpgetnext')];
$cmd = gen_snmp_cmd($snmpcmd, $device, $oid, $options, $mib, $mibdir);
$data = trim(external_exec($cmd), "\" \n\r");
@@ -326,10 +332,10 @@ function snmp_getnext($device, $oid, $options = null, $mib = null, $mibdir = nul
function snmp_getnext_multi($device, $oids, $options = '-OQUs', $mib = null, $mibdir = null, $array = array())
{
$time_start = microtime(true);
if (is_array($oids)) {
$oids = implode(' ', $oids);
if (!is_array($oids)) {
$oids = explode(' ', $oids);
}
$snmpcmd = Config::get('snmpgetnext', 'snmpgetnext');
$snmpcmd = [Config::get('snmpgetnext', 'snmpgetnext')];
$cmd = gen_snmp_cmd($snmpcmd, $device, $oids, $options, $mib, $mibdir);
$data = trim(external_exec($cmd), "\" \n\r");
@@ -359,9 +365,10 @@ function snmp_check($device)
$time_start = microtime(true);
$oid = '.1.3.6.1.2.1.1.2.0';
$options = '-Oqvn';
$cmd = gen_snmpget_cmd($device, $oid, $options);
exec($cmd, $data, $code);
$cmd = gen_snmpget_cmd($device, $oid, '-Oqvn');
$proc = new \Symfony\Component\Process\Process($cmd);
$proc->run();
$code = $proc->getExitCode();
d_echo("SNMP Check response code: $code".PHP_EOL);
recordSnmpStatistic('snmpget', $time_start);
@@ -398,7 +405,7 @@ function snmp_walk($device, $oid, $options = null, $mib = null, $mibdir = null)
function snmpwalk_cache_cip($device, $oid, $array = array(), $mib = 0)
{
$cmd = gen_snmpwalk_cmd($device, $oid, ' -OsnQ', $mib);
$cmd = gen_snmpwalk_cmd($device, $oid, '-OsnQ', $mib);
$data = trim(external_exec($cmd));
// echo("Caching: $oid\n");
@@ -434,7 +441,7 @@ function snmpwalk_cache_cip($device, $oid, $array = array(), $mib = 0)
function snmp_cache_ifIndex($device)
{
// FIXME: this is not yet using our own snmp_*
$cmd = gen_snmpwalk_cmd($device, 'ifIndex', ' -OQs', 'IF-MIB');
$cmd = gen_snmpwalk_cmd($device, 'ifIndex', '-OQs', 'IF-MIB');
$data = trim(external_exec($cmd));
$array = array();
@@ -668,7 +675,7 @@ function snmpwalk_group($device, $oid, $mib = '', $depth = 1, $array = array(),
function snmpwalk_cache_twopart_oid($device, $oid, $array, $mib = 0)
{
$cmd = gen_snmpwalk_cmd($device, $oid, ' -OQUs', $mib);
$cmd = gen_snmpwalk_cmd($device, $oid, '-OQUs', $mib);
$data = trim(external_exec($cmd));
foreach (explode("\n", $data) as $entry) {
@@ -690,7 +697,7 @@ function snmpwalk_cache_threepart_oid($device, $oid, $array, $mib = 0)
{
global $debug;
$cmd = gen_snmpwalk_cmd($device, $oid, ' -OQUs', $mib);
$cmd = gen_snmpwalk_cmd($device, $oid, '-OQUs', $mib);
$data = trim(external_exec($cmd));
foreach (explode("\n", $data) as $entry) {
@@ -715,7 +722,7 @@ function snmpwalk_cache_threepart_oid($device, $oid, $array, $mib = 0)
function snmp_cache_slotport_oid($oid, $device, $array, $mib = 0)
{
$cmd = gen_snmpwalk_cmd($device, $oid, ' -OQUs', $mib);
$cmd = gen_snmpwalk_cmd($device, $oid, '-OQUs', $mib);
$data = trim(external_exec($cmd));
foreach (explode("\n", $data) as $entry) {
@@ -747,7 +754,7 @@ function snmp_cache_port_oids($oids, $port, $device, $array, $mib = 0)
$string .= " $oid.$port";
}
$cmd = gen_snmpget_cmd($device, $string, ' -Ovq', $mib);
$cmd = gen_snmpget_cmd($device, $string, '-Ovq', $mib);
$data = trim(external_exec($cmd));
$x = 0;
@@ -765,47 +772,40 @@ function snmp_cache_port_oids($oids, $port, $device, $array, $mib = 0)
}//end snmp_cache_port_oids()
function snmp_gen_auth(&$device)
/**
* generate snmp auth arguments
* @param array $device
* @param array $cmd
* @return array
*/
function snmp_gen_auth(&$device, $cmd = [])
{
global $debug, $vdebug;
$cmd = '';
if ($device['snmpver'] === 'v3') {
$cmd = " -v3 -n '' -l '".$device['authlevel']."'";
array_push($cmd, '-v3', '-l', $device['authlevel']);
array_push($cmd, '-n', isset($device['context_name']) ? $device['context_name'] : '');
//add context if exist context
if (key_exists('context_name', $device)) {
$cmd = " -v3 -n '".$device['context_name']."' -l '".$device['authlevel']."'";
}
if (strtolower($device['authlevel']) === 'noauthnopriv') {
$authlevel = strtolower($device['authlevel']);
if ($authlevel === 'noauthnopriv') {
// We have to provide a username anyway (see Net-SNMP doc)
$username = !empty($device['authname']) ? $device['authname'] : 'root';
$cmd .= " -u '".$username."'";
} elseif (strtolower($device['authlevel']) === 'authnopriv') {
$cmd .= " -a '".$device['authalgo']."'";
$cmd .= " -A '".$device['authpass']."'";
$cmd .= " -u '".$device['authname']."'";
} elseif (strtolower($device['authlevel']) === 'authpriv') {
$cmd .= " -a '".$device['authalgo']."'";
$cmd .= " -A '".$device['authpass']."'";
$cmd .= " -u '".$device['authname']."'";
$cmd .= " -x '".$device['cryptoalgo']."'";
$cmd .= " -X '".$device['cryptopass']."'";
array_push($cmd, '-u', !empty($device['authname']) ? $device['authname'] : 'root');
} elseif ($authlevel === 'authnopriv') {
array_push($cmd, '-a', $device['authalgo']);
array_push($cmd, '-A', $device['authpass']);
array_push($cmd, '-u', $device['authname']);
} elseif ($authlevel === 'authpriv') {
array_push($cmd, '-a', $device['authalgo']);
array_push($cmd, '-A', $device['authpass']);
array_push($cmd, '-u', $device['authname']);
array_push($cmd, '-x', $device['cryptoalgo']);
array_push($cmd, '-X', $device['cryptopass']);
} else {
if ($debug) {
print 'DEBUG: '.$device['snmpver']." : Unsupported SNMPv3 AuthLevel (wtf have you done ?)\n";
}
d_echo('DEBUG: '.$device['snmpver']." : Unsupported SNMPv3 AuthLevel (wtf have you done ?)\n");
}
} elseif ($device['snmpver'] === 'v2c' or $device['snmpver'] === 'v1') {
$cmd = " -".$device['snmpver'];
$cmd .= " -c '".$device['community']."'";
} elseif ($device['snmpver'] === 'v2c' || $device['snmpver'] === 'v1') {
array_push($cmd, '-' . $device['snmpver'], '-c', $device['community']);
} else {
if ($debug) {
print 'DEBUG: '.$device['snmpver']." : Unsupported SNMP Version (shouldn't be possible to get here)\n";
}
}//end if
d_echo('DEBUG: '.$device['snmpver']." : Unsupported SNMP Version (shouldn't be possible to get here)\n");
}
return $cmd;
}//end snmp_gen_auth()
@@ -832,7 +832,7 @@ function snmp_mib_parse($oid, $mib, $module, $mibdir = null, $device = array())
$lastpart = end($fulloid);
$cmd = 'snmptranslate -Td -On';
$cmd .= mibdir($mibdir, $device);
$cmd .= ' -M ' . mibdir($mibdir, $device);
$cmd .= ' -m '.$module.' '.$module.'::';
$cmd .= $lastpart;
@@ -912,7 +912,7 @@ function snmp_mib_parse($oid, $mib, $module, $mibdir = null, $device = array())
function snmp_mib_walk($mib, $module, $mibdir = null, $device = array())
{
$cmd = 'snmptranslate -Ts';
$cmd .= mibdir($mibdir, $device);
$cmd .= ' -M ' . mibdir($mibdir, $device);
$cmd .= ' -m '.$module;
$result = array();
$data = preg_split('/\n+/', shell_exec($cmd));
@@ -1008,10 +1008,8 @@ function snmp_mib_translate($oid, $module, $mibdir = null, $device = array())
$oid = "$module::$oid";
}
$cmd = 'snmptranslate'.mibdir($mibdir, $device);
$cmd .= " -IR -m $module $oid";
// load all the MIBs looking for our object
$cmd .= ' 2>/dev/null';
// load all the MIBs looking for our object (-IR)
$cmd = [Config::get('snmptranslate', 'snmptranslate'), '-M', mibdir($mibdir, $device), '-IR', '-m', $module, $oid];
// ignore invalid MIBs
$lines = preg_split('/\n+/', external_exec($cmd));
if (empty($lines)) {
@@ -1042,15 +1040,13 @@ function snmp_mib_translate($oid, $module, $mibdir = null, $device = array())
* @param string $oid
* @param string $mib
* @param string $mibdir the mib directory (relative to the LibreNMS mibs directory)
* @param string $options Options to pass to snmptranslate
* @param array|string $options Options to pass to snmptranslate
* @param array $device
* @return string
*/
function snmp_translate($oid, $mib = 'ALL', $mibdir = null, $options = null, $device = array())
{
$cmd = Config::get('snmptranslate', 'snmptranslate');
$cmd .= mibdir($mibdir, $device);
$cmd .= " -m $mib";
$cmd = [Config::get('snmptranslate', 'snmptranslate'), '-M', mibdir($mibdir, $device), '-m', $mib];
if (oid_is_numeric($oid)) {
$default_options = '-Os';
@@ -1061,8 +1057,10 @@ function snmp_translate($oid, $mib = 'ALL', $mibdir = null, $options = null, $de
$default_options = '-On';
}
$options = is_null($options) ? $default_options : $options;
$cmd = array_merge($cmd, (array)$options);
$cmd[] = $oid;
return trim(external_exec("$cmd $options $oid 2>/dev/null"));
return trim(external_exec($cmd));
}