Create and login to a fresh Ubuntu 10.04 LTS machine:
vmbuilder kvm ubuntu \ --dest /var/lib/libvirt/images/freeradius \ --proxy http://192.168.1.2/ubuntu \ --rootsize 10000 \ --mem 600 \ --suite lucid \ --flavour virtual \ --addpkg unattended-upgrades \ --addpkg openssh-server \ --addpkg avahi-daemon \ --addpkg acpid \ --ssh-key /root/.ssh/authorized_keys \ --libvirt qemu:///system \ --hostname freeradius \ --bridge br0 \ --debug ssh -l root freeradius.local
apt-get install build-essential wget apt-get install libpam0g-dev libykclient3 libykclient-dev
Install PAM module:
wget http://yubico-pam.googlecode.com/files/pam_yubico-2.4.tar.gz tar xfz pam_yubico-2.4.tar.gz cd pam_yubico-2.4 ./configure make check install ln -s /usr/local/lib/security/pam_yubico.so /lib/security/
Setup PAM debug log file:
touch /var/run/pam-debug.log chmod go+w /var/run/pam-debug.log tail -F /var/run/pam-debug.log &
Install FreeRadius:
apt-get install freeradius /etc/init.d/freeradius stop
Next we configure FreeRadius. First add this to /etc/freeradius/users:
DEFAULT Auth-Type = pam
Then comment out pap and uncomment pam from /etc/freeradius/sites-available/default.
Add to the top of /etc/pam.d/radiusd:
auth sufficient pam_yubico.so id=1 debug authfile=/etc/yubikey_mapping
If you want to use HMAC signing, specify the key= field too, like this:
auth sufficient pam_yubico.so id=1 key=b64foo debug authfile=/etc/yubikey_mapping
Create a file /etc/yubikey_mapping (ccccccccltnc is Alice’s YubiKey’s public ID) :
alice:ccccccccltnc
Create a Unix account alice: XXX should not be necessary?
adduser --disabled-password alice
Just press RET and finally y RET on the prompts.
Start radiusd:
LD_PRELOAD=/lib/libpam.so.0 freeradius -X
Confirm that it works with radtest (use a real OTP from Alice’s YubiKey) :
radtest alice ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef 127.0.0.1 0 testing123
Output should be like this:
Sending Access-Request of id 69 to 127.0.0.1 port 1812 User-Name = "alice" User-Password = "ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef" NAS-IP-Address = 127.0.1.1 NAS-Port = 0 rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=69, length=20
PAM debug output should be like this:
[pam_yubico.c:parse_cfg(404)] called. [pam_yubico.c:parse_cfg(405)] flags 0 argc 3 [pam_yubico.c:parse_cfg(407)] argv[0]=id=1 [pam_yubico.c:parse_cfg(407)] argv[1]=debug [pam_yubico.c:parse_cfg(407)] argv[2]=authfile=/etc/yubikey_mapping [pam_yubico.c:parse_cfg(408)] id=1 [pam_yubico.c:parse_cfg(409)] key=(null) [pam_yubico.c:parse_cfg(410)] debug=1 [pam_yubico.c:parse_cfg(411)] alwaysok=0 [pam_yubico.c:parse_cfg(412)] verbose_otp=0 [pam_yubico.c:parse_cfg(413)] try_first_pass=0 [pam_yubico.c:parse_cfg(414)] use_first_pass=0 [pam_yubico.c:parse_cfg(415)] authfile=/etc/yubikey_mapping [pam_yubico.c:parse_cfg(416)] ldapserver=(null) [pam_yubico.c:parse_cfg(417)] ldap_uri=(null) [pam_yubico.c:parse_cfg(418)] ldapdn=(null) [pam_yubico.c:parse_cfg(419)] user_attr=(null) [pam_yubico.c:parse_cfg(420)] yubi_attr=(null) [pam_yubico.c:pam_sm_authenticate(452)] get user returned: alice [pam_yubico.c:pam_sm_authenticate(542)] conv returned: ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef [pam_yubico.c:pam_sm_authenticate(558)] OTP: ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef ID: ccccccccltnc [pam_yubico.c:pam_sm_authenticate(583)] ykclient return value (0): Success [pam_yubico.c:check_user_token(117)] Authorization line: alice:ccccccccltnc [pam_yubico.c:check_user_token(121)] Matched user: alice [pam_yubico.c:check_user_token(125)] Authorization token: ccccccccltnc [pam_yubico.c:check_user_token(128)] Match user/token as alice/ccccccccltnc [pam_yubico.c:pam_sm_authenticate(625)] done. [Success]
FreeRadius debug output should be like this:
rad_recv: Access-Request packet from host 127.0.0.1 port 38575, id=69, length=89 User-Name = "alice" User-Password = "ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef" NAS-IP-Address = 127.0.1.1 NAS-Port = 0 +- entering group authorize {...} ++[preprocess] returns ok ++[chap] returns noop ++[mschap] returns noop [suffix] No '@' in User-Name = "alice", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] returns noop [eap] No EAP-Message, not doing EAP ++[eap] returns noop [files] users: Matched entry DEFAULT at line 204 ++[files] returns ok ++[expiration] returns noop ++[logintime] returns noop Found Auth-Type = PAM +- entering group authenticate {...} pam_pass: using pamauth string <radiusd> for pam.conf lookup pam_pass: authentication succeeded for <alice> ++[pam] returns ok +- entering group post-auth {...} ++[exec] returns noop Sending Access-Accept of id 69 to 127.0.0.1 port 38575 Finished request 0. Going to the next request Waking up in 4.9 seconds. Cleaning up request 0 ID 69 with timestamp +17 Ready to process requests.
Run the command again, with the same OTP :
radtest alice ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef 127.0.0.1 0 testing123
Then output should be like this, since the OTP was replayed:
Sending Access-Request of id 32 to 127.0.0.1 port 1812 User-Name = "alice" User-Password = "ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef" NAS-IP-Address = 127.0.1.1 NAS-Port = 0 rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=32, length=20
PAM debug log:
[pam_yubico.c:parse_cfg(404)] called. [pam_yubico.c:parse_cfg(405)] flags 0 argc 3 [pam_yubico.c:parse_cfg(407)] argv[0]=id=1 [pam_yubico.c:parse_cfg(407)] argv[1]=debug [pam_yubico.c:parse_cfg(407)] argv[2]=authfile=/etc/yubikey_mapping [pam_yubico.c:parse_cfg(408)] id=1 [pam_yubico.c:parse_cfg(409)] key=(null) [pam_yubico.c:parse_cfg(410)] debug=1 [pam_yubico.c:parse_cfg(411)] alwaysok=0 [pam_yubico.c:parse_cfg(412)] verbose_otp=0 [pam_yubico.c:parse_cfg(413)] try_first_pass=0 [pam_yubico.c:parse_cfg(414)] use_first_pass=0 [pam_yubico.c:parse_cfg(415)] authfile=/etc/yubikey_mapping [pam_yubico.c:parse_cfg(416)] ldapserver=(null) [pam_yubico.c:parse_cfg(417)] ldap_uri=(null) [pam_yubico.c:parse_cfg(418)] ldapdn=(null) [pam_yubico.c:parse_cfg(419)] user_attr=(null) [pam_yubico.c:parse_cfg(420)] yubi_attr=(null) [pam_yubico.c:pam_sm_authenticate(452)] get user returned: alice [pam_yubico.c:pam_sm_authenticate(542)] conv returned: ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef [pam_yubico.c:pam_sm_authenticate(558)] OTP: ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef ID: ccccccccltnc [pam_yubico.c:pam_sm_authenticate(583)] ykclient return value (2): YubiKey OTP was replayed (REPLAYED_OTP) [pam_yubico.c:pam_sm_authenticate(625)] done. [Authentication failure]
FreeRadius debug log:
rad_recv: Access-Request packet from host 127.0.0.1 port 55170, id=32, length=89 User-Name = "alice" User-Password = "ccccccccltncdjjifceergtnukivgiujhgehgnkrfcef" NAS-IP-Address = 127.0.1.1 NAS-Port = 0 +- entering group authorize {...} ++[preprocess] returns ok ++[chap] returns noop ++[mschap] returns noop [suffix] No '@' in User-Name = "alice", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] returns noop [eap] No EAP-Message, not doing EAP ++[eap] returns noop [files] users: Matched entry DEFAULT at line 204 ++[files] returns ok ++[expiration] returns noop ++[logintime] returns noop Found Auth-Type = PAM +- entering group authenticate {...} pam_pass: using pamauth string <radiusd> for pam.conf lookup pam_pass: function pam_authenticate FAILED for <alice>. Reason: Permission denied ++[pam] returns reject Failed to authenticate the user. Using Post-Auth-Type Reject +- entering group REJECT {...} [attr_filter.access_reject] expand: %{User-Name} -> alice attr_filter: Matched entry DEFAULT at line 11 ++[attr_filter.access_reject] returns updated Delaying reject of request 1 for 1 seconds Going to the next request Waking up in 0.5 seconds. Sending delayed reject for request 1 Sending Access-Reject of id 32 to 127.0.0.1 port 55170 Waking up in 4.9 seconds. Cleaning up request 1 ID 32 with timestamp +66 Ready to process requests.