The problem with PAM based 2FA:
- PAM does not get called when the SSH daemon does key based authentication. So your 2FA there only works with password authentication. This might be something you want but maybe not.
- A PAM module based solution to 2FA is harder to implement
The solution: Poor man’s 2FA!
It is possible to add the ForceCommand directive to your sshd_config. Like the name suggests it simply runs a command after authentication and before the shell is spawned. This is a good spot to add an extra check, say another factor for authentication.
The code:
#!/bin/bash trap "echo "I'm sorry Dave. I'm afraid I can't do that."; sleep 1 ; kill -9 $PPID ; exit 1" 2 20 code=`od -a -A n /dev/urandom | head -2 | tr -d ' ' | tr -d 'n' | sed 's/[^a-zA-Z0-9]//g' | awk '{print substr($0,1,5)}'` echo -e "Subject:$code\nFrom:root@server <root@server.com>\n2FA code in subject" | sendmail phone_number@carrier.com read input if [ $code = $input ]; then `awk -F: '($1 == $LOGNAME) { print $7 }' /etc/passwd` else kill -9 $PPID fi
That’s it really, save this to an executable file, replace the obvious variables and ForceCommand its ass.
Love the idea of this and am adapting it to the Yubico keys. But I noticed in the awk line (to determine and run the users shell) you have nested backticks… once to run id -u to give you the users user ID and then around the whole ‘awk’ line. Not sure about your shell but this fails on mine.
I went with a simpler solution:
`awk -v name=$LOGNAME -F: ‘($1 == name) { print $7 }’ /etc/passwd`
You could of course refactor this to not require the assignment of name, but this was the least amount of change to your code.
Cheers.
I may have committed a change without testing it first 🙂 Thanks for catching this.
Your solution is far superior I’m updating the code with it, and I swear I’ll test it tomorrow 🙂
Thanks for sharing the 1337ness, please let me know when you have a YubiKey version working I’m interested!