Table of Contents

Exim4 - Enable SMTP-Auth with PAM

To use PAM for SMTP authentication, but with the possibility of passwords in a local file, say /etc/exim4/passwd, overriding those in PAM. In other words, the goal is to have the following:

Configuring exim

/etc/exim4/exim4.conf.template
tls_advertise_hosts = *

Make sure authentication is only enabled on an encrypted connection. This is due to the fact that passwords would otherwise be sent in clear text:

/etc/exim4/exim4.conf.template
auth_advertise_hosts = ${if def:tls_in_cipher {*}{}}

and

/etc/exim4/exim4.conf.template
begin authenticators
 
PLAIN:
   driver = plaintext
   server_prompts = :
   server_condition = "${if pam{$auth2:$auth3}{yes}{no}}"
   server_set_id = $auth2
 
LOGIN:
   driver = plaintext
   server_prompts = "Username:: : Password::"
   server_condition = "${if pam{$auth1:$auth2}{yes}{no}}"
   server_set_id = $auth1

Add or modify the following

/etc/exim4/exim4.conf.template
begin authenticators
 
#########################################################################
plain_server:
 
  # This authenticator implements the PLAIN authentication mechanism
  # (RFC2595).  Since the password is transmitted essentially as clear
  # text, a user can only authenticate if the session is encrypted using
  # TLS.  The user name and password is first checked against
  # /etc/exim4/passwd, then against the system database using PAM (in
  # that order).
 
  driver                     = plaintext
  public_name                = PLAIN
  server_advertise_condition = ${if eq{$tls_cipher}{}{false}{true}}
  server_prompts             = :
  server_set_id              = $auth2
 
  server_condition           = "\
        ${if exists{CONFDIR/passwd}\
          {${lookup{$auth2}lsearch{CONFDIR/passwd}\
            {${if crypteq{$auth3}{\\\{md5\\\}${extract{1}{:}{$value}{$value}fail}}\
              {true}{false} }}\
            {${if pam{$auth2:${sg{$auth3}{:}{::}} }\
              {true}{false}} } }}\
          {${if pam{$auth2:${sg{$auth3}{:}{::}} }\
            {true}{false}} }}"
 
#########################################################################
login_server:
 
  # This authenticator implements the LOGIN authentication mechanism.
  # Since the password is transmitted essentially as clear text, a user
  # can only authenticate if the session is encrypted using TLS.  The
  # user name and password is first checked against /etc/exim4/passwd,
  # then against the system database using PAM (in that order).
 
  driver                     = plaintext
  public_name                = LOGIN
  server_advertise_condition = ${if eq{$tls_cipher}{}{false}{true}}
  server_prompts             = Username:: : Password::
  server_set_id              = $auth1
  server_condition           = "\
        ${if exists{CONFDIR/passwd}\
          {${lookup{$1}lsearch{CONFDIR/passwd}\
            {${if crypteq{$auth2}{\\\{md5\\\}${extract{1}{:}{$value}{$value}fail}}\
              {true}{false} }}\
            {${if pam{$auth1:${sg{$auth2}{:}{::}} }\
              {true}{false}} } }}\
          {${if pam{$auth1:${sg{$auth2}{:}{::}} }\
            {true}{false}} }}"

NOTE: It's important to use \\\{md5\\\} instead of \{md5\} in the crypteq function.

PAM config

Contents of /etc/pam.d/exim

/etc/pam.d/exim
auth        required      /lib/security/$ISA/pam_env.so
auth        sufficient    /lib/security/$ISA/pam_unix.so likeauth nullok
auth        required      /lib/security/$ISA/pam_deny.so
account     required      /lib/security/$ISA/pam_unix.so
password    required      /lib/security/$ISA/pam_cracklib.so retry=3 type=
password    sufficient    /lib/security/$ISA/pam_unix.so nullok use_authtok md5shadow
password    required      /lib/security/$ISA/pam_deny.so
session     required      /lib/security/$ISA/pam_limits.so
session     required      /lib/security/$ISA/pam_unix.so

This file must be readable by the exim group (the group your exim daemon runs as) otherwise you will get the error.

535 Incorrect authentication data (set_id='userid')

Configuring /etc/exim4/passwd

/etc/exim4/passwd
#########################################################################
#    /etc/exim4/passwd: Client Passwords for Mail Submission to Exim    #
#########################################################################
 
# This file allows a user to authenticate a mail submission to the Exim
# MTA without using their system password (found in /etc/shadow).
#
# Each line of this file should contain a "user:password:comment" field,
# where the password is encrypted using MD5 and encoded as a hexadecimal
# string.  Please note that this format is NOT the same as is used by
# /etc/shadow!  You can disable a user from ever sending (authenticated)
# messages by using "*" as the password.
#
# You can use the following Perl command line to generate the password:
#
#  perl -MDigest::MD5=md5_hex -e 'print md5_hex($ARGV[0]),"\n"' password
#
# (replace "password" with your password, of course).
 
####################
#   System users   #
####################
 
root:*:
 
###################
#   Local users   #
###################
 
#test:68772f0946d616e78f18452f84e39da7:Test#Password#01a

The easiest way to generate a password is to use the Digest::MD5 package with Perl:

perl -MDigest::MD5=md5_hex -e 'print md5_hex($ARGV[0]),"\n"' password

Simply replace password with your password.

NOTE: The Perl md5_base64 function is not compatible with Exim's crypteq: the former generates a 22-character string, the latter expects a 24-character string (i.e., it expects two additional characters, ==, on the end of the string).

References

https://github.com/Exim/exim/wiki/AuthenticatedSmtpUsingPamAndPasswords