Configuration
To use the module, first make sure that it is accessible as /lib/security/pam_oath.so:
# ln -s /usr/local/lib/security/pam_oath.so /lib/security/pam_oath.so # ls -la /lib/security/pam_oath.so lrwxrwxrwx 1 root root 35 Dec 4 10:49 /lib/security/pam_oath.so -> /usr/local/lib/security/pam_oath.so #
The next step is to configure PAM to use the module. One simple way for testing is to configure it for "su". Make sure you have a root window open before making any changes!
# head -1 /etc/pam.d/su auth requisite pam_oath.so debug usersfile=/etc/users.oath window=20 #
The next step is to create a user credentials file. As you can see, the PAM configuration uses /etc/users.oath for this. So we create the file:
# cat>/etc/users.oath HOTP root - 00 # chmod go-rw /etc/users.oath #
The file format handles any whitespace as field separator. You may also add lines starting with # for comments.
The above added an OATH secret of all-zeros. To test this, we need to generate some one-time passwords. The "oathtool" is handy for this purpose:
# oathtool/oathtool -w 5 00 328482 812658 073348 887919 320986 435986 #
So let’s test this by running su. At the prompt, you type the password (in this example, "pw") concatenated with the OTP (in this example, "328482").
jas@mocca:~$ su [pam_oath.c:parse_cfg(122)] called. [pam_oath.c:parse_cfg(123)] flags 0 argc 4 [pam_oath.c:parse_cfg(125)] argv[0]=alwaysok [pam_oath.c:parse_cfg(125)] argv[1]=debug [pam_oath.c:parse_cfg(125)] argv[2]=usersfile=/etc/users.oath [pam_oath.c:parse_cfg(125)] argv[3]=window=20 [pam_oath.c:parse_cfg(126)] debug=1 [pam_oath.c:parse_cfg(127)] alwaysok=1 [pam_oath.c:parse_cfg(128)] try_first_pass=0 [pam_oath.c:parse_cfg(129)] use_first_pass=0 [pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath [pam_oath.c:parse_cfg(131)] digits=0 [pam_oath.c:parse_cfg(132)] window=20 [pam_oath.c:pam_sm_authenticate(162)] get user returned: root One-time password (OATH) for `root': [pam_oath.c:pam_sm_authenticate(237)] conv returned: 328482 [pam_oath.c:pam_sm_authenticate(297)] OTP: 328482 [pam_oath.c:pam_sm_authenticate(308)] authenticate rc 0 last otp Wed Jun 3 19:22:50 1931 [pam_oath.c:pam_sm_authenticate(329)] done. [Success] [pam_oath.c:pam_sm_setcred(341)] called. [pam_oath.c:pam_sm_setcred(347)] retval: 0 [pam_oath.c:pam_sm_setcred(367)] done. [Success] mocca:/home/jas#
Success!
The code should have updated the /etc/users.oath file to record the incremented counter, last OTP and timestamp. Inspect the new value as follows:
# cat /etc/users.oath HOTP root - 00 0 328482 2009-12-07T23:23:49L #
In production use you will want to remove the debug parameter in the PAM configuration.
Two-factor authentication
To also verify passwords, you need to configure the one-time password length for the PAM module:
# head -1 /etc/pam.d/su auth requisite pam_oath.so usersfile=/etc/users.oath window=20 digits=6 #
Next specify a password in the users.oath file:
# cat>/etc/users.oath HOTP root pw 00 # chmod go-rw /etc/users.oath #
Then test it:
jas@mocca:~$ su [pam_oath.c:parse_cfg(122)] called. [pam_oath.c:parse_cfg(123)] flags 0 argc 5 [pam_oath.c:parse_cfg(125)] argv[0]=alwaysok [pam_oath.c:parse_cfg(125)] argv[1]=debug [pam_oath.c:parse_cfg(125)] argv[2]=usersfile=/etc/users.oath [pam_oath.c:parse_cfg(125)] argv[3]=window=20 [pam_oath.c:parse_cfg(125)] argv[4]=digits=6 [pam_oath.c:parse_cfg(126)] debug=1 [pam_oath.c:parse_cfg(127)] alwaysok=1 [pam_oath.c:parse_cfg(128)] try_first_pass=0 [pam_oath.c:parse_cfg(129)] use_first_pass=0 [pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath [pam_oath.c:parse_cfg(131)] digits=6 [pam_oath.c:parse_cfg(132)] window=20 [pam_oath.c:pam_sm_authenticate(163)] get user returned: root One-time password (OATH) for `root': [pam_oath.c:pam_sm_authenticate(238)] conv returned: pw820368 [pam_oath.c:pam_sm_authenticate(279)] Password: pw [pam_oath.c:pam_sm_authenticate(297)] OTP: 820368 [pam_oath.c:pam_sm_authenticate(308)] authenticate rc 0 last otp Mon Jun 1 20:43:54 1931 [pam_oath.c:pam_sm_authenticate(330)] done. [Success] [pam_oath.c:pam_sm_setcred(342)] called. [pam_oath.c:pam_sm_setcred(348)] retval: 0 [pam_oath.c:pam_sm_setcred(368)] done. [Success] mocca:/home/jas#
If you supply an incorrect password, you’ll get:
jas@mocca:~$ su [pam_oath.c:parse_cfg(122)] called. [pam_oath.c:parse_cfg(123)] flags 0 argc 5 [pam_oath.c:parse_cfg(125)] argv[0]=alwaysok [pam_oath.c:parse_cfg(125)] argv[1]=debug [pam_oath.c:parse_cfg(125)] argv[2]=usersfile=/etc/users.oath [pam_oath.c:parse_cfg(125)] argv[3]=window=20 [pam_oath.c:parse_cfg(125)] argv[4]=digits=6 [pam_oath.c:parse_cfg(126)] debug=1 [pam_oath.c:parse_cfg(127)] alwaysok=1 [pam_oath.c:parse_cfg(128)] try_first_pass=0 [pam_oath.c:parse_cfg(129)] use_first_pass=0 [pam_oath.c:parse_cfg(130)] usersfile=/etc/users.oath [pam_oath.c:parse_cfg(131)] digits=6 [pam_oath.c:parse_cfg(132)] window=20 [pam_oath.c:pam_sm_authenticate(163)] get user returned: root One-time password (OATH) for `root': [pam_oath.c:pam_sm_authenticate(238)] conv returned: grr525990 [pam_oath.c:pam_sm_authenticate(279)] Password: grr [pam_oath.c:pam_sm_authenticate(297)] OTP: 525990 [pam_oath.c:pam_sm_authenticate(308)] authenticate rc -8 last otp Tue Jun 2 19:29:14 1931 [pam_oath.c:pam_sm_authenticate(314)] One-time password not authorized to login as user 'root' [pam_oath.c:pam_sm_authenticate(327)] alwaysok needed (otherwise return with 9) [pam_oath.c:pam_sm_authenticate(330)] done. [Success] [pam_oath.c:pam_sm_setcred(342)] called. [pam_oath.c:pam_sm_setcred(348)] retval: 0 [pam_oath.c:pam_sm_setcred(368)] done. [Success] mocca:/home/jas#
List of all parameters
"debug": Enable debug output to stdout.
"alwaysok": Enable that all authentication attempts should succeed
(aka presentation mode).
"try_first_pass": Before prompting the user for their password, the
module first tries the previous stacked module´s
password in case that satisfies this module as
well.
"use_first_pass": The argument use_first_pass forces the module to
use a previous stacked modules password and will
never prompt the user - if no password is
available or the password is not appropriate, the
user will be denied access.
"usersfile": Specify filename where credentials are stored, for
example "/etc/users.oath".
"digits": Specify number of digits in the one-time password,
required when using passwords in usersfile. Supported
values are 6, 7, and 8.
"window": Specify search depth, an integer typically from 5 to 50
but other values can be useful too.
SSH Configuration
Configuring pam_oath for use with SSH is straight forward, however you should make sure the /etc/ssh/sshd_config file contains the following:
UsePAM yes ChallengeResponseAuthentication yes
Another reported cause of problems has been SELinux, and you could experiment with disabling SELinux by doing "/usr/sbin/setenforce 0".
Alternatively, instead of "ChallengeResponseAuthentication" it should work to enable "PasswordAuthentication" instead.
Debug hint
By using a /lib/security symlink, you may point the module to a file in your build directory (for testing purposes):
# ln -s /home/jas/src/oath-toolkit/pam_oath/.libs/pam_oath.so /lib/security/pam_oath.so # ls -la /lib/security/pam_oath.so lrwxrwxrwx 1 root root 53 Dec 4 10:49 /lib/security/pam_oath.so -> /home/jas/src/oath-toolkit/pam_oath/.libs/pam_oath.so #
This makes it easy to test newly built code.