Commit Graph
39 Commits
Author SHA1 Message Date
Isaac ConnorandClaude Opus 5.5 0e9f82513c fix: bind the FOSCAMR2C preset and require Control permission for PTZ refs GHSA-qcm7-vq92-f86f
FOSCAMR2C presetGoto and presetSet interpolated the preset into
"SELECT Label FROM ControlPresets WHERE Preset = $preset" and sent the selected
Label to the camera as name=. For presetGoto the preset came straight from the
web request, so any user who could see the monitor could run a SELECT against
the ZoneMinder database and have the value (the auth hash secret, password
hashes) delivered to the camera link, or use it as a boolean oracle.

- FOSCAMR2C: bind the preset in every statement, refuse a preset that is not a
  number, and look ControlPresets up by MonitorId as Dahua and PSIA do.
- buildControlCommand(): refuse a non-numeric presetGoto preset, and a control
  name that is not a plain method name. zmcontrol calls the name as a method and
  the options are split back out of the command string on spaces.
- zmcontrol.pl: refuse a command that is not a plain method name, so a qualified
  Package::sub name can't call a sub outside the control module.
- canView()/canEdit() with a monitor id returned only the monitor check and
  ignored the area, so canView('Control', $mid) passed for anyone who could see
  the monitor. Require the area permission as well; Monitors stays decided by
  visibleMonitor()/editableMonitor().

tests/php/test_control_command.php covers buildControlCommand() and the
monitor-scoped canView()/canEdit(); tests/perl/test_foscamr2c_preset_sql.pl
checks the statements FOSCAMR2C prepares and what it sends to the camera.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:21:32 -04:00
Isaac ConnorandClaude Opus 5 b4599c16f2 fix: keep the control session alive while a monitor is busy, not only while idle
zmcontrol sent keepAlive only from the branch that runs when select() times
out. A monitor taking a steady stream of commands never reaches that branch,
so it never pinged at all, and cameras that expire a session on a timer
refresh it on the keepAlive rather than on ordinary requests. The monitors
with the most traffic were therefore the ones that lost their session.

Measured on monitor 1: it pinged twice while idle, then took a command every
three seconds for three minutes and the camera rejected the next one 181
seconds after the last ping. Its light commands were being dropped for as long
as the motion kept coming, which is exactly when they matter.

Move the decision into Control::keepAliveDue, timed from the last ping, and
check it at the top of the loop so the 'next' paths in the command handling
cannot skip it. A clock step backwards resets the baseline rather than holding
the ping off until real time catches up.

refs #4423

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UvTCzCbvGt8xKQRNCSA7o8
2026-09-20 18:17:43 -05:00
Steve GilvarryandClaude Opus 5 ba49bbb33c fix: make the Perl scripts' taint-safe PATH configurable
The scripts run under -T, so they cannot trust the caller's PATH and set
their own. Sixteen of them hardcoded /bin:/usr/bin:/usr/local/bin, which
assumes everything they shell out to lives under /usr or /usr/local.

ZoneMinder::General::findDbCommand looks for a database client on that
PATH, and zmupdate.pl and zmcamtool.pl run what it finds. So an install
whose client sits anywhere else cannot apply schema changes:

  sh: mysql: command not found
  Command 'mysql -u'zmuser' ... ' exited with status: 127

even with the client on the caller's PATH. Homebrew on Apple Silicon is
the case that surfaced it - the client is in /opt/homebrew/bin - but a
--prefix=/opt install on Linux has the same shape, as does anything that
keeps its database client outside the FHS locations.

Replaced the literal with @ZM_SCRIPT_PATH@, defaulting to the same three
directories plus wherever cmake actually found a client, and overridable
for packagers who want to pin it. Warn at configure time when no client
is found at all, since that failure otherwise appears much later and
says something unrelated.

Nothing changes for an install whose client is already under /usr/bin:
the directory is only appended when it is not in the list, so the
default stays exactly as it was.

Memory.pm is deliberately left alone. It has a narrower PATH of
/bin:/usr/bin, and the only command it runs is uname through an absolute
path from ZM_PATH_UNAME, so it does not need widening.

Verified on macOS across the three cases: with the client in
/opt/homebrew/bin the directory is appended; -DZM_SCRIPT_PATH= is
respected verbatim; and pointing detection at /usr/bin/mariadb leaves
the default untouched. Build clean, suite 146 cases.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B5KL9Xbi7K5aGsauLtd8tG
2026-09-13 13:04:59 +10: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
Jash 386a12a174 fix: record the lock holder pid and separate held from unopenable refs #4423 2026-08-30 03:47:14 +05:30
Jash d70fdeb0c9 fix: lock to stop a second zmcontrol server per monitor fixes #4423 2026-08-26 11:05:42 +05:30
Isaac ConnorandClaude Opus 4.8 f02bc29c0d feat: add Indicator LED control capability with session keepalive refs #4875
Add a CanIndicatorLight capability and status-aware Indicator toggle button. The indicator LED on the ASH21-B, ADC2W and ASH42-B is controlled via the LightGlobal config (configManager get/setConfig); add indicatorLightOn/Off/Status to Dahua_RPC and a model-specific 'Amcrest ASH42-B RPC' Controls row, with the capability also enabled on the ASH21-B/ADC2W/generic rows. Migration zm_update-1.39.13.sql adds the column.

