diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index 42a5ac3df..45c3ea774 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -126,6 +126,17 @@ class MonitorsController extends AppController { * * @return void */ + // The EventStartCommand / EventEndCommand values the request supplies, if any. + private function requestCommandFields() { + require_once __DIR__ .'/../../../includes/Monitor.php'; + $fields = array(); + foreach (ZM\Monitor::$commandFields as $field) { + $value = $this->requestField('Monitor', $field); + if ($value !== null) $fields[$field] = $value; + } + return $fields; + } + public function add() { if ( $this->request->is('post') ) { @@ -135,6 +146,12 @@ class MonitorsController extends AppController { throw new UnauthorizedException(__('Insufficient privileges')); return; } + // A new monitor's command fields start empty, so any value is a change. + require_once __DIR__ .'/../../../includes/Monitor.php'; + $new_monitor = new ZM\Monitor(); + if (count($new_monitor->commandFieldChangesNotAllowed($this->requestCommandFields()))) { + throw new UnauthorizedException(__('Setting the event commands requires System edit permission')); + } $this->pinRequestId($this->Monitor, null); $this->Monitor->create(); if ($this->Monitor->save($this->request->data) ) { @@ -178,6 +195,9 @@ class MonitorsController extends AppController { throw new UnauthorizedException(__('Insufficient Privileges')); return; } + if (count($zm_monitor->commandFieldChangesNotAllowed($this->requestCommandFields()))) { + throw new UnauthorizedException(__('Changing the event commands requires System edit permission')); + } $this->pinRequestId($this->Monitor, $id); $message = ''; diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 01c4a3945..cc12b9cb0 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -953,6 +953,25 @@ class Monitor extends ZM_Object { return $this->connKey; } + // Fields whose value zmc runs as a command. Setting one is equivalent to shell access + // on the server, so it needs System=Edit, not just edit on this monitor, the same rule + // Filter::canEdit() applies to AutoExecuteCmd. refs GHSA-vcrj-35c6-g97c + public static $commandFields = array('EventStartCommand', 'EventEndCommand'); + + // The command fields $data would change on this monitor that the user may not set. + // Submitting the current value is not a change, since the monitor form always posts it. + public function commandFieldChangesNotAllowed($data, $u=null) { + global $user; + if (!$u) $u = $user; + if (!$u or $u->System() == 'Edit') return array(); + $refused = array(); + foreach (self::$commandFields as $field) { + if (!array_key_exists($field, $data)) continue; + if ((string)$data[$field] !== (string)$this->{$field}()) $refused[] = $field; + } + return $refused; + } + function canEdit($u=null) { global $user; if ($u===null or $u->Id() == $user->Id()) diff --git a/web/includes/actions/monitor.php b/web/includes/actions/monitor.php index 93ac0dadd..c82720bee 100644 --- a/web/includes/actions/monitor.php +++ b/web/includes/actions/monitor.php @@ -153,6 +153,13 @@ if ($action == 'save') { if (!empty($newMonitor['ModelId']) and empty($newMonitor['Model'])) unset($newMonitor['Model']); + $refused = $monitor->commandFieldChangesNotAllowed($newMonitor); + if (count($refused)) { + $error_message .= 'Changing '.implode(', ', $refused).' requires System edit permission.
'; + ZM\Warning('Refused to save monitor '.$mid.': '.implode(', ', $refused).' requires System edit permission'); + return; + } + $changes = $monitor->changes($newMonitor); ZM\Debug('Changes: '. print_r($changes, true)); $restart = false; diff --git a/web/includes/actions/monitors.php b/web/includes/actions/monitors.php index b059c404d..b3c45df4c 100644 --- a/web/includes/actions/monitors.php +++ b/web/includes/actions/monitors.php @@ -33,6 +33,12 @@ if ($action == 'save') { continue; } $Monitor = new ZM\Monitor($mid); + // Before stopping it, so a refused save leaves the monitor running. + $refused = $Monitor->commandFieldChangesNotAllowed($_REQUEST['newMonitor']); + if (count($refused)) { + $error_message .= 'Changing '.implode(', ', $refused).' requires System edit permission.
'; + continue; + } if ($Monitor->Type() != 'WebSite') { $Monitor->zmcControl('stop'); } diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 75728c99c..4fcdb45bb 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -1328,14 +1328,18 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor +
  • - + />
  • - -
  • + /> +