UserName ignored on per-user LaunchAgents
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. 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." When that key is specified in a LaunchAgent, even one in /Library/LaunchAgents, I've found that the key is ignored, a message to that effect is written to the system.log, and the job runs as the user that is logging in. 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? Thanks! -- Jeremy
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
I can understand the desire/need for privilege separation. Not being skilled in IPC, though, is there a way that systems administrators operating at a scripting level can set up what you've described? The reality is that LoginHook/LogoutHook exist today and do what I want, but I'd rather be doing the same thing with launchd because it gives me a little more granularity in setup and control. Instead of editing loginwindow.plist for root and having a hook script that does its work itself or calls other scripts to do work during those system events, I would like to have the benefit of setting up multiple compartmentalized, modularized launchd jobs. This is especially true if you manage systems with Radmind, which works really well at managing files. But moving to launchd jobs for what would have been in Login/LogoutHook also seems to make sense for the more installer-based management provided by ARD, LanDesk, LANrev, FileWave, etc. Thanks! -- Jeremy
On Dec 5, 2007, at 6:59 AM, Jeremy Reichman wrote:
I can understand the desire/need for privilege separation.
Not being skilled in IPC, though, is there a way that systems administrators operating at a scripting level can set up what you've described?
Not really. That is a sore spot in the operating system right now. Actually, scripting in general is a sore spot of most, if not all, operating systems, given that the core routines tend to be written in compiled languages first, and those routines are NOT automatically bridged to the interpreted languages.
The reality is that LoginHook/LogoutHook exist today and do what I want, but I'd rather be doing the same thing with launchd because it gives me a little more granularity in setup and control. Instead of editing loginwindow.plist for root and having a hook script that does its work itself or calls other scripts to do work during those system events, I would like to have the benefit of setting up multiple compartmentalized, modularized launchd jobs.
Setup a launchd job that launches at login. Have it do the LoginHook stuff you used to do. Then have the program wait for SIGTERM. Once SIGTERM arrives, do the LogoutHook stuff and exit. davez
On Dec 5, 2007, at 12:48 AM, Kevin Van Vechten wrote:
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).
I'm afraid I don't understand what is meant by the term "external form" here. Are you suggesting that the authorization API be used to prevent rogue applications from utilizing the IPC services vended by the daemon?
Nathan Duran <mailto:launchd@khiltd.com> wrote (Wednesday, December 5, 2007 10:31 AM -0800):
I'm afraid I don't understand what is meant by the term "external form" here. Are you suggesting that the authorization API be used to prevent rogue applications from utilizing the IPC services vended by the daemon?
Hey, a question I can answer. :) When you authenticate a user, you get an authorization reference which can then be passed to various Authorization API functions to do stuff. However, authorization references cannot be passed between processes. To obtain an authorization (like in a GUI app) and pass that to another process for it to use (like a deamon or faceless helper) you must convert the authorization ref into an "external form", which is just an opaque data blob that encapsulates the authorization. You then pass that data blob to the other process, which then turns the "external" form of the authorization back into a usable authorization ref. -- James Bucanek
On Dec 5, 2007, at 9:31 AM, Nathan Duran wrote:
On Dec 5, 2007, at 12:48 AM, Kevin Van Vechten wrote:
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).
I'm afraid I don't understand what is meant by the term "external form" here. Are you suggesting that the authorization API be used to prevent rogue applications from utilizing the IPC services vended by the daemon?
The term "external form" is just taken from the relevant Authorization API -- AuthorizationMakeExternalForm(...). <http://developer.apple.com/documentation/Security/Conceptual/authorization_c...
Depending on the context of the privileged operation, yes, it makes sense to vet incoming IPC requests with the Authorization API before performing the operation. For example, we have a launch-on-demand helper that performs some privileged operations on behalf of System Preferences.app; but it only performs the operation if the "system.preferences" right has been acquired (via clicking the lock icon in System Preferences). - Kevin
On Dec 5, 2007, at 9:46 AM, Kevin Van Vechten wrote:
The term "external form" is just taken from the relevant Authorization API -- AuthorizationMakeExternalForm(...).
Ah, now I remember. That's one of those APIs whose very nature encourages code recycling and I know haven't actually looked at its documentation since the last time it was updated. So if you still have to present the user with an authentication dialog then, from *their* point of view, is there any difference between the two methodologies (helper tool vs. daemons-on-demand)? On Dec 5, 2007, at 9:51 AM, Quinn wrote:
For a concrete illustration of this, check out the recently released BetterAuthorizationSample.
<http://developer.apple.com/samplecode/BetterAuthorizationSample/index.html
Excellent. If I recall correctly, the fact that the previous incarnation of sample code (MoreAuth?) either didn't work or wouldn't compile factored heavily in my reluctance to revisit the API ;) I'll definitely take a look at the new stuff.
On Dec 5, 2007, at 10:11 AM, Nathan Duran wrote:
On Dec 5, 2007, at 9:46 AM, Kevin Van Vechten wrote:
The term "external form" is just taken from the relevant Authorization API -- AuthorizationMakeExternalForm(...).
Ah, now I remember. That's one of those APIs whose very nature encourages code recycling and I know haven't actually looked at its documentation since the last time it was updated.
So if you still have to present the user with an authentication dialog then, from *their* point of view, is there any difference between the two methodologies (helper tool vs. daemons-on-demand)?
Absolutely. Helper tools require a setuid executable bit to be set; they're also inherently less secure -- every environment variable used by every library linked against is a potential source of attack. Launch-on-demand helpers start from a clean environment, avoiding this class of vulnerabilities. Additionally setuid executable binaries get in the way of drag- installs. Today, launch-on-demand helpers present the same obstacles to drag-installs because we'd recommend secure ownership (root:wheel); however this is a matter of policy (permissions are used to establish trust), not mechanism (setuid is required to escalate privilege). As we move to better mechanisms for establishing trust (code signing), we can eventually alleviate the ownership requirements and allow for drag installs. We're clearly not there yet, but moving to launch-on-demand is a step in this direction. - Kevin
On Dec 5, 2007, at 2:50 PM, Kevin Van Vechten wrote:
Absolutely. Helper tools require a setuid executable bit to be set; they're also inherently less secure -- every environment variable used by every library linked against is a potential source of attack. Launch-on-demand helpers start from a clean environment, avoiding this class of vulnerabilities.
I get that, but I'm talking about what the user sees on their screen, not the under-the-hood stuff they know nothing about.
On Dec 5, 2007, at 5:02 PM, Nathan Duran wrote:
On Dec 5, 2007, at 2:50 PM, Kevin Van Vechten wrote:
Absolutely. Helper tools require a setuid executable bit to be set; they're also inherently less secure -- every environment variable used by every library linked against is a potential source of attack. Launch-on-demand helpers start from a clean environment, avoiding this class of vulnerabilities.
I get that, but I'm talking about what the user sees on their screen, not the under-the-hood stuff they know nothing about.
I believe the dialog presented is the same in both cases. - Kevin
At 9:31 -0800 5/12/07, Nathan Duran wrote:
I'm afraid I don't understand what is meant by the term "external form" here. Are you suggesting that the authorization API be used to prevent rogue applications from utilizing the IPC services vended by the daemon?
For a concrete illustration of this, check out the recently released BetterAuthorizationSample. <http://developer.apple.com/samplecode/BetterAuthorizationSample/index.html> Share and Enjoy -- Quinn "The Eskimo!" <http://www.apple.com/developer/> Apple Developer Relations, Developer Technical Support, Core OS/Hardware
On Dec 5, 2007, at 9:51 AM, Quinn wrote:
At 9:31 -0800 5/12/07, Nathan Duran wrote:
I'm afraid I don't understand what is meant by the term "external form" here. Are you suggesting that the authorization API be used to prevent rogue applications from utilizing the IPC services vended by the daemon?
For a concrete illustration of this, check out the recently released BetterAuthorizationSample.
<http://developer.apple.com/samplecode/BetterAuthorizationSample/index.html
Share and Enjoy
I finally had a chance to sit down and look over this, and while I think it may be a great approach for an application which needs to perform certain tasks as root on an ongoing basis, I don't think it's a privileged operations panacea, however secure it may be. In particular, it strikes me as overkill to litter /Library and /var with support files and dance around with complicated launchd IPC maneuvers at times when all I need to do is create a keychain item or install a trusted root certificate as part of a larger software installation. Things like this are usually run once before they're thrown away, and since something's going to have to ask for permission to write all those root-owned plists out anyway, might as well get it over with right then and there the old fashioned AEWP/setuid way. Cool stuff, but I unfortunately can't replace any of the helper tools I've got with it. The asl_log() thing sounds interesting, though. What list should I complain about the lack of documentation/evangelization for that on? I didn't even know it existed.
participants (6)
-
Dave Zarzycki
-
James Bucanek
-
Jeremy Reichman
-
Kevin Van Vechten
-
Nathan Duran
-
Quinn