Add Dahua_RPC keepAlive (global.keepAlive) wired into a 30s zmcontrol idle tick, plus session-expiry re-login retry in set_config and the status queries, so the long-running control daemon does not silently fail after the ~60s session timeout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:00:00 -04: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 ConnorandClaude Opus 4.6 a5fd6e063e feat: add --protocol mode to zmcontrol.pl for direct module testing
Add --protocol, --address, and --device CLI options that bypass the
database and socket machinery to load a control module directly and
execute a single command. This enables standalone testing of control
modules (e.g. ONVIF.pm get_config) without a running ZoneMinder
instance. Also update POD with full documentation and examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:07:49 -05:00
Isaac Connor 6423afa5aa Remove impossible code for sending a command after server startup 2026-01-06 14:59:08 -05:00
Isaac Connor a74b785d08 Move the protocol loading into the Monitor Object. 2021-10-26 18:15:43 -04:00
Isaac Connor 94634f1ca7 Spacing 2021-06-14 13:31:05 -04:00
Isaac Connor ec8e0f5997 replace while(1) with while(not zm_terminate) so that these scripts exit cleanly 2021-03-17 13:09:54 -04:00
Isaac Connor b44f14691e Don't exit after 30 minutes. Google code style. 2020-11-21 15:08:09 -05:00
Isaac Connor 271dcbc4e8 select returns EINTR when HUP'd. This is not fatal. Handling this gracefully reduces log spam 2020-11-21 09:12:41 -05:00
Isaac Connor 94fdddc1e8 Synchronize on space instead of = in zmcontrol.pl command line 2020-09-21 11:56:56 -04:00
Isaac Connor d1e7d396f7 zmcontrol needs to be able to take floats instead of integers for it's parameters 2020-06-26 16:49:55 -04:00
Isaac Connor 80c95d5afe Merge branch 'master' into wip_axisv2 2020-01-10 17:20:32 -05:00
Isaac Connor 55b1d29927 better error messages when no command is given to zmcontrol 2019-10-08 18:06:52 -04:00
Isaac Connor 766a59884d Don't hard code perl path. Use PERL_EXECUTABLE cmake var 2019-09-23 12:54:27 -04:00
Isaac Connor bc33c0bcb5 make zmcontrol log to zmcontrol_id.log 2019-09-23 12:21:59 -04:00
Isaac Connor f0a8595e50 quiet warning caused by server_up being undef for false 2019-09-20 10:36:08 -04:00
Isaac Connor 3bae7a5432 spaces and parenthesis 2019-06-20 13:28:12 -04:00
Isaac Connor aa83239069 rework zmcontrol.pl. If command is given and server is not up, use zmdc.pl to start it. Give up after 10 seconds. 2019-04-05 15:18:03 -04:00
Andrew Bauer 2bb15c4f90 daemonize zmcontrol (#2563) 2019-04-01 17:26:24 -04:00
Isaac Connor 70ba0ad342 Merge https://github.com/michaelbarkdoll/ZoneMinder into trendnet 2018-08-13 11:05:50 -04:00
Andy Bauer 254fcbcef7 update gpl 2 mailing address in source files 2016-12-26 09:23:16 -06:00
Kyle Johnson b9085cea64 Fix issue where programs are installed in unexpected paths.
For example, on freebsd, sudo is in /usr/local/bin, and as things
were pre-this commit, sudo wasn't being found.
2016-03-11 14:28:16 -07:00
Isaac Connor e4b3344a8c improve log 2015-07-15 16:06:55 -04:00
Dmitry Smirnov fba085a1c5 zmcontrol.pl: pod2usage (draft) + minor readability improvements.
Looks like "zmcontrol.pl" was based upon "zmfilter.pl" so it inherited
 commented description of the latter.
 Therefore "zmcontrol.pl" needs a description...
2015-04-11 11:15:56 +10:00
Isaac Connor 21ccb9b91a introduce the quit command which makes the resident zmcontrol.pl exit 2015-01-07 16:37:26 -05:00
Isaac Connor 78f0243c69 This replaces Module::Load with Module::Load::Conditional which can actually handle errors.
Then I move the module load call up before the fork so that any errors will be visible and will make zmcontrol.pl die quickly instead of waiting 11 seconds for something that will never happen.
2014-12-12 16:33:18 -05:00
Isaac Connor 9ce7da4147 Don't 'use Data::Dumper'; it was only there for debug 2014-10-20 16:47:03 -04:00
Kyle Johnson 07b4d83d74 Have Usage() in zmcontrol.pl exit 0 instead of -1 2014-01-02 11:50:39 -05:00
Isaac Connor 48a6dcf5ce Change COnfig from using the subroutine symbol table to just using a global hash 2013-12-16 16:32:02 -05:00
stan 88da162112 Reinitialise logs to allow database output after fork.
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@3465 e3e1d417-86f3-4887-817a-d78f3d33393f
2011-06-24 09:04:32 +00:00
stan 6ff385e407 git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@3459 e3e1d417-86f3-4887-817a-d78f3d33393f 2011-06-21 09:19:10 +00: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 11a1cc2d41 Now supports custom perl install path
git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@2908 e3e1d417-86f3-4887-817a-d78f3d33393f
2009-06-08 09:11:56 +00:00