Search

Paranoid Penguin - Secure Mail with LDAP and IMAP, Part II

In the first part of this series on using LDAP with the Cyrus IMAP mail
delivery server (LJ, November 2003),
we got as far as installing and setting up Cyrus
IMAP and Cyrus SASL. In this article, we add some users to Cyrus IMAP
and configure Postfix to deliver mail to the Cyrus IMAP server.

Cyrus IMAP Documentation

Before we dive back in to Cyrus IMAP configuration and administration,
a note about documentation. Cyrus IMAP comes with an administrator's
manual in HTML format. In the SuSE distribution, the manual is in
/usr/share/doc/packages/cyrus-imapd/doc, and in Simon
Matter's Red Hat SRPM distribution (see Part I of this article) it's
in /usr/share/doc/cyrus-imapd-2.1.12. The link
misleadingly labeled Installation actually leads not only to Cyrus
installation instructions but to configuration and administration
instructions as well.
Besides this documentation, several man pages also are included with
Cyrus IMAP, most notably imapd.conf(5), imapd(8) and
cyradm(1).

In addition to Cyrus IMAP's included documentation, I recommend the book
Managing IMAP by Dianna and Kevin Mullet
(O'Reilly & Associates,
2000). As far as I know, it's the only book dedicated to IMAP. Although
its coverage of Cyrus IMAP doesn't extend to LDAP, it's a well-written
book that clearly explains IMAP concepts and Cyrus IMAP administration;
it also covers UW-IMAP in some detail.

Using cyradm

Cyrus IMAP comes with a Perl script, cyradmn, that provides the most
convenient way to create and manage user mailboxes.
You should understand several things before using cyradm.
First, you should run cyradm from any account with which
you also read e-mail. In other words, you never should use
an IMAP administrative account as an e-mail account. Due to unusual
write-access permissions, using such accounts to read or send e-mail can
have strange negative effects on your server. As we learned last time,
Cyrus administrative accounts are named according to the variable admins in
/etc/imapd.conf.

Second, cyradm uses the same authentication method as does the rest of
Cyrus IMAP. In my previous column, we determined this by setting
/etc/imapd.conf's variable sasl_pwcheck_method to saslauthd
and by editing /etc/sysconfig/saslauthd to use either LDAP or,
in the case of SuSE, to use PAM. PAM itself can be configured to use
LDAP for IMAP transactions in the files /etc/pam.d/imap and
/etc/openldap/ldap.conf. In short, cyradm identifies and
authenticates administrative users with LDAP, assuming you've correctly
configured LDAP support in Cyrus IMAP, as described last time.

Finally, to authenticate, cyradm performs an LDAP auth lookup
against your user name and password, using the LDAP attribute UID as
the search criterion. For each user account you want to
allow to run cyradm, therefore, the LDAP record needs to contain definitions
for both UID and userPassword. UID is a required attribute and
userPassword is an allowed attribute in the posixAccount Object Class,
so all IMAP user accounts need to be associated with posixAccount.

This last point has another important ramification: in your OpenLDAP
server's /etc/openldap/slapd.conf file, you need to have
access control list (ACL) statements granting auth access to the
userPassword attribute for whatever LDAP user your IMAP server
(or its saslauthd process) uses to bind to the LDAP server (that is,
to perform authentications). LDAP ACL statements are described in the
slapd.conf(5) man page and in my article “Authenticate with
LDAP, Part III” (LJ, September 2003).

cyradm usually is run as an administrative shell rather than as a command,
per se. When you invoke cyradm, supplying your user name plus the host
you wish to administer, it prompts you for a password. On successful
authentication, it begins an interactive session with its own commands
and help screen. cyradm also can be run non-interactively; see the cyradm(1) man page for information on using cyradm for scripting.

The simplest invocation of cyradm is:

bash-$> cyradm --user usernamehostname

If you're running cyradm on the same host on which Cyrus IMAP is running, you
can use the hostname localhost. If the server you want to administer is
a remote host, however, specify its hostname or IP address. By default,
cyradm attempts to connect to it over TCP port 143. Because Cyrus IMAP
uses this port for clear-text communication, use the
--port option to specify TCP port 993 for TLS-encrypted communications
instead, like this: --port 993. Personally, in such
situations I find it simplest to connect to my remote IMAP servers with SSH and then
run cyradm locally on the remote host using my SSH session.

