如何在另一个用户的图形会话中启动GUI应用程序?


15

我试图弄清楚如何在该用户的图形会话中以交互登录的另一个用户身份启动GUI应用程序。

例如,假设我有两个用户,即foo和bar。两者都已登录,但是当前的交互式用户是foo。我想以“ bar”用户身份启动Calculator.app,以便当我快速将用户切换到bar时,我发现bar会话中的Calculator窗口处于打开状态。

这是我尝试过的不起作用的方法:

sudo -u bar /Applications/Calculator.app/Contents/MacOS/Calculator

这将以栏形式启动Calculator.app,但该窗口在foo的图形会话中打开。

sudo -u bar osascript -e "tell application \"Calculator\" to activate"

效果一样。

sudo -u bar open "/Applications/Calculator.app"

以foo(而不是bar)启动Calculator。

launchctl asuser [uid of bar] [any of the above commands]

效果一样。

有什么办法可以做到这一点?我愿意招待所有可能的解决方案,包括bash脚本编写,AppleScript,编写Core Foundation或Cocoa程序等等。在我的情况下,任何程序或脚本都可以以任何用户身份执行,包括root用户。

注意:我知道可以使用远程Apple Events,但是我不能使用它,因为在这种情况下,我无法保证在“共享”首选项中将启用“远程Apple Events”。

任何帮助将不胜感激!


1
您是否尝试过open使用命令SSH
Matthieu Riegler

奇怪的是,应用程序的停靠图标出现在foo的会话中,而应用程序窗口却出现在bar的会话中。所以这似乎不起作用,但很好的建议。不幸的是,不能保证在我需要安装程序的情况下启用安全登录。
GuyGizmo

我认为这一难题可能涉及-psn命令行参数,操作系统在某些情况下会添加该参数。过去在将一些代码移植到OS X时遇到过这种情况。请参阅此问题及其引用的Apple文档。
阿什利2013年

终于从10.10开始,下面提到的bsexec可以完美运行
Hofi

Answers:


7

您想要实现的目标是可能的,但很难。您需要在适当的用户会话中启动应用程序。出于安全原因,很难跨越用户会话划分。

您需要一个已在其他用户会话中运行的进程来侦听您的请求并代表您启动该应用程序。

推出的bsexec

值得庆幸的是,最新版本的launchd具备此功能;尽管Apple工程师不建议使用它。使用launchctl中bsexec选项定位适当的用户会话:

 bslist [PID | ..] [-j]
          This prints out Mach bootstrap services and their respective states. While the namespace
          appears flat, it is in fact hierarchical, thus allowing for certain services to be only avail-
          able to a subset of processes. The three states a service can be in are active ("A"), inactive
          ("I") and on-demand ("D").

          If [PID] is specified, print the Mach bootstrap services available to that PID. If [..] is
          specified, print the Mach bootstrap services available in the parent of the current bootstrap.
          Note that in Mac OS X v10.6, the per-user Mach bootstrap namespace is flat, so you will only
          see a different set of services in a per-user bootstrap if you are in an explicitly-created
          bootstrap subset.

          If [-j] is specified, each service name will be followed by the name of the job which regis-
          tered it.

 bsexec PID command [args]
          This executes the given command in the same Mach bootstrap namespace hierachy as the given
          PID.

 bstree [-j]
          This prints a hierarchical view of the entire Mach bootstrap tree. If [-j] is specified, each
          service name will be followed by the name of the job which registered it.  Requires root priv-
          ileges.

推荐的方法是编写启动的作业凭单,然后重新启动Mac-或要求用户注销并再次登录。

问题原因

问题源于应用程序连接到错误的WindowServer进程。每个用户会话都有一个单独的WindowServer。此过程处理用户界面。您以前的方法将进程的所有权分配给正确的用户,但连接到您自己的WindowServer进程。

Apple 的“ 守护程序和代理”技术说明中提到了此问题。

经验

我从个人经验中知道这一点。对于Power Manager,我将pmuser编写为存在于每个用户会话中。pmuser侦听我们的守护程序并处理每个用户的启动和命令。尽管我们的守护程序具有root权限,但是我们仍然需要每个用户的进程才能在用户会话中可靠地工作。


