> /var/log/mine.log', '/usr/local/bin/backup.sh', true, 'redirection is not chaining'), // Spelling. array(' /usr/local/bin/backup.sh ', '/usr/local/bin/backup.sh', true, 'surrounding whitespace does not change the program'), array('"/usr/local/bin/my script.sh"', '/usr/local/bin/my script.sh', true, 'a quoted path is the same program'), array('/usr/bin/zmaudit.pl', ' /usr/local/bin/backup.sh , /usr/bin/zmaudit.pl ', true, 'whitespace around list entries is ignored'), // Nothing to run. array('', '/usr/local/bin/backup.sh', false, 'an empty command is not on any list'), array(' ', '/usr/local/bin/backup.sh', false, 'nor is whitespace'), // A leading environment assignment is not the listed program, and is // refused rather than looked past. array('FOO=1 /usr/local/bin/backup.sh', '/usr/local/bin/backup.sh', false, 'a leading assignment is not the program'), ); echo "the rule, in PHP\n"; foreach ($cases as $case) { list($command, $allowed, $want, $label) = $case; check($label, commandIsAllowed($command, $allowed), $want); } echo "picking the program out of a command\n"; check('a bare path', commandProgram('/bin/true'), '/bin/true'); check('with arguments', commandProgram('/bin/echo hello world'), '/bin/echo'); check('quotes are not part of the name', commandProgram('"/bin/my prog"'), '/bin/my prog'); check('nothing to pick', commandProgram(' '), null); check('not a string', commandProgram(null), null); echo "the same rule, in Perl\n"; // ZoneMinder::General is where zmfilter.pl gets it. Driven as a subprocess // because that is the only honest way to ask the other implementation. $lib = escapeshellarg(__DIR__.'/../../scripts/ZoneMinder/lib'); $disagreements = array(); $perl_ran = 0; foreach ($cases as $case) { list($command, $allowed, $want, $label) = $case; $script = 'use ZoneMinder::General qw(:all); '. 'print commandIsAllowed($ARGV[0], $ARGV[1]) ? "1" : "0";'; $cmd = 'perl -I'.$lib.' -e '.escapeshellarg($script).' '. escapeshellarg($command).' '.escapeshellarg($allowed).' 2>/dev/null'; $out = shell_exec($cmd); if ($out === null or $out === '') { $disagreements[] = "$label: perl produced no answer"; continue; } $perl_ran++; $perl = (trim($out) === '1'); if ($perl !== $want) $disagreements[] = "$label: perl said ".($perl?'allowed':'refused'); } check('perl answered every case', $perl_ran, count($cases)); check('perl and php agree on every case', $disagreements, array()); echo "the two chaining lists are the same list\n"; // Read out of the Perl source rather than restated here, since a copy in the // test would drift just as happily as the implementations would. $general = file_get_contents(__DIR__.'/../../scripts/ZoneMinder/lib/ZoneMinder/General.pm'); preg_match('/our \@COMMAND_CHAINING = \((.*?)\);/s', $general, $m); $perl_chaining = array(); if (isset($m[1])) { preg_match_all("/'((?:[^'\\\\]|\\\\.)*)'/", $m[1], $entries); $perl_chaining = $entries[1]; } check('perl declares a chaining list', count($perl_chaining) > 0, true); check('and it matches the php one', $perl_chaining, ZM_COMMAND_CHAINING); echo "\n$passed passed, $failed failed\n"; exit($failed ? 1 : 0);