Suppose I want to run cyradm locally on my IMAP server and my
admin account is called mick_admin. The command would look like this:

Notice the localhost> prompt after a successful login: I'm now logged in
to a cyradm shell session. To see a complete list of available commands,
all I need to do is type ? or
help. There are 20 commands in all,
and each can be abbreviated, sometimes in two different ways. The help
screen lists all versions of each command.

Creating Mailboxes with cyradm

To create a mailbox, I can use the command
createmailbox.
Alternatively, I can use the abbreviation create or
even a simple
cm, like this:

localhost> cm user.bwooster
localhost>

This is the very model of command-line efficiency, but notice that the
user name corresponding to our new mailbox isn't really
user.bwooster—it's simply bwooster. The user. prefix must be used for all mailboxes
you create in Cyrus IMAP. Thus, to create a mailbox for the user
bubba, I'd use the command cm user.bubba. To then create
subdirectories for that mailbox, I'd use cm
user.bubba.sent,
cm user.bubba.drafts and so forth.

This user. prefix is visible only to Cyrus and to its administrators. In
fact, when our user Bubba connects to the server with Evolution or some
other IMAP client, rather than user.bubba he simply sees a folder
named Inbox, even though its real name is user.bubba. Similarly,
submailboxes appear as sent, drafts and so on, indented
beneath Inbox.

Another thing worth noting about the e-mail account creation command is the lack of any feedback
whatsoever from Cyrus upon successful completion.
If you're like me, you find this unnerving; you
periodically want to use the listmailbox command,
lm for short, to see what you have:

localhost> lm
user.bwooster (\HasNoChildren)

Believe it or not, this is all we need to do with Cyrus IMAP
to allow user bwooster to receive and read his e-mail, assuming
there's an LDAP record with a UID of bwooster. In Cyrus IMAP,
creating a new user mailbox has the effect of creating that user's IMAP
account. But before I move on to the topic of configuring the Postfix
MTA to deliver e-mail to Cyrus IMAP, a few words about Cyrus IMAP ACLs.

Cyrus IMAP ACLs

Each mailbox in a Cyrus IMAP system can have one or more ACLs associated
with it in which each ACL defines which actions a given user may perform
on the referenced mailbox or folder. By default, a new mailbox has only
one ACL, one that grants the mailbox's owner full administrative rights
over the mailbox.

Interestingly, administrators by default have only lookup
and administer rights on the new mailbox. You can look up the name
of the mailbox using the listmailbox command, and you can set ACLs on
it. But if you need to delete the mailbox, you first must create an ACL
for the mailbox that grants your administrative account administrative
rights. This is a feature, not a bug; it helps prevent things from
getting deleted accidentally.

Continuing with our example, below are the commands for
removing the mailbox we just created, using our administrative account
mick_admin:

The second command issued here is of particular note; it begins
with the cyradm command setaclmailbox, which may be abbreviated
as sam or setacl. This is followed by the mailbox in question
(user.bwooster), in turn followed by the account name to which we wish
to grant (or deny) access, mick_admin in this case. Finally,
either a group of permission codes or a special string is indicated. In
this example,
we have the special string all, which is short for all
permissions. To delete the user.bwooster mailbox, it
would have been sufficient simply to specify c, for create or delete
mailbox or submailboxes.
Other possible ACL permissions are listed in Table 1.

ACLs are covered in detail in the cyradm(1) man page and are
explained in Cyrus IMAP's HTML documentation. I highly recommend that you
get into the habit of at least reviewing, if not always customizing, the
ACLs on each mailbox you create with cyradm. On some sites,
it may not be necessary for users to retain the default permission c. If
all user submailboxes (user.whomever.sent, user.whomever.saved and so on)
are created for them by you, for example, you may prefer that they not have
the ability to create new ones or delete them accidentally.

Configuring Postfix to Deliver to Cyrus IMAP

In Part I, I described the role of mail delivery agents (MDAs)
as delivering mail to mailboxes. Being an MDA, Cyrus IMAP
can deliver mail, but it first must receive that mail from a message
transfer agent (MTA). The most popular MTA is Sendmail, but a
simpler and more secure option is Wietse Venema's excellent Postfix
(www.postfix.org). As Postfix is my MTA of choice, and because
it's available either as the default MTA or as an option
in most major Linux distributions nowadays, it's the one I explain
in detail here.

