vodik / envoy

A ssh/gpg-agent wrapper leveraging cgroups and systemd/socket activation
GNU General Public License v3.0
218 stars 17 forks source link

Add keys in pam module #18

Open seanlynch opened 10 years ago

seanlynch commented 10 years ago

It would be great if the pam module could add keys using my password as the passphrase (or prompting a second time if the passphrase is different), same as pam_ssh with try_first_pass (or use_first_pass if you don't want it to ever prompt).

Thanks!

terlar commented 10 years ago

:+1:

eklitzke commented 9 years ago

I looked at this a bit, I think I understand what needs to be done. The options like try_first_pass or use_first_pass can be accessed within pam_sm_open_session() via argc and argv. I believe the password itself can be accessed using pam_get_item() and supplying it PAM_AUTHTOK as the item type. I'll probably take a stab at implementing this at some point when I some time to play around with things; or if I don't get around to it, maybe this will help someone else who wants to try.

eklitzke commented 9 years ago

I spent some time looking at this in more detail, and it's actually rather difficult to do this. Here's the deal. If you invoke ssh-add with a key encrypted by a password, it opens /dev/tty to prompt for and read the password. This makes it rather cumbersome to try to send input into (actually, I'm not even sure if it's possible from within the context that the PAM module is running in...). There's no way to, for, instance, send the password to ssh-add using a normal Unix pipe. You might be able to use something like expect, but that's super hacky.

I looked at the code for pam_ssh_agent, which is an existing PAM module that does unlock password protected ssh keys using the user's supplied password. The way it does this is to use a bunch of low level OpenSSL APIs to attempt to decrypt the key. It looks like what they actually did is copy the file sshkey.c from the OpenSSH project, i.e. this file https://github.com/openssh/openssh-portable/blob/master/sshkey.c is actually copied into the source code for pam_ssh_agent. Then they have their own wrapper around this. It looks pretty complicated... the code is literred with a lot of #if 0 and #if 1 statements which leads me to believe that the APIs are difficult to understand or use correctly, which is why there's dead code everywhere.

Waldteufel commented 9 years ago

You could provide the password with a custom SSH_ASKPASS. Self-contained example:

#!/bin/bash
if [[ "$SSH_ASKPASS" == "$0" ]]
then
    id=$(keyctl request user ssh-add) || exit 1
    # pipe the password to stdout (inside ssh-add)
    exec keyctl pipe $id
elif [[ -n "$HAVE_SESSION" ]]
then
    # read a password from stdin (outside ssh-add)
    keyctl padd user ssh-add @s
    export DISPLAY=-
    export SSH_ASKPASS="$0"
    exec ssh-add </dev/null
else
    export HAVE_SESSION=1
    # create a temporary keyring so the password will be deleted after exiting
    exec keyctl session - "$0" "$@"
fi

Edit: It seems that ssh-add checks $DISPLAY before it runs the helper, so you should set it to something arbitrary in case you are not running the script from an X11 session…

vodik commented 9 years ago

Oh wow, forgot about this.

@eklitzke if you're still interested in this, it should be possible to wrap ssh-add in its own tty, pass passwords in. It does mean extra complexity, but it should be doable.