On Dec 4, 2007, at 7:39 PM, Jeremy Reichman wrote:
This may be something of a "duh" but I'm curious if it is intentional and immutable that per-user LaunchAgents, such as those a sys admin might want to stuff into /Library/LaunchAgents, ignore the "UserName" key.
Yes, it's intentional. LaunchAgents are executed by the per-user launchd. As a non-root process, it does not have the privilege to setuid(2) to another user, hence the UserName key is ignored.
In launchd.plist's man page:
"UserName <string> This optional key specifies the user to run the job as. The default is the user who submitted the job to launchd."
This was written before the advent of the per-user launchd. It should be revised to indicate this key is honored by the root launchd only (for use by LaunchDaemons).
Why do I want to specify it? Well, launchd tasks have certain advantages over LoginHook (and LogoutHook). If I could replace LoginHook scripts -- which, let's face it, are limited in that they have to be called by a single script parent script (similar to `/usr/sbin/periodic`) -- with launchd tasks, I'd much prefer to do so. For one thing, there's no modification of the loginwindow plist -- and the use of individual launchd jobs would make it much easier to run multiple tasks.
The most obvious way to accomplish that is with a LaunchAgent, but Login|LogoutHook run as root. Hence the problem. If your LoginHook- type tasks need root access for whatever reason, then the obvious launchd way to set that up is with the UserName key in your job plist. But it doesn't work.
I can see the wisdom of ignoring the key, but if a sys admin has placed a job in /Library/LaunchAgents, and that directory is installed with the system using restrictive permissions, and the job is owned by root, there would seem to be several adequate safeguards in place to make malicious use difficult. (Application Launch Restrictions are already depending on the filesystem location and permissions, at least in managed environments, so it would seem that launchd could do so as well.) I would be supportive of other reasonable safeguards besides these, too, including script signing and more.
Besides asking whether ignoring the UserName key is meant to be this way and could be changed in the future if enhancement requests were filed, is there another way to replace the hooks with launchd?
Let's step back to a time before launchd and consider the case of an ordinary Cocoa application that needs to perform a privileged operation. Since there's no "UserName" key available in the Info.plist, the application must invoke a privileged helper tool (setuid binary, gated by AuthorizationExecWithPrivilege). With launchd, it's now possible to get rid of the setuid binary (which avoids a whole class of potential privilege escalation vulnerabilities) and replace it with a LaunchDaemon that executes in a privileged context. The Cocoa application can send an IPC message to the Daemon, and the daemon can perform the privileged operation (Authorization API can still be used to create an "external form" that can be validated across the IPC channel). A LaunchAgent, like the Cocoa application example, runs as the user -- in fact they're running in the same context. If it needs to perform a privileged operation, it can send an IPC message to a LaunchDaemon running in a privileged context to perform said operation. - Kevin