Does your IMAP server need to reside on your
organization's SMTP relay? It can, but it doesn't have to.
It may make more sense from the standpoints
of security and performance to keep your SMTP
relay dedicated to that purpose. You then can have your
IMAP server run its own instance of Postfix that
receives mail from the dedicated SMTP relay rather
than directly from other networks' MTAs. In either
case, we assume the MTA from which IMAP receives its mail
is running on the same host as Cyrus IMAP.

Three files need to be edited in order to configure Postfix to
transfer mail to Cyrus. The first file is /etc/postfix/main.cf,
in which we need to add or uncomment this line:

mailbox_transport = cyrus

The second file we need to edit is /etc/postfix/master.cf,
in which we need to add or uncomment these two lines:

Actually, the second line may differ on your system; the syntax of
Cyrus' deliver program has changed over the years. If you installed
both Cyrus IMAP and Postfix from your Linux distribution's current CDs
or download site, the included /etc/postfix/master.cf file
should work without tweaking. If you installed either Cyrus IMAP or
Postfix from source code, however, you may need to do some tweaking and
Googling to get the second line exactly right. One key piece of the second
line is the path in argv=/usr/libexec/cyrus/deliver, which must point
to your local system's Cyrus deliver command.

The third and final Postfix file to edit is /etc/aliases; you may keep yours in /etc/postfix/aliases. Unless you're
using LDAP for alias lookups—a process too involved for this article,
but which I describe in the Sidebar—you need to have at least one
entry in aliases for each Cyrus mailbox, plus any aliases to
those mailboxes you need.
For our example user Bubba, /etc/aliases needs the line:

bubba: bubba

Simple enough, right? We omit the user. prefix; Cyrus mailboxes
are referred to by user name. If your Cyrus (LDAP) user names correspond
to local system user names, you don't need aliases entries for
those users. But part of Cyrus' attraction lies in its not requiring
users to have shell accounts.

If Bubba is our organization's marketing analyst, we also can add
the line:

marketing_weasel: bubba

After you edit your aliases file, don't forget to use the postalias
command to generate a new alias database:

bash-$> postalias hash:/etc/aliases

Postfix and LDAP

In this article I describe how to use LDAP to authenticate Cyrus IMAP
users, but I cover Postfix only so far as pointing Postfix mail delivery
at Cyrus. In fact, Postfix also has LDAP functionality: it can use LDAP
to resolve e-mail aliases to mailbox names.

That is, you can configure Postfix to check both its local
/etc/postfix/aliases database for e-mail-alias-to-mailbox-name mappings
and also to query the local LDAP service or a remote one. This can
save considerable administration time; rather than maintaining separate
alias and user databases, you can do it all in LDAP.

However, Postfix on Red Hat 7.3 (and possibly on later versions) doesn't
have LDAP support compiled in. To determine whether your version of your
distribution of choice has LDAP support compiled in its Postfix package,
use the command postconf -m. If LDAP isn't listed among the supported
Postfix modules, you need to uninstall your Postfix package and build
it yourself from source.

See www.postfix.org for more information and for Postfix source
code. Be sure to read the instructions in ./READMES/LDAP_README
in the Postfix source code, which explains how to compile in
Postfix's LDAP functionality—the default Postfix Makefile
does not do so automatically. Be sure also to read the file
/etc/postfix/samples/sample-ldap.cf, which contains the
parameters you need to add and configure in /etc/postfix/main.cf
to get LDAP alias lookups working. The latter step is extremely
important, and it may take some tinkering to get it working properly.

If you forego all this and choose instead to maintain Postfix's aliases
file separately (the old-fashioned way), then don't worry; using or not
using LDAP with Postfix has no ramifications whatsoever on Postfix's
ability to interact with your LDAP-authenticated Cyrus IMAP software.

Conclusion

This is not all you need to know in order to be a Cyrus IMAP administrator,
but hopefully it's enough to get started in building an LDAP-enabled
Cyrus IMAP server. With the topics we've covered or touched on in
these two articles, you now can go on to advanced topics, including
how to let users change their LDAP passwords;
how to let users use the LDAP server as an address book;
how to set up shared IMAP folders securely; and
how to set up a secure Web mail interface, such as SquirrelMail for
Cyrus IMAP.