Set up a secure, scalable mail system that uses your existing LDAP server to authenticate IMAP users connecting from anywhere.
In the September 2003 issue, I ended a series on building an OpenLDAP server. With this current column and the next, I discuss in-depth one of LDAP's most compelling applications: providing authentication and address book information for IMAP users. These aren't more LDAP articles, though. The focus is on IMAP itself (Cyrus) and how it can leverage LDAP and its own security features to provide secure remote mail services. In other words, assume you already have (or know how to get) an LDAP server running and populated with user accounts.
First, a little background on IMAP's role in the e-mail food chain. IMAP, the Internet Message Access Protocol (specified in RFC 3501), is a protocol for mail delivery agents (MDAs). Whereas mail transport agents (MTAs), such as Postfix and Sendmail, move mail between networks, MDAs move mail from MTAs to destination mailboxes. To use a simile from my book Building Secure Servers With Linux, if an MTA is like a mail truck that moves mail between post offices, an MDA is like a letter carrier who delivers mail from the local post office to your house.
An IMAP-based MDA system has two parts: an IMAP server, which houses user mailboxes and receives mail from some MTA, and a group of users running IMAP client software. The three most popular open-source IMAP servers are University of Washington IMAP (UW IMAP), Cyrus IMAP from Carnegie Mellon University and Courier IMAP from Inter7 Internet Technologies. Popular IMAP client applications include Netscape/Mozilla Communicator, Ximian Evolution, Microsoft Outlook Express, KMail, mutt, pine and Apple Mac OS X Mail. IMAP clients are beyond the scope of our purposes here, but they're relatively easy to configure and use. Furthermore, most IMAP clients interoperate with most IMAP servers, so there isn't much to explain anyhow.
When building an IMAP system, the first choice an e-mail administrator must make is which server to use. What are the major differences between UW IMAP, Courier IMAP and Cyrus IMAP? Because features are added to the latter two fairly frequently, I'm going to cop out of telling you the answer in much detail. What I can say is:
Of the three, UW IMAP is the least flexible, as it supports only local-user-account mail file delivery; each local user's inbox is stored as a single flat file, /var/mail/myusername. This has two disadvantages: each mail user also must be a system user, and only one process may write to any given user's inbox at any given time, potentially resulting in file-locking complications.
Courier IMAP, actually part of the Courier Mail Server, was designed to support qmail's maildir system. In it, users have their own mail directories that store messages as individual files, which is better both from a performance standpoint and for obviating file-locking problems. Courier also can store mail in databases (see point 3); recent versions of Courier IMAP also support LDAP authentication.
Cyrus IMAP can be more complicated to set up than UW IMAP or Courier IMAP, mainly due to the Cyrus SASL authentication libraries on which it depends. However, Cyrus IMAP uses its own user and mail databases, both completely separate from the underlying OS, which allows you to add mail users without adding system user accounts. Also, using databases rather than flat files to store messages has an obvious performance benefit.
Personally, I've used Cyrus IMAP the most, so it is the MDA this article discusses. Refer to the features lists on the respective home pages of UW IMAP, Courier IMAP and Cyrus IMAP (see Resources) to decide which is the best fit for your environment. If your choice is different from mine, I hope some of the concepts in the rest of this article still are helpful to you.
As you know, I'm a big fan of binary packages due to the version control and patch management features provided by a good package manager. To my thinking, the major distributions' package managers all are quite good. Accordingly, I recommend you install Cyrus IMAP from your distribution's update service or installation media if at all possible. You also need Cyrus SASL, an authentication back end Cyrus IMAP requires. SMTP AUTH also uses this, so you already may have it installed.
Thus, in SuSE 8.2 the RPMs you need are cyrus-imapd and cyrus-sasl2. In Debian 3.0, you need the deb packages cyrus-common, cyrus-imapd, libsasl2 and sasl2-bin. Both SuSE and Debian users should be aware that earlier versions of your respective distributions may have Cyrus SASL packages based on old (pre-v2.0) versions of Cyrus SASL. The method of authenticating Cyrus IMAP against LDAP that I'm about to describe depends on SASL v2.0 or later, however. If your distribution version has a pre-2.0 SASL package, you may need to obtain and compile Cyrus SASL source code (available at ftp.andrew.cmu.edu/pub/cyrus-mail).
For Red Hat 9.0, you have to do a little more work than you do for the latest versions of SuSE or Debian, because Red Hat hasn't provided Cyrus IMAP packages since Red Hat 7.1. You should install the RPMs cyrus-sasl, cyrus-sasl-plain and cyrus-sasl-md5, which are part of the standard Red Hat 9.0 distribution. But, you need to get Cyrus IMAP itself in the form of an SRPM from home.teleport.ch/simix (graciously maintained and provided by Simon Matter in Switzerland).
If you've never dealt with source RPM (SRPM) files before, don't worry: the command to build a binary RPM from an SRPM is simply rpm --rebuild [--target yourarch] srpm.name.src.rpm, where srpm.name.src.rpm is the name of your SRPM file, and yourarch is your machine's architecture (such as i386, i586, i686). For example, when I ran this command on my Pentium III server I used rpm --rebuild --target i686 cyrus-imapd-2.1.12-7.src.rpm. Although the --target setting is optional, if you're going to have a large IMAP user database, optimizing Cyrus IMAP for your CPU type reportedly yields noticeable speed improvements over the default i386 build.
rpm then automatically compiles several new binary RPMs, customized for your local system architecture. These RPMs are written into /usr/src/redhat/RPMS/ (the precise subdirectory being whatever you specified after --target or i386/ by default). These RPMs are cyrus-imapd, cyrus-imapd-utils, cyrus-imapd-devel and perl-Cyrus. Install them with the rpm -Uvh filenames command.
We have two goals for the remainder of this article: to leverage our existing LDAP server to authenticate IMAP users and to configure our Cyrus IMAP server to accept only SSL-encrypted connections from end users. In past articles, I've extolled the virtues of centralizing authentication, so hopefully the value of using LDAP for this step is a given by now. I may have explained in earlier columns how dangerous clear-text e-mail retrieval is. In normal POP3 and IMAP transactions, your user name, password and all subsequent e-mail data traverse the network unencrypted. Therefore, they are exposed to eavesdropping attacks, especially if you retrieve your e-mail over a wireless network or from the Internet, the largest untrusted network of them all.
Back to SASL. Because Cyrus IMAP and Cyrus SASL both come from Carnegie Mellon University, and because the Cyrus team is understandably reluctant to reinvent the wheel, Cyrus IMAP depends on Cyrus SASL for its authentication functionality. This may seem confusing: isn't this function what we're using LDAP for? Yes it is, and SASL is indeed redundant insofar as SASL was designed to use its own user database to authenticate users.
Besides using its own database, however, SASL also can be used to broker authentication transactions with other authentication sources, such as PAM or LDAP. The simplest way to do this is by configuring saslauthd, the SASL authentication dæmon, whose behavior is controlled primarily by the file /etc/saslauthd.conf. Listing 1 shows a sample saslauthd.conf file.
ldap_servers specifies a space-delimited list of LDAP server URIs. In Listing 1, I've specified a clear-text LDAP connection to the local LDAP process. I instead could specify the encrypted ldaps protocol instead of ldap, a remote fully qualified domain name or IP address instead of localhost or both, as in ldaps://ldap.wiremonkeys.org.
ldap_search_base is the base (shared) part of your users' distinguished names (DNs). ldap_bind_dn and ldap_bind_pw are the DN and password you wish saslauthd to use to connect to your LDAP server. I recommend creating a special LDAP record for this purpose. In Listing 1, servers is the name of a special LDAP account with an objectClass of simpleSecurity Object, which means that besides its DN and objectClass, it has only one other attribute, userPassword.
If nothing else, having a dedicated server account in LDAP means that in your LDAP logs you can distinguish LDAP lookups by back-end processes and servers from end-user-initiated queries. This would be harder if IMAP used, for example, your personal LDAP account. For still more granular auditing, you even could use a different LDAP account for each service that performs LDAP queries, for example, cyrus and postfix.
Those are the options I use in my own /etc/saslauthd.conf file, but they aren't the only ones available to you. Cyrus SASL is distributed with a file, LDAP_SASLAUTHD, that documents these and other saslauthd.conf options. It's located in the source code distribution's saslauthd directory, but if you install SASL from a binary package, this file is placed wherever your distribution puts package documentation, probably some subdirectory of /usr/share/doc.
Besides editing /etc/saslauthd.conf, you also need to make sure saslauthd is started with the -a ldap option. On Red Hat, this is done by editing the file /etc/sysconfig/saslauthd so the parameter MECH is set to ldap. On SuSE, you edit the same file, but the parameter is called SASLAUTHD_AUTHMECH. Other distributions using sysconfig may have a different parameter name, and/or you may need to customize /etc/saslauthd. Again, the desired end result is for saslauthd to be passed the option -a ldap on startup.
Once you've configured and restarted saslauthd, you're ready to configure your IMAP service. As it happens, this is the easy part.
Most of Cyrus IMAP's behavior is controlled by a file named, predictably, /etc/imapd.conf. Listing 2 shows a sample imapd.conf file.
As you can see, many of the options in imapd.conf simply define paths to various things Cyrus IMAP needs. I won't cover these in detail (see the imapd.conf(5) man page for complete documentation), but let's at least discuss the nondefault settings in Listing 2.
admins: specifies the Cyrus IMAP users who may administer the IMAP system using the cyradm tool. (We'll cover cyradm in a future column.) By setting sasl_pwcheck_method: to saslauthd and by already having configured saslauthd to use LDAP, we've configured Cyrus IMAP to use LDAP for all authentication. So even though, for example, the user cyrus may exist on the local Linux system (in /etc/passwd), cyrus also needs to have an LDAP entry. When you run cyradmin and are prompted for cyrus' password, provide the password defined for Cyrus in the database, not cyrus' Linux password, if indeed the Linux account has one. In other words, any account names you specify after admins: must exist on whatever user database is specified by sasl_pwcheck_method.
When you installed Cyrus IMAP, whether from binary packages or from source code, a new user (cyrus) should have been created and given ownership of most Cyrus IMAP files. As with any other good service dæmon, Cyrus IMAP runs as a special nonprivileged user rather than root most of the time.
The three other settings in Listing 2 that I had to customize were tls_cert_file:, tls_key_file: and tls_cipher_list:. These are analogous to OpenLDAP's slapd.conf parameters TLSCertificateFile, TLSCertificateKeyFile and TLSCipherSuite, respectively. I mention this because the certificate/key files specified here are the same ones I used for OpenLDAP on this system. I did this because, in my example scenario, I'm running Cyrus IMAP on the same server on which I'm running OpenLDAP; there's no reason to use different server certificates and keys for each service. I did, however, copy both files from /etc/openldap to /var/lib/imap to simplify ownership/permissions management.
If my LDAP service was running on a separate host, I would create a new TLS certificate/key pair for my LDAP server, using exactly the same procedure I described in my August 2003 column:
openssl req -new -x509 -nodes -out slapdcert.pem \ -keyout slapdkey.pem -days 365
Regardless, remember to make both your certificate and key file owned by cyrus and your key file readable only by its owner.
If you install Cyrus IMAP from source, it uses default SSL keys that fail if an IMAP client attempts to connect using TLS rather than SSL encryption. Aside from the reliability issue, it's never, ever a good idea to use default (placeholder) certificates or keys for anything. Either leverage a server certificate/key you've created already (if applicable) or create a new pair. Your IMAP server will be both more reliable and more secure.
That's it; Cyrus IMAP now can be restarted (/etc/init.d/cyrus-imapd restart) and users added with cyradm. We'll have to save that part, plus getting your local MTA to deliver mail to IMAP, for next time.