Unfortunately neither project really showcases a modern, sane, secure way of adding a priveleged helper tool to your application.
With BetterAuthorizationSample (BAS), your application includes an installer tool and a helper tool within the application bundle. Your application then jumps through the following hoops to use the helper tool:
- Your application runs the installer tool as root via
AuthorizationExecuteWithPrivileges(), specifying the helper tool as an argument.
- Installer tool copies the helper tool into
- Installer tool creates a
launchd.plistfile for the helper tool in
launchd.plistfile specifies the path to the tool and that it should be launched when a connection is made to a UNIX domain socket located at
/var/run/<application bundle ID>.socket.
- Installer tool executes
launchctl load -w <path to helper tool launchd.plist>.
At this point your application can connect to the socket at
/var/run/<application bundle ID>.socket and start sending commands to the privileged helper tool. Your application might ask the helper tool to “open TCP port 80”, to which the helper tool might respond with “here’s the descriptor that I opened”.
Note that while the BAS sample code’s README claims that it’s “the recommended way to access privileged functionality from a non-privileged application on Mac OS X”, that’s no longer the case.
AuthorizationExecuteWithPrivileges() was deprecated in in Mac OS X v10.7, and has been replaced with
Introduced in Mac OS X v10.6’s Service Management framework, the
SMJobBless() API provides a more modern, secure replacement for the
AuthorizationExecuteWithPrivileges() technique used in the BAS sample. Improvements include:
- The installer tool is unnecessary, so there’s fewer moving parts.
- The helper tool &
launchd.plistare automatically copied into correct system folders and registered with
- A trust relationship is established between the application and helper tool via code-signing identities. This means that the helper tool can only be used by explicitely identified applications.
- Subsequent calls to
SMJobBless()will check the version of your helper tool and automatically upgrade it if necessary.
The SMJobBless sample code does a good job of outlining registration & execution of a privileged helper tool, but unlike the BAS sample it does include any form of inter-process communication (IPC) between the application and helper tool. Most developers combine the UNIX domain socket communication code from the BAS sample with the SMJobBless sample code and call it a day.
But surely there’s a more modern IPC mechanism than defining your own custom command protocol over raw UNIX domain sockets?
Apple introduced the XPC services API in Mac OS X v10.7, providing a modern, lightweight IPC mechanism integrated with GCD and
launchd. The typical way of using XPC is by embedding lightweight helper tools in your application (called “XPC services”), which perform work on behalf of your application.
Sound familiar? That’s exactly what we’re after.
So if XPC helps us create these “lightweight helper tool” bundles, can we simply run an XPC service in a privileged context? Apparently not:
Elevating a [XPC] service’s privileges to root is not supported. Further, an XPC service is private, and is available only to the main application that contains it.
So XPC services are out if your helper needs elevated privileges, but that doesn’t mean we can’t use the XPC APIs independently of XPC services.
A quick look at the XPC APIs for creating an XPC connection reveals this:
By registering a Mach service (instead of a UNIX domain socket as per the BAS sample code) with
man launchd.plist(5)), we can connect to it from our application using
SMJobBless + XPC
To demonstrate how this works, I’ve modified the SMJobBless sample code and added XPC-based IPC support which you can find on Github.
The initial revision is the original SMJobBless sample code, so you can see all the modifications I’ve made by looking at the commit history.
Neither SMJobBless or BetterAuthorizationSample provide the full picture of how you would create a privileged helper tool and communicate with it from your application. SMJobBlessXPC is a step in the right direction.
Let me know if you have any suggestions for improvements.