Software used:
- FreeBSD 4.0-STABLE
- qmail 1.03
- openldap 2.0.7
- exim 3.22
- Cyrus 1.6.22
- pam_ldap 107
After using qmail for almost a year, I decided to switch to exim for a few reasons:
- Support. Debian uses exim as its default mailer, so I figured I could find plenty of people who used it. In fact, I originally thought about switching back to sendmail, but I've played with that enough that I knew things would be too easy with it.
- LDAP integration. I want to move away from passwd-based authentication systems to LDAP since it seems that I could offer graded accounts using LDAP to set privs.
- Perl Integration. This is the real selling point for me. I love perl and the more places I can stick it, the better.
Compiling exim
Easy. The included it with options to link against OpenSSL and OpenLDAP. Can't get much simpler than:
$ cd /usr/ports/mail/exim
$ make WITH_LDAP=yes WITH_PAM=yes WITH_TLS=yes WITH_PERL=yes LDAP_LIB_TYPE=OPENLDAP2
$ sudo make install
I did comment out the start line in the rc.d script for now till
I get it running.
Compiling Cyrus
Again, easy. Just
$ cd /usr/ports/security/cyrus-sasl; make; sudo make install
$ cd /usr/ports/mail/cyrus; make; sudo make install
It prompted me for what sort of authentication I wanted to use, and
of course I said "OpenLDAP".
Integrating Exim with Cyrus
Since exim's config is in /usr/local/etc/exim and qmail's configuration resides in /var/qmail, I could now set up exim to deliver directly to cyrus without interfering with anything.
Outfitting Exim with RBL
Added the following to the exim config:
rbl_domains = blackholes.mail-abuse.org:dialups.mail-abuse.org:relays.mail-abuse.org
Converting dot-qmail files to /etc/alias entries
I used the following script to change my .qmail* files to entries in the /etc/alias file:
# User of qmail's alias
alias=alias
# Where we want the aliases kept
aliasfile=/usr/local/etc/exim/aliases
# DBM maker
exim_dbm=/usr/local/sbin/exim_dbmbuild
# User mailman runs as
mailman=mailman
# find all non-mailman/alias users
users=`awk 'BEGIN {FS=":"} !/'$alias'|'$mailman'/ {print $1}' < /etc/passwd | sort | xargs`
for user in $users; do
homedir=`sh -c "echo ~$user"`
for q in $homedir/.qmail*; do
if [ -f $q ]; then
echo $user -\> $q
echo ------------
sudo -u $user sh -c "cat $q | sed 's,^&,,' > $homedir/.forward"
cat $homedir/.forward && sudo rm $q
echo
fi
done
done;
sudo rm $aliasfile $aliasfile.db
homedir=`sh -c "echo ~alias"`
for f in $homedir/.qmail*; do
if [ -f $f ]; then
name_from=`echo $f | sed 's,.*/\.qmail-,,'`
name_from=`echo $name_from | sed 's,^/.*,alias,'`
name_to=`cat $f | sed 's,^&,,'`
echo $name_from =\> $name_to
sudo sh -c "echo $name_from $name_to >> $aliasfile"
fi
done;
sudo $exim_dbm $aliasfile $aliasfile.db
Converting mailman aliases
Very, very simple. Just follow the directions for mailman integration on the website.Testing
At this point, I had a working setup to test. Using the following configure file, this is simply the drop-in replacement of exim for qmail. There are no LDAP lookups; there is no cyrus delivery. This is simply to have something in place that works. I will build on this.
Note the mailman components of this configuration. Exim is set up so that all one has to do is run newlist for mailman and Exim will automatically begin to deliver those messages. Also, note that the mailing lists are in the lists.everybody.org domain.
MAILMAN_HOME=/home/websites/lists.everybody.org/
# wrapper script for mailman
MAILMAN_WRAP=MAILMAN_HOME/mail/wrapper
# user and group for mailman
MAILMAN_UID=mailman
MAILMAN_GID=mailman
######################################################################
# MAIN CONFIGURATION SETTINGS #
######################################################################
primary_hostname = everybody.org
local_domains = everybody.org:everyhost.com:slideshow.org:lists.everybody.org
# No local deliveries will ever be run under the uids of these users
exim_user = root
exim_group = mail
never_users = root : root
# Local relays are necessary for mailman, and they don't really hurt.
host_accept_relay = "127.0.0.1/32"
# We only accept unqualified email addresses from localhost
receiver_unqualified_hosts = "127.0.0.1/32"
sender_unqualified_hosts = "127.0.0.1/32"
# We block all of RBL, DUL, and RSS. Later we may turn this to
# warnings and filter on the warnings.
rbl_domains = blackholes.mail-abuse.org:dialups.mail-abuse.org:relays.mail-abuse.org
pid_file_path = /var/run/exim%s.pid
end
######################################################################
# TRANSPORTS CONFIGURATION #
######################################################################
# ORDER DOES NOT MATTER #
# Only one appropriate transport is called for each delivery. #
######################################################################
remote_smtp:
driver = smtp
# We use procmail for local delivery
procmail_pipe:
driver = pipe
command = "/usr/local/bin/procmail -d ${local_part}"
return_path_add
delivery_date_add
envelope_to_add
check_string = "From "
escape_string = ">From "
user = $local_part
group = mail
# This is the normal local delivery
local_delivery:
driver = appendfile
file = /var/mail/${local_part}
delivery_date_add
envelope_to_add
return_path_add
group = mail
mode = 0660
address_pipe:
driver = pipe
return_output
address_file:
driver = appendfile
delivery_date_add
envelope_to_add
return_path_add
address_reply:
driver = autoreply
## Three transports for list mail, request mail and admin mail
## respectively
## Mailman is installed in MAILMAN_HOME
## Mailman is configured to be invoked as user MAILMAN_UID
list_transport:
driver = pipe
command = MAILMAN_WRAP post ${lc:$local_part}
current_directory = MAILMAN_HOME
home_directory = MAILMAN_HOME
user = MAILMAN_UID
group = MAILMAN_GID
list_request_transport:
driver = pipe
command = MAILMAN_WRAP mailcmd ${lc:$local_part}
current_directory = MAILMAN_HOME
home_directory = MAILMAN_HOME
user = MAILMAN_UID
group = MAILMAN_GID
list_admin_transport:
driver = pipe
command = MAILMAN_WRAP mailowner ${lc:$local_part}
current_directory = MAILMAN_HOME
home_directory = MAILMAN_HOME
user = MAILMAN_UID
group = MAILMAN_GID
### end of transports section fragment
end
######################################################################
# DIRECTORS CONFIGURATION #
# Specifies how local addresses are handled #
######################################################################
# ORDER DOES MATTER #
# A local address is passed to each in turn until it is accepted. #
######################################################################
# Local addresses are those with a domain that matches some item in the
# "local_domains" setting above, or those which are passed back from the
# routers because of a "self=local" setting (not used in this configuration).
system_aliases:
driver = aliasfile
file = /usr/local/etc/exim/aliases
search_type = lsearch
file_transport = address_file
pipe_transport = address_pipe
user = root
## Directors section [this deals with local addresses]
##
## First 2 directors rewrite list-owner or owner-list to list-admin
## This is only done if the list exists.
## List existence checks are done by seeing if the file
## MAILMAN_HOME/lists//config.db
## exists.
list_owner_director:
driver = smartuser
domains = lists.everybody.org
require_files = MAILMAN_HOME/lists/${lc:$local_part}/config.db
suffix = "-owner"
new_address = "${lc:$local_part}-admin@${domain}"
owner_list_director:
driver = smartuser
domains = lists.everybody.org
require_files = MAILMAN_HOME/lists/${lc:$local_part}/config.db
prefix = "owner-"
new_address = "${lc:$local_part}-admin@${domain}"
##
## Next 3 directors direct admin, request and list mail to the appropriate
## transport. List existence is checked as above.
list_admin_director:
driver = smartuser
domains = lists.everybody.org
suffix = -admin
require_files = MAILMAN_HOME/lists/${lc:$local_part}/config.db
transport = list_admin_transport
list_request_director:
driver = smartuser
domains = lists.everybody.org
suffix = -request
require_files = MAILMAN_HOME/lists/${lc:$local_part}/config.db
transport = list_request_transport
list_director:
driver = smartuser
domains = lists.everybody.org
require_files = MAILMAN_HOME/lists/${lc:$local_part}/config.db
transport = list_transport
## End of directors fragment
# Handle forward files
userforward:
driver = forwardfile
file = .forward
no_verify
no_expn
check_ancestor
# filter
file_transport = address_file
pipe_transport = address_pipe
reply_transport = address_reply
# Do the local delivery with procmail
procmail:
driver = localuser
transport = procmail_pipe
# Conventional local delivery
localuser:
driver = localuser
transport = local_delivery
end
######################################################################
# ROUTERS CONFIGURATION #
# Specifies how remote addresses are handled #
######################################################################
# ORDER DOES MATTER #
# A remote address is passed to each in turn until it is accepted. #
######################################################################
# Remote addresses are those with a domain that does not match any item
# in the "local_domains" setting above.
# This router routes to remote hosts over SMTP using a DNS lookup with
# default options.
lookuphost:
driver = lookuphost
transport = remote_smtp
# This router routes to remote hosts over SMTP by explicit IP address,
# given as a "domain literal" in the form [nnn.nnn.nnn.nnn]. The RFCs
# require this facility, which is why it is enabled by default in Exim.
# If you want to lock it out, set forbid_domain_literals in the main
# configuration section above.
literal:
driver = ipliteral
transport = remote_smtp
end
######################################################################
# RETRY CONFIGURATION #
######################################################################
# This single retry rule applies to all domains and all errors. It specifies
# retries every 15 minutes for 2 hours, then increasing retry intervals,
# starting at 1 hour and increasing each time by a factor of 1.5, up to 16
# hours, then retries every 8 hours until 4 days have passed since the first
# failed delivery.
# Domain Error Retries
# ------ ----- -------
* * F,2h,15m; G,16h,1h,1.5; F,4d,8h
end
######################################################################
# REWRITE CONFIGURATION #
######################################################################
# There are no rewriting specifications in this default configuration file.
# End of Exim configuration file
Getting PAMized LDAP authentication working
Converting dot-qmail files to LDAP entries
Using LDAP to look up deliveries
Setting up SSL
Most of this comes from example configuration C027 in the
configuration
samples. Especially the following:
$ cd /usr/local/openssl/certs |
Directory already existed in this case |
$ sudo sh -c 'openssl genrsa 1024 > exim.rsa' |
RSA key |
$ sudo sh -c 'openssl gendh -rand /dev/urandom > exim.dh' |
Diffie-Hellman parameters |
Using configuration from /etc/ssl/openssl.cnf You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [US]: State or Province Name (full name) [Louisiana]: Locality Name (eg, city) [New Orleans]: Organization Name (eg, company) [Everybody Networks]: Organizational Unit Name (eg, section) [webserver]: Common Name (eg, YOUR name) [everybody.org]: Email Address [mah@everybody.org]: |
Q & A |
sudo sh -c 'cat everybody-org.rsa everybody-org.x509 everybody-org.dh
> everybody-org.pem'
|
The signed cert is necessary for Outlook which won't take an unsigned cert.
Added the following line to /etc/inetd.conf:
# Following is for cyrus imap over ssl imaps stream tcp nowait cyrus /usr/local/sbin/stunnel exim -l /usr/local/cyrus/bin/imapd -p /usr/local/openssl/certs/everybody-org.pem -- imapd # SMTP Authentication only over SSL smtps stream tcp nowait mail /usr/local/sbin/stunnel exim -l /usr/local/sbin/exim -p /usr/local/openssl/certs/everybody-org.pem -- exim -bs
Alternatively, I could have put this in the rc script:
/usr/local/bin/stunnel -d 465 -l /usr/local/sbin/exim -p /usr/local/openssl/certs/everybody-org.pem -- exim -bsand
/usr/local/bin/stunnel -d 993 -l /usr/local/cyrus/bin/imapd -p /usr/local/openssl/certs/everybody-org.pem -- imapd
Authentication
I found these entries for the configuration file in C034: