Debugging An Authorization Plug-In With Xcode
This technote describes how you can use Xcode's SSH-based debugging feature to remotely debug an authorization plug-in. It is targeted at Mac OS X developers who are developing an authorization plug-in.
Introduction
The authorization plug-in facility allows you to run code during the login process. You can't use standard Xcode techniques to debug an authorization plug-in because there is no way to run Xcode at the time that the plug-in runs. This technote describes how you can use Xcode's SSH-based debugging feature to remotely debug an authorization plug-in. The setup is rather complicated (it requires two computers, setting up SSH login for root, and a shared build directory), but it's well worth the effort if you do a lot of work with authorization plug-ins.
You have to enable the root account and Remote Login (SSH), never a good combination.
You have to enable AFP guest access to your source code.
Once you're done debugging, you should restore your computers to their default state by following the instructions in Restoring Your System.
Getting Started
To start, you'll need to do some basic configuration of your computers.
Start with two machines, the development machine (which runs Xcode) and the target machine (which runs your authorization plug-in).
In the Sharing panel of System Preferences, name the development machine "Development" and the target machine "Target".
Install the Xcode developer tools on both machines.
Sharing The Source
For debugging to work properly, both machines will need access to your source code with exactly the same path.
On the development machine, put your source code on a volume other than the root volume (if you don't have another volume handy, you can use a disk image). Rename the volume to "Source".
On the development machine ensure that the Guest Account is enabled for sharing access ("Allow guests to connect to shared folders" in the Accounts panel of System Preferences).
On the development machine, in the Sharing panel of System Preferences, enable File Sharing over AFP.
In the same panel, drag the "Source" volume into the Shared Folders list and ensure that Everyone has Read Only access.
On the target machine use Connect to Server in the Finder to connect to the development machine as a guest user and verify that you can mount the "Source" volume and see the source code. Then unmount the "Source" volume.
On the target machine, add a mount record to your local directory store and refresh the automounter, as shown in Listing 1.
Listing 1 Adding a mount record
$ # Create the mount record $ sudo dscl . -create /Mounts/Development.local.:\\/Source $ sudo dscl . -create /Mounts/Development.local.:\\/Source VFSType url $ sudo dscl . -create /Mounts/Development.local.:\\/Source VFSLinkDir \ /Volumes/Source $ sudo dscl . -create /Mounts/Development.local.:\\/Source VFSOpts \ url==afp://\;AUTH=NO%20USER%20AUTHENT@Development.local./Source $ # Refresh the automounter $ sudo /usr/sbin/automount -c
On the target machine, confirm that the automount is working by listing the
/Volumes/Source
directory, as shown in Listing 2. This should automatically mount the "Source" volume on the target machine. However, because the volume is automounted it will not show up in the Finder.Listing 2 Confirming the automount
$ ls -lh /Volumes/Source total 32 -r--r--r--@ 1 apple wheel 1.0K Jun 26 17:23 Desktop DB -r--r--r--@ 1 apple wheel 2B Jun 26 15:55 Desktop DF drwxrwxrwx@ 7 apple wheel 264B Nov 28 2007 NullAuthPlugin
Enable Key-Based SSH For Root
On current systems an authorization plug-in is hosted by either SecurityAgent
or authorizationhost
. These run as UID 92 (_securityagent
) or UID 0 (root
), respectively. To debug them, you'll have to run GDB as root on the target machine. To keep things simple, we will enable the root account and then enable key-based SSH authentication for that account.
On the target machine, enable Remote Login (SSH) in the Sharing panel of System Preferences.
On the target machine, run Directory Utility and choose enable the root user (choose Enable Root User on the Edit menu).
On the development machine, generate an SSH key pair as shown by Listing 3.
Listing 3 Generating an SSH key pair
$ mkdir -p .ssh $ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/Users/apple/.ssh/id_rsa): .ssh/id_rsa-wideopen Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in .ssh/id_rsa-wideopen. Your public key has been saved in .ssh/id_rsa-wideopen.pub. The key fingerprint is: 90:cc:24:66:ef:bf:8e:61:4a:f3:d0:9c:0f:d4:ac:5f apple@Development.local
Copy the SSH public key to the root user's home directory on the target machine, as shown by Listing 4.
Listing 4 Copying the SSH public key to the root user's home directory
$ scp .ssh/id_rsa-wideopen.pub root@Target.local.:
On the target machine, log in as root and install the SSH public key, as shown by Listing 5.
Listing 5 Installing the SSH public key
# mkdir -p .ssh # cat id_rsa-wideopen.pub > .ssh/authorized_keys
On the development machine, add the SSH key to your ssh-agent and then confirm that you can SSH as root to the target machine without requiring a password (see Listing 6).
Listing 6 Testing the SSH setup
$ ssh-add .ssh/id_rsa-wideopen $ ssh root@Target.local. Last login: Thu Jun 26 23:58:23 2008 from Development.local #
Configuring Xcode and Debug
The last step is to configure Xcode and debug your program. In this step we'll use Sample Code 'NullAuthPlugin' to provide a concrete illustration as to the steps involved. To start, you wil have to build and install your code and then configure Xcode.
On the development machine, download Sample Code 'NullAuthPlugin' and unpack it to the root directory of your "Source" volume.
Open the project in Xcode and build it.
On the target machine, copy the built plug-in to
/Library/Security/SecurityAgentPlugins/
, as shown by Listing 7.Listing 7 Installing the plug-in
$ sudo cp -R \ /Volumes/Source/NullAuthPlugin/build/Debug/NullAuthPlugin.bundle \ /Library/Security/SecurityAgentPlugins/
On the target machine, modify the
system.login.console
right in the authorization database (currently/etc/authorization
) to invoke the plug-in. Start by making a backup of the authorization database, as shown by Listing 8.Listing 8 Backing up the authorization database
$ sudo cp /etc/authorization /etc/authorization-orig
Then edit the file (using your favorite text editor) to add the mechanism string "NullAuthPlugin:WaitForDebugger" after the mechanism string "HomeDirMechanism:status". Confirm your change using the command shown in Listing 9.
Listing 9 Check the authorization database modification
$ grep -A 2 HomeDirMechanism /etc/authorization <string>HomeDirMechanism:login,privileged</string> <string>HomeDirMechanism:status</string> <string>NullAuthPlugin:WaitForDebugger</string> <string>MCXMechanism:login</string>
On the target machine, log out and then log back in. The login should hang as
NullAuthPlugin
waits for the debugger to connect.On the development machine, bring the
NullAuthPlugin
project to the front in Xcode and choose New Custom Executable from the Project menu. In the resulting dialog leave the Executable Name field set to "Executable" and enter "/System/Library/CoreServices/SecurityAgent.app/Contents/MacOS/SecurityAgent" into the Executable Path field. Then click Finish.In the Debugging tab of the Executable Info window, check the "Debug executable remotely via SSH" checkbox. Enter "root@Target.local." into the "Connect to:" field. And uncheck the "Start executable after starting the debugger" checkbox. The window should now look like Figure 1.
Once everything is set up you can use the following steps to actually debug your code.
In Xcode, choose Debugger from the Run menu to show the debugger window, then choose Console from the Run menu to show the console window.
In Xcode, choose Debug from the Run menu. This console window will now show you the state of GDB running as root on the target machine!
In the console window, attach to the
SecurityAgent
as shown in Listing 10.Listing 10 Attaching to the SecurityAgent
(gdb) attach SecurityAgent Attaching to program: `/System/Library/CoreServices/SecurityAgent.app/Contents/MacOS/SecurityAgent', process 263. Reading symbols for shared libraries ...[…]... done 0x920dd806 in __sigsuspend_nocancel () […]
In Xcode, you can now use the debugger window to debug the authorization plug-in as you would any other code.
Phew! It's been a long haul, but I trust that the result is worth the effort.
Lather, Rinse, Repeat
Inevitably your debugging efforts will lead to code changes, and that requires you to reinstall your authorization plug-in and debug the new version. This is surprisingly simple.
In Xcode on the development machine, stop the debugger.
Make your code changes and rebuild your project.
On the target machine, reinstall the plug-in by repeating the command in Listing 7.
On the target machine, log out and then log back in. The login should hang as
NullAuthPlugin
waits for the debugger to connect.Follow the steps from the previous section to start the debugger.
Restoring Your System
Once you're done debugging you should restore your computers to a reasonable state. This section describes the necessary steps.
On the target machine, remove the reference to your authorization plug-in from the
system.login.console
right in the authorization database (/etc/authorization
). You can do this by restoring the database from the backup you made earlier, as shown in Listing 11.Listing 11 Restoring the authorization database from your backup
$ sudo cp /etc/authorization-orig /etc/authorization
On the target machine, remove your authorization plug-in from the
/Library/Security/SecurityAgentPlugins/
directory.On the target machine, remove the SSH public key for the root user. Log in as root and then run the command in Listing 12.
Listing 12 Removing the SSH public key
# rm .ssh/authorized_keys
On the target machine, disable SSH login (Remote Login in the Sharing panel of System Preferences).
On the target machine, disable the root user (in Directory Utility).
On the target machine, remove the mount record from your local directory store, as shown in Listing 13.
Listing 13 Remove the mount record
$ # Delete the mount record $ sudo dscl . -delete /Mounts/Development.local.:\\/Source $ # Refresh the automounter $ sudo /usr/sbin/automount -c
Restart the target machine.
On the development machine, quit Xcode.
On the development machine, remove the "Source" volume from the Shared Folders list (in the Sharing panel of System Preferences).
On the development machine, disable File Sharing over AFP (in the Sharing panel of System Preferences).
On the development machine, restore the Guest Account to your preferred state (in the Accounts panel of System Preferences).
Restart the development machine.
On each of the development and target machines, restore the computer name to its previous value (in the Sharing panel of System Preferences).
Further Reading
Document Revision History
Date | Notes |
---|---|
2008-09-08 | New document that a tutorial on how to use Xcode to debug an authorization plug-in. |
Copyright © 2008 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2008-09-08