»Home
»News
»Download
»Documentation
     »oathtool(1)
     »pskctool(1)
     »Liboath API
     »Libpskc Quickstart
     »Libpskc API
     »pam_oath
»Contribute
     »Code
     »Bug tracker
OATH Toolkit
One-time password components

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.