为什么 Automator 应用程序在作为 LaunchDaemon 运行时会出现权限错误?
我有 Home Assistant Core(Python 服务器)在 OSX 11.6< 上作为 LaunchDaemon 运行/code> (大苏尔)Mac Mini。我正在尝试为其构建一个插件,以直接访问连接到机器的相机。这需要 OSX 相机权限。
不幸的是,无法将任意二进制文件(例如服务器 virtualenv 中的 python)添加到相机权限;与其他权限一样,没有 +
图标。当我从终端运行代码时,我收到相机提示,它将 Terminal.app
(或 iTerm2.app 或 sshd-keygen-wrapper)添加到相机权限中,一切正常。但由于这些都不是 launchd
根进程,因此在 Home Assistant 守护进程下运行时会失败。
我发现这个问题,其接受的答案建议围绕二进制文件包装一个 Automator 应用程序:
在 Mac OSX launchd 权限问题中运行 python 脚本
我创建了该应用程序,当我使用 /usr/bin/open -a
从终端运行它时,我得到了相机权限提示和.app
已完全按照需要添加到相机权限列表中。但是,当我修改 LaunchDaemon .plist
以运行(通过 ProgramArguments
)/usr/bin/open -a /opt/homeassistant/bin/hass 时。 app
我收到此错误:
The application /opt/homeassistant/bin/hass.app cannot be opened for an unexpected reason, error=Error Domain=NSOSStatusErrorDomain Code=-10826 "kLSNoLaunchPermissionErr: User doesn't have permission to launch the app (managed networks)" UserInfo={_LSFunction=_LSLaunchWithRunningboard, _LSLine=2488, NSUnderlyingError=0x126309f40 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x12630b350 {Error Domain=OSLaunchdErrorDomain Code=125 "Domain does not support specified action" UserInfo={NSLocalizedFailureReason=Domain does not support specified action}}}}}
我验证了 hass.app
及其中的所有内容均归 LaunchDaemon 的 UserName
和 GroupName
所有, homeassistant:homeassistant
,并且其 Contents/MacOS/Automator Application Stub
具有 +x
。我尝试授予应用程序完全磁盘访问权限。我在 system.log 中没有看到任何有用的内容;只是守护进程正在崩溃循环。
我发现了有关类似权限问题的问题,其答案建议重新签名应用程序、删除隔离 xattrs 等,但这不是这里的问题,因为它从终端运行得很好。
是什么导致了此权限错误?如何解决?
I have Home Assistant Core (a Python server) running as a LaunchDaemon on an OSX 11.6
(Big Sur) Mac Mini. I am trying to build a plugin for it that directly accesses a camera attached to the machine. This requires OSX Camera permissions.
Unfortunately there is no way to add an arbitrary binary (e.g. python from the server's virtualenv) to Camera permissions; there is no +
icon as with other permissions. When I run my code from a terminal I get the camera prompt, which adds Terminal.app
(or iTerm2.app, or sshd-keygen-wrapper) to Camera permissions, and everything works. But since none of these is the launchd
root process, it fails when running under the Home Assistant daemon.
I found this question whose accepted answer suggests wrapping an Automator app around the binary:
Running python script in Mac OSX launchd permission issue
I created the app, and when I use /usr/bin/open -a
to run it from a terminal, I get the Camera permissions prompt and the .app
is added to the Camera permissions list, exactly as desired. However, when I then modify the LaunchDaemon .plist
to run (via ProgramArguments
) /usr/bin/open -a /opt/homeassistant/bin/hass.app
I get this error:
The application /opt/homeassistant/bin/hass.app cannot be opened for an unexpected reason, error=Error Domain=NSOSStatusErrorDomain Code=-10826 "kLSNoLaunchPermissionErr: User doesn't have permission to launch the app (managed networks)" UserInfo={_LSFunction=_LSLaunchWithRunningboard, _LSLine=2488, NSUnderlyingError=0x126309f40 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x12630b350 {Error Domain=OSLaunchdErrorDomain Code=125 "Domain does not support specified action" UserInfo={NSLocalizedFailureReason=Domain does not support specified action}}}}}
I verified that hass.app
and everything within it is owned by the LaunchDaemon's UserName
and GroupName
, homeassistant:homeassistant
, and that its Contents/MacOS/Automator Application Stub
has +x
. I tried giving the app Full Disk Access. I don't see anything useful in the system.log; just that the daemon is crash-looping.
I found questions about similar permissions issues whose answers suggested re-signing the app, removing quarantine xattrs, etc. but that's not the issue here, since it runs just fine from the terminal.
What is causing this permissions error, and how can I resolve it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
虽然这可能不是您想听到的答案,但看来通过 LaunchDaemon 访问相机实际上不再可能了,至少根据 Apple 员工“eskimo”在 Apple 自己的开发者论坛上给出的答案:
请注意,由于我不确切知道 Apple 如何禁止相机访问,因此仍然可以通过 LaunchDaemon 中的外部框架运行外部相机 - 上面的帖子是响应访问内部摄像头。
我担心您可能不会在这里得到更好的答案,至少没有一些可以使用的示例(即该社区可以尝试重现您的错误的一些代码)。
While this probably isn't the answer you wanted to hear, it appears that accessing the camera through a LaunchDaemon is actually not possible anymore, at least according to this answer given by Apple staff member "eskimo" over at Apple's own developer forums:
Note that since I don't know precisely how Apple is prohibiting camera access, it might still be possible to run external cameras through external frameworks within a LaunchDaemon - the post above is in repsonse to accessing the internal camera.
I fear you'll likely not get a better answer here, at least without some example to work with (i.e. some code this community could try to reproduce your error with).
现在有些旧且不再更新技术说明 TN2083 守护进程代理人声明:
这与 Asmus 在 Apple 自己的开发者论坛中关于对非守护程序安全框架的支持的有趣发现相符。
适当命名的部分
特别是以下言论非常具有启发性:
它还说:
根据具体要求,使用 LaunchAgent 可能是一种替代方案。当然,缺点是只有当用户登录到图形会话时才会调用 LaunchAgents。大家可以通过下面的小例子自行测试一下,访问摄像头是没有问题的,正如预期的那样。
启动代理
一个没有故事板的小型独立示例的实验,甚至除了 AVFoundation 之外还使用 AppKit(用于图像转换),并将照片保存为 .png,可能如下所示:
相机。 swift
AppDelegate.swift
main.swift:
除了
com.apple.security.device.camera
权限之外,LSUIElement
中Info.plist
设置为true
并添加了一个NSCameraUsageDescription
键并添加了文本。这当然不是一个有效适用的通用解决方案,但至少应该允许以较低的总体复杂性进行实验。
com.software7.camera.plist in ~/Library/LaunchAgents:
这里应用程序每 30 秒触发一次:
假设目标用户的
id -u
为 503,则设置完成:并且可以通过
拆分为守护进程和代理组件
再次删除如果您编写这样的LaunchAgent,您可以将其链接到任何框架,如上面的示例所示应用程序套件。
还有一个
一些测试
我不会将以下内容视为证据,而是强烈表明使用 AppKit 的应用程序应该不能按照 Apple 的建议用于 LaunchDemons:
使用 4 个变体运行测试,所有变体在调用时都会向名为
/tmp/daemonlog.txt
的同一日志文件写入一个条目,然后exit:在
/Library/LaunchDaemons
中,变体设置为启动间隔在 25 到 35 秒之间。观察:
只要用户登录,所有 4 个变体就会根据指定的开始间隔定期写出消息。用户注销后,应继续创建日志条目。但是,只有不使用 AppKit 的变体 2) 和 3) 才会执行此操作。变体 1) 和 4) 不再起作用。在活动监视器中,您可以看到两个应用程序都挂起,但实际上它们被编程为在写入日志输出后立即退出。当两个应用程序都手动终止时,它们会再次开始正常工作,但前提是用户保持登录状态。
这可以通过日志文件中的黄色突出显示区域(=用户已注销)轻松看出:
测试源代码
Writer.swift
Writer.swift
由 1) 和 2) 使用:AppDelegate.swift
案例 1 中的应用程序使用一个AppDelegate。使用此 AppDelegate 的相应 main.swift 看起来像上面所示的,这里不再重复:
main.swift
没有 AppKit 的应用程序是情况 2,看起来像这样:
daemonscript.sh< /strong>
对于情况 3,
daemonscript.sh
由launchd
直接调用。Automator 配置
在 Automator 中,使用
Run Shell Script
操作,如下所示:The now somewhat older and no longer updated Technical Note TN2083 Daemons and Agents states:
Which lines up with Asmus' interesting find from Apple's own developer forums regarding support for non-daemon-safe frameworks.
The appropriately named section Living Dangerously also describes that when using frameworks that are not daemon-safe, it is entirely possible that certain things may or may not work to some degree.
In particular, the following statements are very revealing:
Also it says:
Depending on the exact requirements, using a LaunchAgent might be an alternative. The downside, of course, is that LaunchAgents are only invoked when the user logs into a graphical session. As one can test for oneself in the following small example, accessing the camera is no problem, as expected.
Launch Agent
An experiment with a small, self-contained example without a storyboard, even using AppKit (for image conversion) in addition to AVFoundation, and taking and saving a photo as a .png, might look like this:
Camera.swift
AppDelegate.swift
main.swift:
In addition to the
com.apple.security.device.camera
permission,LSUIElement
inInfo.plist
is set totrue
and aNSCameraUsageDescription
key with text added.This is certainly not a productively applicable generic solution, but should at least allow experiments with lower overall complexity.
com.software7.camera.plist in ~/Library/LaunchAgents:
Here the app is triggered every 30 seconds:
Assuming
id -u
for the target user is 503, the setup is done with:and could be removed again with
Splitting into Daemon and Agent component
If you write such a LaunchAgent, you can link it to any framework, as shown in the example above with AppKit.
There is also a good suggestion in Apple's Technical Note that it is possible to split the code if it is not possible to do without a daemon completely. Apple writes about this:
Some Tests
I would not consider the following as proof, rather as a strong indication that applications using AppKit should not be used for LaunchDemons as recommended by Apple:
A test was run with 4 variants, all of which write an entry to the same log file named
/tmp/daemonlog.txt
when they are called, and then exit:In
/Library/LaunchDaemons
the variants were set up with startup intervals between 25 and 35 seconds.Observation:
As long as the user is logged in, all 4 variants write out their messages periodically according to their specified start interval. As soon as the user logs out, the log entries should continue to be created. However, only variants 2) and 3), which do not use AppKit, do this. Variants 1) and 4) no longer work. In the Activity Monitor you can see that both applications are hanging, but actually they are programmed to quit immediately after writing the log output. When both applications are terminated manually, they start working normally again, but only as long as the user remains logged in.
This can be easily seen by the yellow highlighted area (=user logged out) in the log file:
Test Source Codes
Writer.swift
Writer.swift
is used by 1) and 2):AppDelegate.swift
The application in case 1 uses an AppDelegate. The corresponding main.swift that uses this AppDelegate looks like the one shown above and is not repeated here:
main.swift
The application without AppKit is case 2 and looks like this:
daemonscript.sh
For case 3
daemonscript.sh
is called directly bylaunchd
.Automator Config
In Automator, a
Run Shell Script
action is used, which looks like this: