15

I'm trying to figure out how to launch a GUI application as another user that's logged in interactively, in that user's graphical session.

For example, say I have two users, foo and bar. Both are logged in, but the current interactive user is foo. I'd like to launch Calculator.app as user "bar", so that when I fast user switch to bar, I find the Calculator window is open in bar's session.

Here's what I've tried that doesn't work:

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

This launches Calculator.app as bar, but the window opens in foo's graphical session.

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

Same effect.

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

Launches Calculator as foo, not bar.

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

Same effect.

Is there any way to accomplish this? I'm willing to entertain all manner of possible solutions, including bash scripting, AppleScript, writing a Core Foundation or Cocoa program, and so on. In my situation, any program or script could execute as any user, including root.

Note: I'm aware that it's possible using remote Apple Events, but I can't use that since in the situation I'm trying to do this I have no guarantee that "Remote Apple Events" will be enabled in Sharing preferences.

Any help would be greatly appreciated!

  • 1
    Did you try the open command, using SSH ? – Matthieu Riegler Sep 3 '13 at 22:55
  • Oddly enough, the app's dock icon appears in foo's session, but the app window appears in bar's. So that doesn't seem to work, but good suggestion. Unfortunately, there's no guarantee that secure login is enabled in the situation I need this, which is for an installer. – GuyGizmo Sep 4 '13 at 3:04
  • I think one piece of this puzzle might involve the -psn command line argument, which the OS adds in some situations. I've encountered this in the past when working on porting some code to OS X. See this question and the Apple documentation it references. – Ashley Sep 5 '13 at 23:09
  • as of 10.10 at last the bellow mentioned bsexec works perfectly – Hofi May 11 '15 at 21:29
7

What you want to achieve is possible but difficult. You need to launch the application within the appropriate user session. For security reasons, crossing the user session divide is difficult.

You need a process already running in the other user's session to listen to your request and launch the application on your behalf.

launchd's bsexec

Thankfully, recent versions of launchd have this ability; although Apple engineers have not recommended its general use. Use the bsexec option in launchctl to target the appropriate user session:

 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.

The recommended approach is to write a launchd job ticket and restart the Mac - or ask the user to log-out and back in again.

Cause of the Problems

The problems stem from the application being connected to the wrong WindowServer process. Each user session has a separate WindowServer; this process handles the user interface. Your earlier methods place the ownership of the process with the right user but connected to your own WindowServer process.

This problem is mentioned in the Daemons and Agents technical note from Apple.

Experience

I know this from personal experience. For Power Manager, I wrote pmuser to exist within each user session. pmuser listens to our daemon and handles the per-user launches and commands. Despite our daemon having root authority, we still needed a per-user process to work reliably within user sessions.

  • Could you provide a simple script, such as in TJ's answer there, but one that works? Or is it just too complex for such a thing? – cregox Jun 19 '14 at 22:40
  • The correct solution is too complex for a short script. Ideally, a separate trampoline-like process is required in the target user session. This is what we had to do for Power Manager: dssw.co.uk/powermanager What are you hoping to achieve? – Graham Miln Jun 20 '14 at 6:08
  • Hoping to achieve exactly what says in the title: launch a gui application in another user's session. "Bonus points" if the other user doesn't need to be logged in or if it can be logged in programmatically. In specific, I want multiple google drive. It works if I simply log in manually and it's under that user's Login Items on System Preferences. A trampoline process wouldn't bring the bonus points, but if that's the only way, what is precisely the Apple engineers recommendation against it? I thought it would be precisely for doing such simple hack scripts! :P – cregox Jun 20 '14 at 10:54
  • @Cawas please ask this as a new question and focus on the goal of wanting multiple Google Drives, rather than how it might be achieved. The change in focus will help the question not be marked as a duplicate. – Graham Miln Jun 20 '14 at 11:23
  • Fair enough and done. – cregox Jun 30 '14 at 21:02
6

None of the bsexec answers above work on El Capitan (10.11), due to System Integration Protection (SIP) closing the ports. "launchctl asuser" works, but requires to be run as root. The command below works on El Capitan (and most recent OS-es):

sudo launchctl asuser 501 open /Applications/Calculator.app

Note that 501 is the userid for my other user.

  • This is my result: bruno.medeiros@brunojcm-macbook:~ $ sudo launchctl asuser 501 open /Applications/Firefox.app, and got LSOpenURLsWithRole() failed with error -600 for the file /Applications/Firefox.app – BrunoJCM Oct 17 '16 at 20:07
2

As finally 10.10 provides a correct "launchctl bsexec" implementation yo can use:

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

man says

This executes the given command in as similar an execution context as possible to the target PID.

So as PID param you can use the pid of the appropriate loginwindow process. The UID is the user id of the user owns that loginwindow and the GID is it's primary group.

This works fine for any command and of course for launchd jobs (f.e. launchagents) also at last like:

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

This works via 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

but if try it via Terminal.app, then it opens TextEdit in the current user's GUI.

If you aren't sure that ssh is enabled, perhaps you can temporarily enable it

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

and disable it again afterwards if necessary?

Otherwise I'm stumped.

Tested on 10.9.

  • It does open the application as you say, but it opens it in the current user session, and not in the other user's session as asked. – cregox Jun 12 '14 at 18:44
-1

Simple

sudo su name_of_user

then execute commands normally.

  • The commands would be run by bar, but would still run in foo's graphical session. – John N Feb 11 '17 at 21:17
  • Sorry, yes im confuse about the question, is not execute on foo graphical session. – PandB Software Feb 12 '17 at 0:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .