Merge commit 'dkg/master'
[monkeysphere.git] / src / share / m / subkey_to_ssh_agent
1 # -*-shell-script-*-
2 # This should be sourced by bash (though we welcome changes to make it POSIX sh compliant)
3
4 # Monkeysphere subkey-to-ssh-agent subcommand
5 #
6 # The monkeysphere scripts are written by:
7 # Jameson Rollins <jrollins@finestructure.net>
8 # Jamie McClelland <jm@mayfirst.org>
9 # Daniel Kahn Gillmor <dkg@fifthhorseman.net>
10 #
11 # They are Copyright 2008-2009, and are all released under the GPL,
12 # version 3 or later.
13
14 # try to add all authentication subkeys to the agent
15
16 # FIXME: what if you only want to add one authentication subkey to the
17 # agent?
18
19 subkey_to_ssh_agent() {
20     local sshaddresponse=0
21     local secretkeys
22     local authsubkeys
23     local workingdir
24     local keysuccess=0
25     local subkey
26     local publine
27     local kname
28
29     if ! test_gnu_dummy_s2k_extension ; then
30         failure "Your version of GnuTLS does not seem capable of using with gpg's exported subkeys.
31 You may want to consider patching or upgrading to GnuTLS 2.6 or later.
32
33 For more details, see:
34  http://lists.gnu.org/archive/html/gnutls-devel/2008-08/msg00005.html"
35     fi
36
37     # if there's no agent running, don't bother:
38     if [ -z "$SSH_AUTH_SOCK" ] || ! which ssh-add >/dev/null ; then
39         failure "No ssh-agent available."
40     fi
41
42     # and if it looks like it's running, but we can't actually talk to
43     # it, bail out:
44     ssh-add -l >/dev/null || sshaddresponse="$?"
45     if [ "$sshaddresponse" = "2" ]; then
46         failure "Could not connect to ssh-agent"
47     fi
48     
49     # get list of secret keys (to work around bug
50     # https://bugs.g10code.com/gnupg/issue945):
51     secretkeys=$(gpg_user --list-secret-keys --with-colons --fixed-list-mode \
52         --fingerprint | \
53         grep '^fpr:' | cut -f10 -d: | awk '{ print "0x" $1 "!" }')
54
55     if [ -z "$secretkeys" ]; then
56         failure "You have no secret keys in your keyring!
57 You might want to run 'gpg --gen-key'."
58     fi
59     
60     authsubkeys=$(gpg_user --list-secret-keys --with-colons --fixed-list-mode \
61         --fingerprint --fingerprint $secretkeys | \
62         cut -f1,5,10,12 -d: | grep -A1 '^ssb:[^:]*::[^:]*a[^:]*$' | \
63         grep '^fpr::' | cut -f3 -d: | sort -u)
64
65     if [ -z "$authsubkeys" ]; then
66         failure "no authentication-capable subkeys available.
67 You might want to 'monkeysphere gen-subkey'"
68     fi
69
70     workingdir=$(msmktempdir)
71     trap "rm -rf $workingdir" EXIT
72     umask 077
73     mkfifo "$workingdir/passphrase"
74
75     # FIXME: we're currently allowing any other options to get passed
76     # through to ssh-add.  should we limit it to known ones?  For
77     # example: -d or -c and/or -t <lifetime> 
78
79     for subkey in $authsubkeys; do 
80         # choose a label by which this key will be known in the agent:
81         # we are labelling the key by User ID instead of by
82         # fingerprint, but filtering out all / characters to make sure
83         # the filename is legit.
84
85         primaryuid=$(gpg_user --with-colons --list-key "0x${subkey}!" | grep '^pub:' | cut -f10 -d: | tr -d /)
86
87         #kname="[monkeysphere] $primaryuid"
88         kname="$primaryuid"
89
90         if [ "$1" = '-d' ]; then
91             # we're removing the subkey:
92             gpg_user --export "0x${subkey}!" | openpgp2ssh "$subkey" > "$workingdir/$kname"
93             (cd "$workingdir" && ssh-add -d "$kname") || keysuccess="$?"
94         else
95             # we're adding the subkey:
96             mkfifo "$workingdir/$kname"
97             gpg_user --passphrase-fd 3 3<"$workingdir/passphrase" \
98                 --export-options export-reset-subkey-passwd,export-minimal,no-export-attributes \
99                 --export-secret-subkeys "0x${subkey}!" | openpgp2ssh "$subkey" > "$workingdir/$kname" &
100             (cd "$workingdir" && DISPLAY=nosuchdisplay SSH_ASKPASS=/bin/false ssh-add "$@" "$kname" </dev/null )&
101
102             passphrase_prompt "Enter passphrase for key $kname: " "$workingdir/passphrase"
103             wait %2 || keysuccess="$?"
104         fi
105
106         rm -f "$workingdir/$kname"
107     done
108
109     trap - EXIT
110     rm -rf "$workingdir"
111
112     # FIXME: sort out the return values: we're just returning the
113     # failure code of the last authentication subkey which fails.
114     # what if more than one authentication subkey fails?
115     return "$keysuccess"
116 }