Commit Graph
17 Commits
Author SHA1 Message Date
Isaac ConnorandClaude Opus 4.8 20e7d68d05 fix: harden remote control request forwarding refs #5343
Follow-up hardening to the multi-server control forwarding added in
#5343:

- remoteControlUrl() now forwards an allowlist of known control
  parameters (id, control, xge, yge, x, y, scale, preset, newLabel,
  action, aid, response) instead of passing everything that is not on a
  denylist, so no stray key or cookie-folded value reaches the other
  server.
- forwardControlRequest() sets a 15s timeout so an unreachable recording
  server can't hang an interactive control click for default_socket_timeout,
  and, with ignore_errors, treats a non-2xx response (e.g. an auth-relay
  login redirect's HTML) as a failure.
- relayControlReply() refuses to pass a non-JSON body back to the browser
  under a JSON content-type.

Extends the test to assert unknown parameters are not forwarded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-25 09:59:36 -04:00
Nic BoetandClaude Opus 5.5 99cf213f62 fix: forward control requests to the server that records the monitor
In a multi-server setup a PTZ move, preset or light command sent to one
server for a monitor that another server records never reached the
camera. Monitor::sendControlCommand() passed the zmcontrol option string
to the other server's monitors/daemonControl API, which only starts and
stops zmcontrol.pl, so the request built a URL like
daemonControl/4/ --panspeed=51 ... --command=moveConLeft/zmcontrol.pl.json
and answered "Failed". The web UI's own PTZ buttons send to the
monitor's server and were not affected; clients that send every request
to the server they log in to (zm-py, pyzmNg, zmNinjaNg, aiozoneminder)
and monitor actions whose target is on another server were.

ajax/control.php now hands such a request, as received, to the index.php
of the server that records the monitor (or the action's target), with
the auth relay in place of the caller's credentials, and answers with
that server's reply. That server checks the permissions and builds the
command itself. A request is forwarded at most once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:24:29 -05:00
Isaac ConnorandClaude Opus 5.5 c3d2e542bc fix: never build an object from an id the request sent as an array
ZM_Object's constructor treats an array as the object's row, and validInt()
and validCardinal() returned an array as they got it (preg_replace() does).
So wherever a request id reached `new ZM\X(...)`, raw or through those
validators, a crafted array built an object whose Id, UserId or MonitorId
the sender chose. The permission check then looked at those, and the delete
or update that followed used the Id. A user with Events=View deleted another
user's filter by posting Id[Id]=<filter>&Id[UserId]=<self> to the filter
delete action; the same shape reached events (MonitorId), users, reports,
snapshots and storage.

validInt() and validCardinal() now give '' for anything that isn't a single
value. The places that built an object from a raw $_REQUEST value (the
control and event ajax handlers, the event, filter, report, snapshot and
storage actions, view_hls, and the download and event detail modals) take
the id through validCardinal().

tests/php/test_request_ids_scalar.php covers the validators with arrays and
fails if web code builds an object straight from $_REQUEST, $_GET or $_POST.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:07:08 -04:00
Isaac Connor eafdffcd95 feat: add per-monitor actions that drive a light or a speaker on alarm
A camera that detects motion should be able to sound a speaker, and the
speaker is rarely the camera: it is a separate device with its own address,
credentials, stream and Controls entry. Model it as a monitor and let a
monitor's alarm drive actions on other monitors.

Add Monitors.DeviceClass enum('Camera','Speaker'). This is what the device
is, as distinct from Type, which selects the capture backend - an IP speaker
still captures over Ffmpeg like any other RTSP device, so Type could not
carry the distinction.

Add the MonitorActions table: MonitorId is the monitor that triggers,
TargetMonitorId the device acted on, and the two are frequently different.
TriggerOn covers EventStart, EventEnd, Alarm and Manual.

Which actions a device is offered is decided by its Controls row - CanLight,
CanIndicatorLight, CanAudioPlay - so a device can only be asked to do what it
has been measured to do. The editor filters on this and the save path
re-checks it, because the request is not to be trusted.

Execution goes straight to the target's zmcontrol socket rather than forking
zmcontrol.pl per action: the daemon already accepts a line of JSON there, and
it is the same path the control panel uses. ActionCommandName maps the DB
enum onto a method name as a whitelist, so nothing out of the database
reaches the control daemon uninspected. Actions are fire-and-forget - a
speaker that is offline is logged and skipped, never allowed to hold up event
handling.

Alarm actions fire only on the genuine entry into alarm, not on the
ALERT->ALARM re-entry, which would re-sound a speaker within one incident.
EventEnd runs on the calling thread before the event is handed to the closing
thread, which does not capture `this`.

Manual actions appear as buttons on the watch page, and are the reason the
control panel is now shown for a monitor that has actions but no control of
its own. Firing one sends only the action id; the command and target are
rebuilt server side, and Control rights are required on the target device and
not merely on the monitor the action hangs off.

Also add --file to zmcontrol.pl, without which audioPlay could not be driven
from the command line. The web path was unaffected as it bypasses GetOptions.

Tests: tests/zm_monitor_action.cpp covers the command whitelist, the message
format (including that file id 0 is a real id and that a stale AudioFile is
never passed to a command that takes none), trigger names, and that every
value of the ActionType enum maps to a command.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UvTCzCbvGt8xKQRNCSA7o8
(cherry picked from commit b561341e988af69c3a46db854da410309f7cfa82)
2026-09-11 20:13:02 -05:00
Isaac ConnorandClaude Opus 4.8 fd83672a11 feat: add status-aware Light control capability and control-command response path refs #4869
Add a CanLight control capability rendering a single status-aware Light toggle button. The ADC2W white light is driven via CoaxialControlIO.control (Type 1, numeric IO); the button queries live state and reflects it (amber when on).

To get device state to the browser, add an opt-in two-way response path to the control protocol: zmcontrol writes a JSON result back only when a request sets wants_response (fire-and-forget commands unchanged, SIGPIPE-safe); Monitor::sendControlCommandWithResponse and ajax/control.php return it.

Also adds get_config/set_config/probe to Dahua_RPC for characterising cameras, the CanLight column (migration zm_update-1.39.12.sql), edit-UI checkbox, and a config unit test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:00:00 -04:00
Isaac Connor 4126554092 Move sendControlCommand out of includes/control_functions.php into Monitor.php. Make it smarted about talking to zmcontrol.pl. Fix sending the quit command 2019-10-08 18:07:33 -04:00
Isaac Connor 481f5b7eac Update control ajax 2019-09-20 10:36:38 -04:00
Isaac Connor 8dd8888975 Php namespace (#2537)
* experiment with namespaces on the Server class

* experiment with namespaces on the Server class

* Implement the ZM namespace on objects

* Implement the ZM namespace on objects

* Implement the ZM namespace on objects
2019-02-22 09:19:07 -05:00
Isaac Connor 6d34f8f424 Use Monitor class instead of old sql 2015-12-09 09:23:42 -05:00
Isaac Connor ceca805b48 more updates 2013-12-17 11:07:19 -05:00
stan 7b43ac2645 Use JSON encoding for language independent serialisation (filters and control commands) rather than PHP serialisation. Removes dependency on rare PHP::Serialization perl module.
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@3357 e3e1d417-86f3-4887-817a-d78f3d33393f
2011-05-23 16:18:18 +00:00
stan 173de6debf Replaced deprecated split function call
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@3276 e3e1d417-86f3-4887-817a-d78f3d33393f
2011-02-06 15:28:25 +00:00
stan 93b955813f Further PTZ preset tweaks
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@2958 e3e1d417-86f3-4887-817a-d78f3d33393f
2009-09-28 14:16:17 +00:00
stan c5a0f98309 Factored out action and request control functionality. Added presets to mobile view for PTZ cams.
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@2956 e3e1d417-86f3-4887-817a-d78f3d33393f
2009-09-28 13:34:10 +00:00
stan 81fd3aaa41 Restructured ajax to be consistent.
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@2668 e3e1d417-86f3-4887-817a-d78f3d33393f
2008-10-16 16:12:23 +00:00
stan ef8f7b85fd Continuing development and bugfixes
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@2632 e3e1d417-86f3-4887-817a-d78f3d33393f
2008-09-26 09:47:20 +00:00
stan 2824cb7355 git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@2508 e3e1d417-86f3-4887-817a-d78f3d33393f 2008-07-14 13:54:50 +00:00