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:
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:
auth_advertise_hosts = ${if def:tls_in_cipher {*}{}}
and
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
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.
Contents of /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')
######################################################################### # /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).