One challenge that can crop up for Mac admins is the problem of running a script or other tool with root privileges and using it to launch and run another tool, script or application as if the logged-in user had launched it. An example of this would be installing Dropbox using an installer package, then launching the Dropbox application as the logged-in user as a post-installation task. One reason to do so would be to give the user the opportunity to sign into their Dropbox account.
To accomplish this task, Apple has provided functionality in the launchctl tool.
For 10.9.x and earlier, launchctl‘s bsexec function was used for this purpose. bsexec allows you to start a process like a tool, script or application in a specific context. One way to get the correct context for the logged-in user is to identify the process identifier (PID) for the loginwindow process associated with the logged-in user, which can be accomplished by using the command below:
ps auxww | grep "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow" | grep logged_in_username_here | grep -v "grep" | awk '{print $2}'
For example, if I logged in with an account named username, running the command shown below should provide the PID for the username account’s loginwindow process:
ps auxww | grep "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow" | grep username | grep -v "grep" | awk '{print $2}'
Once the PID has been identified, it can be used to identify the context that I want to start a process in. For example, the commands below can be run with root privileges to first identify the correct PID for the username account’s loginwindow process, then launch Safari as the username account using the open command:
ps auxww | grep "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow" | grep logged_in_username_here | grep -v "grep" | awk '{print $2}'
launchctl bsexec PID_number_here open "/Applications/Safari.app"
When we check the process list for which account is was launched from, the Safari process should show up as being run by the username account.
If you wanted to automate opening Safari as the logged-in user, you could run a script like the one below with root privileges:
Starting in OS X Yosemite, Apple made a number of changes to the launchctl tool and added a new asuser function. The asuser function is designed to take the place of the bsexec function, in the context of starting processes in the context of a specific user account. This makes it easier, as you now just need to figure out the username and do not have to figure out the PID of the user’s loginwindow process.
You can identify the user by either the user’s account name, or by the account’s UID. One way to identify an account’s UID is to use the id command as shown below:
id -u username_goes_here
To continue with the example of opening Safari, you can run the commands below to first identify the correct UID, then launch Safari as the username account using the open command:
id -u username_goes_here
launchctl asuser username_uid_goes_here open "/Applications/Safari.app"
If you wanted to automate opening Safari using the logged-in user’s UID, you could run a script like the one below with root privileges:
As mentioned earlier, you can also use just the account name with launchctl‘s asuser function. In that case, you can run the command below to launch Safari as the username account using the open command:
launchctl asuser username_goes_here open "/Applications/Safari.app"
If you wanted to automate opening Safari using the logged-in user’s account name, you could run a script like the one below with root privileges: