Saturday, January 3, 2009

Unwrapping the MacGPG installation

There's a promising bit of software available at http://macgpg.sourceforge.net/. Unfortunately, the installation of version 2.0.9 had to manipulate various .plist files on the system, and for all users. This makes the system much more difficult to use, and potentially breaks any customizations to the environment.

The authors of MacGPG have been very responsive to reports of issues, and are in the process of creating an uninstall script. The purpose of this blog post is to dig into how this software runs in the system, and learn a little about OSX 10.4 along the way.



So what's running?

$ ps aux | grep gpg
******* 6986 0.0 -0.0 29644 308 ?? Ss 10:46AM 0:00.01 gpg-agent --daemon --write-env-file
******* 7025 0.0 -0.0 27376 420 p1 S+ 10:47AM 0:00.01 grep gpg


You'll notice that this process is started for any user of the system, not just the user that installed the software. From the manpage:

gpg-agent is a daemon to manage secret (private) keys independently from any protocol. It is used as a backend for gpg and gpgsm as well as for a couple of other utilities. The usual way to run the agent is from the ~/.xsession file: eval `gpg-agent --daemon` If you don't use an X server, you can also put this into your regular startup file ~/.profile or .bash_profile. It is best not to run multi- ple instance of the gpg-agent, so you should make sure that only one is running: gpg-agent uses an environment variable to inform clients about the communication parameters. You can write the content of this envi- ronment variable to a file so that you can test for a running agent. This short script may do the job: if test -f $HOME/.gpg-agent-info && kill -0 `cut -d: -f 2 $HOME/.gpg-agent-info` 2>/dev/null; then GPG_AGENT_INFO=`cat $HOME/.gpg-agent-info` export GPG_AGENT_INFO else eval `gpg-agent --daemon` echo $GPG_AGENT_INFO >$HOME/.gpg-agent-info fi Note that the new option --write-env-file may be used instead.

You should have a .gpg-agent-info file in your home directory, but there isn't a .bashrc or .profile file. We do however have a .MacOSX directory. Inside there should be a file called environment.plist with the following:


GPG_AGENT_INFO
/tmp/gpg-pIhMQu/S.gpg-agent:6986:1


This is confirmed running lsof -p 6986 gives the following:

**********:~ *******$ lsof -p 6986
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
gpg-agent 6986 ******* cwd VDIR 14,2 1122 2 /
gpg-agent 6986 ******* txt VREG 14,2 4247824 1429308 /usr/local/bin/gpg-agent
gpg-agent 6986 ******* txt VREG 14,2 1797576 163657 /usr/lib/dyld
gpg-agent 6986 ******* txt VREG 14,2 4398204 1368964 /usr/lib/libSystem.B.dylib
gpg-agent 6986 ******* txt VREG 14,2 1231864 1368744 /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
gpg-agent 6986 ******* txt VREG 14,2 801160 1090767 /usr/lib/libobjc.A.dylib
gpg-agent 6986 ******* txt VREG 14,2 1455656 1368830 /usr/lib/libicucore.A.dylib
gpg-agent 6986 ******* txt VREG 14,2 304580 1110847 /usr/lib/libncurses.5.4.dylib
gpg-agent 6986 ******* 0r VCHR 3,2 0t0 62268292 /dev/null
gpg-agent 6986 ******* 1w VCHR 3,2 0t0 62268292 /dev/null
gpg-agent 6986 ******* 2w VCHR 3,2 0t0 62268292 /dev/null
gpg-agent 6986 ******* 3r 0x051bdd60 file struct, ty=0x3, op=0x384768
gpg-agent 6986 ******* 4r 0x051bdbb0 file struct, ty=0x6, op=0x3833ec
gpg-agent 6986 ******* 5w 0x051bd8f0 file struct, ty=0x6, op=0x3833ec
gpg-agent 6986 ******* 6u unix 0x03bb9720 0t0 /tmp/gpg-pIhMQu/S.gpg-agent


This looks a bit weird though. Why in /tmp? Why have the nonce appended to the path? We also have some timeline information. 6986 corresponds to the PID of gpg-agent at that time, so that PID was already assigned when the environment.plist was written. On my system in /tmp I have the following:

drwx------ 3 ******* wheel 102 Jan 2 10:39 gpg-wJ3ihI
drwx------ 3 ******* wheel 102 Jan 2 11:45 gpg-m2uq2i
drwx------ 3 ******* wheel 102 Jan 3 10:46 gpg-pIhMQu


According to last, this corresponds to login times. Each of these folders contains the exact same thing, S.gpg-agent, a socket link.

We also know that the gpg-agent is executed on login. A .plist file isn't present, however in OSX the defaults system shows us how the application is started:

************:~/Library/Preferences root# defaults read com.apple.loginwindow LoginHook
/usr/local/sbin/gpg-login.sh
************:~/Library/Preferences root# defaults read com.apple.loginwindow LogoutHook
/usr/local/sbin/gpg-logout.sh




Uninstalling version 2.0.9


We should be able to stop the agent from running by removing the login and logout hooks using defaults. First we want to stop the running process:

kill -9 6986 (change to your PID)

Remove the hooks:

sudo defaults delete com.apple.loginwindow LoginHook
sudo defaults delete com.apple.loginwindow LogoutHook


Reading the hooks should now give the following:

defaults read com.apple.loginwindow LoginHook
2009-01-03 18:22:49.320 defaults[7836]
The domain/default pair of (com.apple.loginwindow, LoginHook) does not exist


Logging out and back in then running ps aux | grep gpg should confirm that the gpg-agent is no longer running. We can now remove the binaries and scripts left on the system we found in the first part of the analysis:

rm /usr/local/sbin/addgnupghome
rm /usr/local/sbin/applygnupgdefaults
rm /usr/local/sbin/gpg-login.sh
rm /usr/local/sbin/gpg-logout.sh

rm -r /tmp/gpg-*

rm /usr/local/bin/gpg-agent
rm /usr/local/bin/gpg-connect-agent
rm /usr/local/bin/gpg2
rm /usr/local/bin/gpgconf
rm /usr/local/bin/gpgkey2ssh
rm /usr/local/bin/gpgparsemail
rm /usr/local/bin/gpgsm
rm /usr/local/bin/gpgsm-gencert.sh
rm /usr/local/bin/gpgv2

rm -r ~/.gnupg
rm ~/.gpg-agent-info


Finally, remove the GPG agent key from the environment.plist file by deleting these two lines:

GPG_AGENT_INFO
/tmp/gpg-pIhMQu/S.gpg-agent:6986:1


Logout and log back in to confirm that everything is starting correctly with no errors.