Password PAM – How to Achieve Conditional PAM Authentication

pampassword

I am currently using

auth required pam_unix.so try_first_pass nullok
auth optional pam_ssh.so  use_first_pass

(plus some other, probably irrelevant entries Arch Linux added by default), which means my login password is also used to attempt unlocking any ssh-key stored (or linked to) in ~/.ssh/login-keys.d/ thanks to pam_ssh (I could also use try_first_pass instead in order to get a passphrase prompt should no ssh key be unlocked by my login password).

This works fine so long as the SSH key passphrase is identical to the login one. However, what I would like to achieve is that I can basically login with one of two different passwords – either my login one or the SSH key one.

So I thought that pam_ssh should fist try to unlock my SSH key, and only if that fails should pam_unix be required, otherwise it should be skipped. Can this be achieved somehow?


At first I thought the solution lies in putting pam_ssh first, but additionally it has to be made sufficient instead of optional:

auth sufficient pam_ssh.so  try_first_pass
auth required pam_unix.so try_first_pass nullok

However, in the real files there are some other required lines following required pam_unix.so, such as required pam_env.so, which would now be ignored! So how can I really solve this?

Best Answer

Thanks to two other SE posts (one on SO, one on SF), the answer lies in using advanced control syntax. The

auth required pam_unix.so try_first_pass nullok
# and sometime later
auth optional pam_ssh.so  use_first_pass

should therefore become

auth [success=1 new_authtok_reqd=1 ignore=ignore default=ignore] pam_unix.so try_first_pass nullok
auth required pam_ssh.so use_first_pass

Now it is imperative that the pam_ssh line exactly precedes the pam_unix one, since success=N means to skip N following module(s).

Also, don't forget the session pam_ssh.so line while you're at it!


In my first attempt, I used

auth [success=1 default=ignore] pam_ssh.so try_first_pass
auth required pam_unix.so use_first_pass nullok

instead, but this method locks out all users without SSH keys! Turns out that default=ignore isn't sufficient, auth_err=ignore has to be added since that is apparently not considered part of default. Also, this attempt means there'll either be a "password" or "SSH passphrase" prompt depending on whether the user has an SSH key!


Note that in Arch Linux, the pam_unix line used by login lies in the include chain

login -> system-local-login -> system-login -> system-auth

and that system-login has some other required before including system-auth, so you cannot simply put auth [success=1 default=ignore] pam_ssh.so try_first_pass in before login's auth include system-local-login - you'd skip the wrong required and thanks to the pam_unix.so use_first_pass (instead of try_first_pass) you could still only login with your login password! On the other hand, by modifying system-auth, you're also allowing other services such as sshd to use your SSH key as authentication option to the login password. If you truly want only your login to use this, you have to pretty much break the include chain and manually copy all auths to login.

Related Question