Creative Commons License
This work is licenced under a Creative Commons Licence.

Exim, Courier-IMAP with TLS+MySQL Auth How-To

Table of contents

1. Introduction

1.1 Concepts

I have recently started to think that BSD is a superior server operating
system over Linux. In this how-to, I’m using FreeBSD 5.3-RELEASE and it’s
excellent jail system.

I’ve also been a fan of databases for organizing and replicating large
amounts of data. I chose MySQL for my setup, mostly because it’s the easiest to
configure with this specific setup. My hosted sites are relatively small in
mail volume, and therefore I decided it was best to host several sites on one
server computer, for maximum efficiency. This is called virtual hosting, which
we will also cover in this document.

I wanted to give my users a wide range of supported protocols, so that I
could maximize client compatibility. On today’s relatively insecure Internet,
I also decided it was best to have as much encryption support as possible.
This is where the strong SSL/TLS encryption support comes in.

I’ve had some previous encounters with Qmail and Sendmail, but didn’t really
like either of them. I’ve always considered Sendmail’s configuration quite
non-trivial, for example. Once I tried Exim, I haven’t looked back.

An important aspect of MTAs is the way they store messages. Currently,
there are two dominating implementations, namely the traditional style
Unix mailboxes, which are know as “mbox”, and the Maildir format, which
was originally introduced by Qmail. You’ll find lots more information on
these and their differences by using your favorite search engine. I will
use Maildirs in this guide. For a tutorial on mboxes, please see my other
how-to, titled Exim, Amavis, Qpopper with TLS+MySQL Auth
Mini How-To
.

I am by no means a guru of any of the softwares mentioned here, and therefore
suggestions and comments are always welcome.

