Creative Commons License This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

A sad story about a mail server and pam_oath

A useless howto about using pam_oath module for Postfix/Dovecot.


2019/01/21

Go back to zered.org index

The main goal top

The goal was to use OTP generator ( tested mOTP ) to authenticate from unsafe/mobile computers, and keep a strong passphrase in secure password stores on my computers.

A simple way to achieve it : pam_oath

libpam_oath allows PAM authentication using HOTP or TOPT OTP. It should be possible to write rules testing OTP passphrase or, in cas of failure, fallback on unix passwd file tests.

Doing it

First problems top

Understanding PAM basics

# /etc/dovcot/auth-system.conf
passdb {
	driver = pam
	args = dovecot
}
# Implies we will modify /etc/pam/pam.d/dovecot file on Debian Buster
			

Understanding libpam_oath internals

PAM applies rules/check to validate an authentication. Following all the documentation found on the web ( on the project's wiki or archlinux wiki ) leads in strange errors.

To see libpam_oath errors you have to monitor /var/log/syslog and give pam_oath.so a debug argument

# In /etc/pam.d/dovecot
#...
auth   [success=2 default=ignore] pam_oath.so debug usersfile=/etc/users.oath window=30 digits=6
#...
# Producing :
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(118)] called.
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(119)] flags 0 argc 4
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(121)] argv[0]=debug
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(121)] argv[1]=usersfile=/etc/users.oath
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(121)] argv[2]=window=30
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(121)] argv[3]=digits=6
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(122)] debug=1
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(123)] alwaysok=0
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(124)] try_first_pass=0
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(125)] use_first_pass=0
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(126)] usersfile=/etc/users.oath
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(127)] digits=6
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:parse_cfg(128)] window=30
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:pam_sm_authenticate(163)] get user returned: zered
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:pam_sm_authenticate(238)] conv returned: 142132
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:pam_sm_authenticate(302)] OTP: 142132
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:pam_sm_authenticate(312)] authenticate rc -14 (OATH_FILE_CREATE_ERROR: System error when creating file) last otp Thu Jan  1 01:00:00 1970
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:pam_sm_authenticate(317)] One-time password not authorized to login as user 'zered'
Jan 20 17:15:57 mails dovecot[13678]: [pam_oath.c:pam_sm_authenticate(333)] done. [Authentication failure]

Unfortunately the error message don't ring a bell...

authenticate rc -14 (OATH_FILE_CREATE_ERROR: System error when creating file) last otp Thu Jan  1 01:00:00 1970
			

All permission modification on /etc/users.oath on a /etc/oath directory containing the users.oath file change nothing...

Patching libpam_oath to have more informations

Getting source using apt-get source libpam-oath, adding a strerror on errno set by failling fopen, recompiling debian packages with debuild -us -uc

# Dirty & quick patch adding a custom debug
# errno should be set by failing fopen in oath_authenticate_usersfile()

--- oath-toolkit-2.6.1.orig/pam_oath/pam_oath.c
+++ oath-toolkit-2.6.1/pam_oath/pam_oath.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <ctype.h>
+#include <errno.h>
 
 /* Libtool defines PIC for shared objects */
 #ifndef PIC
@@ -307,6 +307,7 @@ pam_sm_authenticate (pam_handle_t * pamh
     rc = oath_authenticate_usersfile (cfg.usersfile,
           user,
           otp, cfg.window, onlypasswd, &last_otp);
+    DBG (("CUSTOM DEBUG : %s", strerror(errno)));
     DBG (("authenticate rc %d (%s: %s) last otp %s", rc,
    oath_strerror_name (rc) ? oath_strerror_name (rc) : "UNKNOWN",
    oath_strerror (rc), ctime (&last_otp)));

A usefull message and a solution

CUSTOM DEBUG : Read-only file system
authenticate rc -14 (OATH_FILE_CREATE_ERROR: System error when creating file) last otp Thu Jan  1 01:00:00 1970
			

Postfix run chrooted on a read only FS !
The solution found was to put the users.oath file in /home/users.oath : Postfix delivers mails in /home, it should be possible to write lock files in this directory even if chrooted :-)

Tests and saaaaaaad conclusion top

A lots of tests implying thunderbird leads to this /etc/pam.d/dovecot

#%PAM-1.0

auth   [success=2 default=ignore] pam_oath.so usersfile=/home/users.oath window=30 digits=6
auth   [success=1 default=ignore] pam_unix.so use_first_pass
auth   requisite       pam_deny.so
auth   required        pam_permit.so

@include common-account
@include common-session
			

The success=N is a kind of goto argument :

In this case, both pam_oath.so and pam_unix.so would jump on pam_permit.so on success.
If the oath OTP check fails, the pam_unix.so check is use as fallback. The use_first_pass argument seems to tell PAM to use the password given to previous check.
It kind of works for imap, sometimes it worked for smtp.... But thunderbird seems to keep trying to send the same password (that is obviously expired since we are speaking of OTP)....

Sad conclusion

After all those debugging tests using a huge/glitchy mail client, I decided to test using a mobile phone App. All tested Apps ask for a password on account creation. Then you have to go in a sub-sub-sub-sub-menu (clicking (with your finger)) to change the Imap password (and another sub-...-menu for SMTP)), perfect for one time passwords.....

Next steps top

Trying the Dovecot SQL Auth database to handle custom account name & password for mobile devices (referencing the same single account).
The main goal will not be reachable. But it should be possible to have a solution with revocable account/password and less risk to leak a strong, kept in head, password using it on unsafe/mobile platforms.

Another solution would be to setup a webmail to use OTP authentication and then use this interface to read/send emails on unsafe/mobile platforms. But no desire to install/setup a webmail right now...