您能否提供一个简单的脚本,例如在TJ的回答中,但可以使用吗?还是对于这样的事情来说太复杂了?
cregox

对于简短的脚本,正确的解决方案过于复杂。理想情况下,目标用户会话中需要单独的类似蹦床的过程。这是我们对于电源管理器必须执行的操作:dssw.co.uk/powermanager您希望实现什么?
Graham Miln 2014年

希望实现标题中的确切说明:在另一个用户的会话中启动gui应用程序。如果不需要其他用户登录或可以通过编程方式登录,则为“奖励积分”。具体来说,我要多个Google驱动器。如果我只是手动登录,并且在该用户在“系统偏好设置”上的“ 登录项”下,它就会起作用。蹦床程序不会带来加分,但是如果那是唯一的方法,那么苹果工程师对此有何建议?我认为这正是做这样简单的黑客脚本的原因!:P
cregox

@Cawas请作为一个新问题提出,并着眼于想要多个Google云端硬盘的目标,而不是如何实现。重点的改变将有助于该问题不会被标记为重复。
Graham Miln 2014年

足够公平和完成
cregox

7

由于系统集成保护(SIP)关闭了端口,bsexec都无法回答上述关于El Capitan(10.11)的工作。“ launchctl asuser”有效,但需要以root身份运行。以下命令可在El Capitan(和最新的OS-es)上使用:

sudo launchctl asuser 501 open /Applications/Calculator.app

注意501是我的其他用户的用户ID。


这是我的结果:bruno.medeiros@brunojcm-macbook:~ $ sudo launchctl asuser 501 open /Applications/Firefox.app,并得到LSOpenURLsWithRole() failed with error -600 for the file /Applications/Firefox.app
BrunoJCM '16

@BrunoJCM您确定要使用501的用户的用户ID代码吗?如果该命令类似于:则更加清楚sudo launchctl asuser $(id -u <user_id_name>) <app>。就是说,posix_spawn(): 13: Permission denied即使我使用与登录(并拥有该会话)所用的用户ID相同的ID运行,也会收到不同的错误sudo launchctl asuser $(id -u mtylutki) /Applications/Calculator.app
-Marcus

2

最后,10.10提供了正确的“ launchctl bsexec”实现,您可以使用:

sudo /bin/launchctl bsexec PID chroot -u UID -g GID / open /Applications/TextWrangler.app

男人说

这将在尽可能类似于目标PID的执行上下文中执行给定命令。

因此,作为PID参数,您可以使用适当的loginwindow进程的pid 。UID是该登录窗口拥有的用户的用户ID,而GID是其主要组。

这适用于任何命令,当然也适用于已启动的作业(例如feetagent),例如:

/bin/launchctl bsexec 104 chroot -u 501 -g 20 / /bin/launchctl load -S Aqua /Library/LaunchAgents/com.youragent.plist 2>&1

不知道这对其他人是否正确,但是task_for_pid(): 0x5现在我得到了一个错误,在此我已经验证了PID是正确的。
Marcus

1

您可以将Finder用作获得正确权限的主机osascript -e "tell application \"Finder\" to open (\"${app}\" as POSIX file as alias)"。这样,它将通过启动GUI的任何Finder启动。


0

这通过ssh起作用:

#!/bin/bash

PID=$(ps auxwww | egrep "^bar" |\
fgrep /System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow |\
awk '{print $2}')

sudo launchctl bsexec "$PID" open -a TextEdit

但是如果通过Terminal.app尝试,则它将在当前用户的GUI中打开TextEdit。

如果不确定是否ssh已启用,则可以暂时启用它

sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist

并在必要时再次禁用它?

否则我很沮丧。

在10.9上测试。


它确实按照您所说的打开了应用程序,但是它在当前用户会话中打开了它,而不是在其他用户会话中打开了它。
cregox 2014年

-1

简单

须藤su name_of_user

然后正常执行命令。


这些命令将由运行bar,但仍将在foo的图形会话中运行。
约翰N

抱歉,是的,我对此问题感到困惑,无法在foo图形会话上执行。
PandB Software
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.