Throughout this document, you will see either hash symbols (#) or dollar signs
($) in front of the commands. These indicate whether the command should be run
as a regular user or with superuser privileges (i.e. root). Do not include these
in the commands! And by the way, copy-pasting commands is not such a great
idea. I also provide my configuration files here for reference only.
Please do not just copy them over to your server without fully understanding
what they do. Additionally, please do not use the authors of this documents
as a technical support, which we are most certainly not. Instead, you should
consult the respective softwares’ manual pages, documentations, forums and
mailing lists.

You should at least have knowledge of how daemons, users, groups and
permissions work and how files are organized in Linux/Unix before you attempt
an installation of this sort. Go read up on them first. Also, read
(and don’t just skim through) the documentations provided with the various
softwares noted here. This how-to is not a replacement for those documents,
but more of a complementation and quick reference. The installation of an
e-mail system is not a task for Linux/Unix beginners. Setting up this for
the first time will take a while.

I will make the following assumptions; you already have a Linux/Unix
operating system installed and configured, you have Perl successfully
installed and configured on your server, this server has Internet access
and that you have root user access to this server.

For brevity’s sake, I will use “e.g.” as a shorthand for “for instance”, and
“i.e.” as a shorthand for “that is” or “in other words” throughout this
how-to.

1.2 Advantages of this setup

Maildirs are more effective and use less system resources. They also work better on NFS, due to the fact that locking is not needed, like it would when using mboxes. Also, the excellent Squirrelmail webmail system uses IMAP. This type of setup also allows me to offer both POP3 and IMAP4 for my users, depending on which one they want to use. Maildirs are also easier to manage – ever tried to delete one specific e-mail message from a mbox with tens of megabytes of data using only vi? Don’t.

1.3 Problems with this setup

MySQL’s MD5 function converts the binary MD5 hash to hexadecimal. Courier-IMAP, however, uses base64-encoded MD5 hashes, like LDAP. Exim supports both. I decided it was best to just stick with the traditional crypt, which is what MySQL’s ENCRYPT() function produces. However, if you want to store base64-encoded MD5 hashes in the MySQL database, you could use this Perl snippet to do the trick (provided that you have Perl installed, of course):

$ perl -e ‘use MIME::Base64 ; print “{MD5}” . encode_base64(‘password’); ‘

Also, there is no support for the “STARTTLS” command in Courier-IMAP’s POP3 daemon, so you’ll have to use the “alternate-port” mechanism (which, some people say, is the only way to do secure POP, but I’m not so sure about that).

1.4. Copyright

Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled “GNU
Free Documentation License”.

1.5. Disclaimer

Use the information in this document at your own risk. I disavow any potential
liability for the contents of this document. Use of the concepts, examples,
and/or other content of this document is entirely at your own risk.

All copyrights are owned by their owners, unless specifically noted otherwise.
Use of a term in this document should not be regarded as affecting the
validity of any trademark or service mark.

Naming of particular products or brands should not be seen as endorsements.

You are strongly recommended to make a backup of your system before major
installation and should make backups at regular intervals.

1.6. Acknowledgments and Thanks

Thanks to everyone who gave comments as I was writing this.

2. FreeBSD’s Jails

2.1. Jail networking theory

First a bit of theory on my networking setup; the host computer I’m setting
up this jail on has the internal IP of 10.0.0.5, which is NATed in my router
for Internet access. The router has my public IP address, 81.17.193.49. Below
is a schematic of my network setup:

To make my administartion tasks easier, I will install Daemontools, a daemon-watching daemon, which will restart services in case they happen to die.

Both Exim and Courier need to be placed in the same jail, as both need
filesystem access to the maildirs. Amavisd-new can be placed in a chroot
of it’s own, as communication between Exim and Amavisd-new is done via
TCP, as is communication with MySQL.

2.2. Jail setup

Here, I’m creating a new jailcell with the IP of 10.0.1.2. I did this on FreeBSD 5.2.1-RELEASE; I’m not sure how this behaves on other operating systems. jailsetup.sh is my small shell script for setting up new jailcells. On the host system, I executed:

# ./jailsetup.sh 10.0.1.2

In order to save some bandwidth, I used mount_nullfs instead of cvsup to get a ports tree into the jailcell:

# mount_nullfs /usr/ports /var/jail/10.0.1.2/usr/ports

Next up is the Exim installation.

3. Exim Installation

First, disable Sendmail, which is enabled if you chose ‘moderate security’ when installing FreeBSD:

# vi /etc/rc.conf

Insert a line such as this (or simply change YES to NONE):


sendmail_enable="NONE"

Next, download and unpack Exim:

$ cd /var/jail/10.0.1.2/tmp
$ fetch http://mirrors.sunsite.dk/exim/exim/exim4/exim-4.62.tar.bz2
$ tar xfvj exim-4.62.tar.bz2
$ cd exim-4.62
$ cp src/EDITME Local/Makefile

$ vi Local/Makefile

Remember to include Maildir support in Exim’s Local/Makefile (make sure SUPPORT_MAILDIR=yes is not commented out). As I’m installing MySQL and PostgreSQL in different jails than Exim, I need to copy over MySQL’s and PostgreSQL’s header files and libraries from the appropriate jails. I’ve installed MySQL in a jail with the address of 10.0.1.0 and PostgreSQL in a jail with the address 10.0.1.3.

$ cp /var/jail/10.0.1.0/usr/local/include/mysql/* /var/jail/10.0.1.2/usr/include/
$ cp /var/jail/10.0.1.0/usr/local/lib/mysql/* /var/jail/10.0.1.2/usr/lib/
$ cp /var/jail/10.0.1.3/usr/local/pgsql/include/*.h /var/jail/10.0.1.2/usr/include/

$ cp /var/jail/10.0.1.3/usr/local/pgsql/lib/libpq.* /var/jail/10.0.1.2/usr/lib/

Let’s jail ourselves to the cell and add a user for Exim:

# jail /var/jail/10.0.1.2 kiwi 10.0.1.2 /bin/sh
# pw useradd exim

Now we can compile and install Exim:

$ cd /tmp/exim-4.62
$ make
# make install

Install Clam AntiVirus, which will be used for content scanning by Exim:

# pkg_add -r clamav

Install SpamAssassin, which will be used for content scanning by Exim:

# cd /usr/ports/mail/p5-Mail-SpamAssassin/; make all install clean

Next, create the SQL tables for Exim, as specified in my other how-to,
Exim, Amavis, Qpopper with TLS+MySQL Auth Mini How-To,
section “5.1. SQL tables for Exim”.

4. Courier IMAP Installtion

4.1. Courier IMAP Installtion

Courier-IMAP requires Perl and gmake. Let’s install them to the jailcell. You’ll also need Perl on the host system later on, when we install Amavisd-new. While we’re still in the jailcell, do something like:

# pkg_add -r perl gmake

Run pw useradd courier to add a user and group for Courier-IMAP. You won’t actually have to add a new user and group for Courier. You could just use the same as for, for example, Exim, but this isn’t really recommended, due to the fact that it’s against good system security, even though we are running in a jail.

First install authlib, Courier depends on it:

$ su courier
$ fetch http://belnet.dl.sourceforge.net/sourceforge/courier/courier-authlib-0.58.tar.bz2

$ tar xfvj courier-authlib-0.58.tar.bz2
$ cd courier-authlib-0.58
$ ./configure –without-authpipe –without-authcustom –without-authvchkpw –without-authshadow –without-authpwd –without-authldap –without-authpam
$ make
# make install
# make install-configure

I stripped all unneccessary authentication modules using the –without options. Next, compile the IMAP portion of Courier. I live in Finland, and the charset here is iso-8859-15. UTF-8 is probably the future.

I installed this on FreeBSD, and therefore I use gmake everywhere, as recommended in Courier-IMAP’s INSTALL file. On Linux, you can probably safely use make.

As were authenticating against a MySQL database, we can safely disable all
other authentication modules in the configure command.

$ fetch http://ovh.dl.sourceforge.net/sourceforge/courier/courier-imap-4.1.0.tar.bz2

$ tar xfvj courier-imap-4.1.0.tar.bz2
$ cd courier-imap-4.1.0
$ ./configure –enable-unicode=iso-8859-1,utf-8,iso-8859-15 \
–bindir=/usr/local/bin –mandir=/usr/local/man \
–with-mailuser=courier \
–with-mailgroup=mail –with-mysql-libs=/usr/lib –with-mysql-includes=/usr/include
$ gmake

Run authlib/authinfo to check that authmysql was
(the only module) compiled in.

$ gmake check
# umask 022
# gmake install-strip

# gmake install-configure

If gmake install-strip fails, use gmake install
instead, or respectively make install-strip and make
install
on Linux.

4.2. SQL tables for Courier-IMAP/Exim/Amavisd-new

My SQL setup is a bit different that the one recommended by Courier, in order
preserve the similarity with my
Exim, Amavis, Qpopper with TLS+MySQL Auth Mini How-To
, and due to the fact
that I use the same table for Exim and Amavisd-new, as well. Note that the
"quota" column is not used by Courier-IMAP in my setup, but Exim. Neither
is the "id" column used by Courier-IMAP, but Amavisd-new. I replaced
Courier-IMAP's "id" column with the "email" column, which will also be used by
Amavisd-new. I also dislike the idea of having plaintext passwords in a database
(or for that matter, the use of plaintext passwords overall), so therefore I
omitted the "plain" column from the table, as it is not needed.

$ mysql -u root -p
mysql> create database mail;
mysql> use mail;
mysql> CREATE TABLE users (
        id int(10) unsigned DEFAULT '0' NOT NULL auto_increment,
        priority int(10) DEFAULT '7' NOT NULL,
        policy_id int(10) unsigned DEFAULT '1' NOT NULL,
        email varchar(128) NOT NULL,
        crypt varchar(128) NOT NULL,
        fullname varchar(128),
        uid int(10) unsigned DEFAULT '1004' NOT NULL,
        gid int(10) unsigned DEFAULT '1004' NOT NULL,
        home char(255) NOT NULL,
        quota varchar(5),
        quotawarn char(3),
        arsubject varchar(255),
        artext blob,
        autoresponder char(3),
        PRIMARY KEY (id)
       );

At this point, it is suitable to grant permission to Exim, Courier-IMAP and
Amavisd-new to access the database. This is done in MySQL with
the GRANT command, like this:

mysql> GRANT SELECT ON mail.* TO mail@localhost IDENTIFIED BY 'mysqlPassword';

This creates a new SQL user with the username "mail" and password
"mysqlPassword" and grants it right to execute SELECT queries on all tables
under the "mail" database. Under no circumstances use the root SQL account for
Exim, Courier-IMAP or Amavisd-new!

In my setup, I will use the /var/mail directories for storing the
Maildirs. However, some people might disagree with me, saying that the
/var/mail directories should only be used for traditional mbox
spools and that Maildirs should be stored under users' homedirs. That's up to
you to decide.

While we're at it, lets add a test user to the database. An insert query
could look something like this (1004 are the user/group ids for my newly
created "courier" user/group, these will probably be different on your
system):

mysql> INSERT INTO users (email, crypt, uid, gid, home) VALUES \
 ('
 


', ENCRYPT('password'), '1004', '1004', '/var/mail/mydomain.com/mymail/');

Each time you add a new user to the SQL database, it might be a good idea to
create the user's Maildir. Do this by running the command
mkdir -m 0700 Maildir; mkdir -m 0700 Maildir/{cur,new,tmp} in the
directory you specified in the SQL database. It is true that by default, Exim
automatically creates the "new" directory if it doesn't exist when a delivery
is made, but you still need to create the other ones.

We still need to edit the /usr/lib/courier-imap/etc/authmysqlrc
(or whatever) file to reflect our SQL setup. You can take a
look at mine for a sample configuration.

5. TLS/SSL Certificates

Now it's time to create the TLS/SSL certificates for use with Courier-IMAP's
TLS/SSL support. These are so called "self-signed" certificates, since I
didn't want to pay for certificates signed by some authority, as these are
quite sufficient for my use. However, these will generate a warning message
on some e-mail clients (Outlook Express being one of them) each time a Maildir
is accessed using TLS/SSL encryption, unless you install the certifiacte authority's public key in the e-mail client beforehand.

New CA:

# cd
# /usr/lib/ssl/misc/CA.pl -newca
# DIR=`pwd`/openssl

Now that you have the CA, generate key and certificate request.

The following is from http://milliwaysconsulting.net/support/systems/courier-ssl.html

Generate private key:

# openssl genrsa -out $DIR/courier.key 1024

Generate certificate signing request:

# openssl req -new -key $DIR/courier.key -out $DIR/courier.csr

Sign the certificarte using the newly-created CA (sign.sh can be found iun mod_ssl):

# ./sign.sh $DIR/courier.csr

Edit courier.crt in a text editor, delete everything up to ------ BEGIN... Save, exit editor.
Combine key and cert to one file using cat.

# cat $DIR/courier.crt $DIR/courier.key > /var/jail/10.0.1.2/usr/local/courier-imap/etc/pop3d.pem

You can now delete courier.csr, courier.crt and courier.key.

6. Exim configuration

Amavisd-new and exiscan patches are no longer needed for this kind of setup. exiscan does pretty much the same thing as amavisd-new, and as of Exim 4.50, the exiscan patch is integrated into Exim itself. And lets face it; more daemons mean more possible problems.

There are a few caveats;

  • $local_part and $domain are only available in the RCPT ACL (NOT in DATA). We need to set some variables that control spam scanning and anti-virus. For this purpose Exim has acl_m0 thought acl_m9. In my configuration, I decided to use the following scheme for fine-grained SQL control of mail account settings:

    acl_m0

    malware
    acl_m1 spam

7. Testing it all

Let's create a Daemontools service directory for Exim.

# mkdir /service/exim

Create a file /service/exim/run with the following content:

#!/bin/sh
exec jail /usr/jail/10.0.0.10/ mail 10.0.0.10 /usr/local/bin/exim -bdf

Exim's -bdf argument prevents Exim from going to background when
started. Daemontools likes it this way. Don't forget to give exec permissions
to the file:

# chmod +x /service/exim/run

Daemontools should now bring up Exim within five seconds. Use ps
to check that exim was actually started and running. Kill Exim's PID to see if
Daemontools brings it up again. Also check the output of svstat exim.

Next, do the same for SpamAssassin:

# mkdir /service/spamassassin

Edit /service/spamassassin/run to look like the following:

#!/bin/sh
exec spamd -q -x --socketpath=/var/run/spamd.sock
# chmod +x /service/spamassassin/run

Once you've got that working, it's time to fire up the Courier-IMAP daemon:

$ /usr/lib/courier-imap/libexec/imapd.rc start

Telnet to localhost port 143. Courier-IMAP should answer something like
this:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK Courier-IMAP ready. Copyright 1998-2003 Double Precision, Inc.  See COPYING for distribution information.

If it does, then you know that the IMAP daemon should be working. If there is
no output, use ps or top to see if there is a Courier-IMAP
process and check Courier-IMAP's log files (by default /var/log/maillog

on FreeBSD, in Linux you'd probably want to check /var/log/syslog).
Next, let's try the SSL enabled IMAP daemon. Start it using the command:

$ /usr/lib/courier-imap/libexec/imapd-ssl.rc start

Telnet to localhost port 993, and IMAPD-SSL should answer. Next, let's try
the POP3 daemon. Start it with the command:

$ /usr/lib/courier-imap/libexec/pop3d.rc start

Telnet to localhost port 110, and the POP3 daemon should answer. Finally,
let's try the SSL enabled POP3 daemon. Start it using the command:

$ /usr/lib/courier-imap/libexec/pop3d-ssl.rc start

After that, telnet to localhost port 995, and POP3-SSL should answer.

To test the anti-virus setup, you can use declude.com's Eicar test mail.


10. Conclusion

Hope you enjoy your brand new, shining, high-performance e-mail server ;-)

10.1. Further Documentation

Tags: , , ,

One Response to “Exim, Courier-IMAP with TLS+MySQL Auth How-To”

  1. to domain name says:

    hi guys…

    hi guysI would like to thank you for the efforts you have made in writing this article. I am hoping the same best work from you in the future as well and i have start my own blog now, , thanks for your effort…

Leave a Reply

Spam protection by WP Captcha-Free