====== The Cyrus-Imapd Chapter ====== The article describes the installation and configuration of a secured cyrus-imapd server on Debian Squeeze. Its goal is to describe the steps to get a running IMAP server, with SSL and LDAP support. It does not include the configuration of Postfix and OpenLDAP. Those onces are described in other articles of this wiki. As shown in the architecture diagram below, Cyrus-Imap will be using many others component of the system, such as OpenLDAP for account information storage, postfix for everything related to SMTP and LMTP, and so on... {{:en:ressources:dossiers:cyrus:cyrus-arch.png|}} Cyrus Imapd's job is mainly to store emails, apply rules to them (via sieve and ACLs), and provide network access (via imap). And we will stick to this. ===== The basis ===== I assume you are familiar with the Imap theory. So let's get started directly with, as always... # aptitude install cyrus-imapd-2.2 Life should always be that simple ! So we now have to major files : **/etc/cyrus.conf** and **/etc/imapd.conf**. The first one declares the services to start, and the second one contains the configuration parameters. ===== Selecting Cyrus Imapd services in cyrus.conf ===== Cyrus-imapd starts a bunch of services by default: samchiel:~# netstat -taupen|grep cyrmaster tcp 0 0 0.0.0.0:110 0.0.0.0:* LISTEN 0 35730 26003/cyrmaster tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 0 35723 26003/cyrmaster tcp 0 0 0.0.0.0:119 0.0.0.0:* LISTEN 0 35737 26003/cyrmaster tcp 0 0 127.0.0.1:4190 0.0.0.0:* LISTEN 0 35750 26003/cyrmaster tcp6 0 0 :::110 :::* LISTEN 0 35732 26003/cyrmaster tcp6 0 0 :::143 :::* LISTEN 0 35725 26003/cyrmaster tcp6 0 0 :::119 :::* LISTEN 0 35739 26003/cyrmaster tcp6 0 0 ::1:4190 :::* LISTEN 0 35748 26003/cyrmaster * 110 is pop3 (deprecated) * 143 is imap (but we will prefer imapS) * 119 is nntp (USENET News Transfer Protocol) * 4190 is sieve (the email filtering daemon) What I want is the following: * imaps open to the world, with a SSL certificate I will generate locally * imap open on localhost only (I intend to put a webmail on this host, no need to overload the server with useless local SSL connections) * sieve open on localhost only (sieve rules will be managed through the webmail) The rest, I can get rid of. So my **/etc/cyrus.conf** file will look as follow (once the commented lines removed): START { recover cmd="/usr/sbin/ctl_cyrusdb -r" delprune cmd="/usr/sbin/cyr_expire -E 3" tlsprune cmd="/usr/sbin/tls_prune" } SERVICES { imap cmd="imapd -U 30" listen="localhost:imap" prefork=0 maxchild=10 imaps cmd="imapd -s -U 30" listen="imaps" prefork=0 maxchild=10 lmtp cmd="lmtpd" listen="localhost:lmtp" prefork=0 maxchild=3 sieve cmd="timsieved" listen="localhost:sieve" prefork=0 maxchild=10 } EVENTS { checkpoint cmd="/usr/sbin/ctl_cyrusdb -c" period=30 delprune cmd="/usr/sbin/cyr_expire -E 3" at=0401 tlsprune cmd="/usr/sbin/tls_prune" at=0401 } OK, 3 different sections with 3 different types of entries. The man page of cyrus.conf gives us some more information on thoses: START This section lists the processes to run before any SERVICES are spawned. This section is typically used to initialize databases and start long running daemons. SERVICES This section is the heart of the /etc/cyrus.conf file. It lists the processes that should be spawned to handle client connections made on certain Internet/UNIX sockets. EVENTS This section lists processes that should be run at specific intervals, similar to cron jobs. This section is typically used to perform scheduled cleanup/maintenance. So, with our new config file, we can restart cyrus and check the open port. It should look like this: # /etc/init.d/cyrus2.2 restart Stopping Cyrus IMAPd: cyrmaster. Waiting for complete shutdown... Starting Cyrus IMAPd: cyrmaster. # netstat -taupen |grep cyrmaster tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN 0 50401 27013/cyrmaster tcp 0 0 127.0.0.1:143 0.0.0.0:* LISTEN 0 50396 27013/cyrmaster tcp 0 0 127.0.0.1:4190 0.0.0.0:* LISTEN 0 50411 27013/cyrmaster tcp6 0 0 :::993 :::* LISTEN 0 50403 27013/cyrmaster tcp6 0 0 ::1:143 :::* LISTEN 0 50394 27013/cyrmaster tcp6 0 0 ::1:4190 :::* LISTEN 0 50409 27013/cyrmaster Good to go... ===== Configuring Cyrus Imapd in imapd.conf ===== **/etc/imapd.conf** contains all the configuration parameters. The Debian version of this file is very well commented, but it doesn't explain the underlying logic of cyrus-imapd. Imapd is not only an imap server, as we saw before, it supports nntp, sieve, pop3, notifyd and so on... All of those services are email related, and the main one is imap v4. The goal of cyrus-imapd is to provide an implementation of those protocol and thus serve email stored on a local storage to a network client through a network protocol. cyrus-imapd needs to rely an other softwares to perform mail delivery and authentication. For mail delivery, feel free to take a look at the articles on Postfix on this wiki. For the authentication, the cyrus team provides another software: cyrus-sasl. SASL stands for **S**imple **A**uthentication and **S**ecurity **L**ayer. Typically, cyrus-imapd will receive and authentication requests through an imap command, and will pass it along to cyrus-sasl to verify this authentication. Will see SASL in detail later. For now, we need to configure the imap service itself. Configuration of **/etc/imapd.conf**: # grep -v "^#" /etc/imapd.conf |grep -v "^$" configdirectory: /var/lib/cyrus defaultpartition: default partition-default: /var/spool/cyrus/mail altnamespace: no unixhierarchysep: no reject8bit: no munge8bit: yes lmtp_downcase_rcpt: yes admins: cyrus allowanonymouslogin: no popminpoll: 1 autocreatequota: 0 umask: 077 sieveusehomedir: false sievedir: /var/spool/sieve hashimapspool: true allowplaintext: yes sasl_pwcheck_method: auxprop sasl_auxprop_plugin: ldapdb sasl_auto_transition: no sasl_ldapdb_uri: ldap://localhost sasl_ldapdb_id: cyrus sasl_ldapdb_pw: highsecuritypassword sasl_ldapdb_mech: DIGEST-MD5 tls_cert_file: /etc/ssl/certs/imap/imap.certificate.pem tls_key_file: /etc/ssl/certs/imap/imap.privatekey.key tls_ca_file: /etc/ssl/certs/imap/rootca-certificate.crt tls_session_timeout: 1440 tls_cipher_list: TLSv1+HIGH:!aNULL:@STRENGTH lmtpsocket: /var/run/cyrus/socket/lmtp idlemethod: poll idlesocket: /var/run/cyrus/socket/idle notifysocket: /var/run/cyrus/socket/notify syslog_prefix: cyrus Let's take a closer look at this file. ==== configdirectory ==== This contains internal databases and files related to imapd internal work. You will find there copies of databases, user 'seen' files (the seen/not seen emails), and so on... This is what I have on another server. |-- annotations.db |-- db | |-- __db.001 | |-- __db.002 | |-- __db.003 | |-- __db.004 | |-- __db.005 | |-- log.0000000011 | `-- skipstamp |-- db.backup1 | |-- annotations.db | |-- log.0000000011 | `-- mailboxes.db |-- db.backup2 | |-- annotations.db | |-- log.0000000011 | `-- mailboxes.db |-- deliver.db |-- log |-- mailboxes.db |-- msg |-- proc | |-- 10012 [...] ==== defaultpartition and partition-default ==== A partition is the location of the file storage, typically a path on your server (with //some// space available). Both values work together, the first one declares the name of the default partition (defaultpartition: ////) and the second one is the expected value (partition-////). So, here, we store all the files in the default partition which is in **/var/spool/cyrus/mail**. (feel free to change that). ==== admins ==== The name(s) of the administrator(s). We will see later that we need to create this guy in the SASL database. ==== hashimapspool ==== Define the hashing for the email partition. This is the option that will decide on your folder hierarchy. If this is on, you will have a partition that looks like this: . |-- a |-- b | `-- user | `-- bogdana | |-- Draft | |-- INBOX | | `-- Trash | |-- Sent | |-- Spam | |-- Trash |-- c |-- d |-- e |-- f | `-- user | `-- franck | |-- Drafts | |-- Junk | |-- Sent | `-- Trash |-- g |-- h |-- i |-- j | `-- user | |-- jeannot | |-- jerome | | |-- Brouillons | | |-- Corbeille | | |-- Exemple | | |-- Trash | | `-- sent | `-- julien | |-- BugTraq | |-- Drafts | |-- Golf | |-- La Sauce | |-- Linuxwall | |-- Lists | | |-- Full Disclosure | | |-- Metasploit | | |-- Netfilter | | | `-- devel | | |-- OpenCA | | |-- OpenSSL | | |-- OpenVPN | | |-- cyrus | | |-- debian | |-- Rapports_Systemes | |-- SQT Group | |-- Spam | |-- Trash | |-- UMD | |-- drafts | |-- jobs | `-- sent-mail |-- k |-- l |-- m |-- n | `-- user | `-- njm | |-- Drafts | |-- Junk | |-- Sent | `-- Trash |-- o |-- p |-- q |-- r |-- s |-- t |-- u |-- v |-- w |-- x |-- y `-- z ==== sieveusehomedir and sievedir ==== We will be using the sieve server. Sieve is a service that allow a user to set up filter on his incoming emails. This is very useful to sort your emails in folder (like the mailing list) when they reach the server. And since it's done by cyrus-imapd directly, it doesn't overload your email client. Sieve needs to store your filtering rules somewhere, and this in what //sievedir// defines. It will contain scripts and bytecodes. The scripts are just text files that look like this: # rule:[postfix] elsif anyof (header :contains "To" "postfix-users", header :contains "Cc" "postfix-users") { fileinto "INBOX.Lists.postfix"; } If you want to read more about sieve, take a look here: [[http://wiki.linuxwall.info/doku.php/en:ressources:astuces:sieve|Filter your emails with sieve]] ==== sasl_* ==== // The mechanism used by the server to verify plaintext passwords. Possible values include "auxprop", "saslauthd", and "pwcheck". // Here, we want to use **auxprop**. Auxprop will call an external SASL plugin to connect to the authentication backend. Since the authentication backend we will use is a ldap directory, the corresponding auxprop module will be **ldapdb**. For now, we focus on imapd and we will configure the authentication later. {{:en:ressources:dossiers:cyrus:ldapdb.png|}} ==== tls_* ==== The tls_* parameters are used to configure the imaps access. You need a certificate and a private key to configure this. If you do not know what a certificate and a private key are, __do not configure this__. (And read some litterature on openssl, pki and X.509 certificates before) TLS session can be costly to renegociate, therefore, the parameter tls_session_timeout is particularly interesting because it allows cyrus-imapd to reuse a previously negociated TLS session during half an hour without renegociating the master key. Once TLS sessions are negociated, there is very little difference between symetrics algorithms. Using a 128 bit key or a 256 bit key in AES won't make a huge difference. Thus, I leave the default parameter for tls_cipher_list that impose high security algorithm. Or, more precisely: # openssl ciphers 'TLSv1+HIGH:!aNULL' DHE-RSA-AES256-SHA DHE-DSS-AES256-SHA AES256-SHA DHE-RSA-AES128-SHA DHE-DSS-AES128-SHA AES128-SHA EDH-RSA-DES-CBC3-SHA EDH-DSS-DES-CBC3-SHA DES-CBC3-SHA ==== and the rest ==== There is still a bunch of configuration parameters I didn't describe here. For them, the default values are alright. The comments inside the file are clear enough, and if not a little **man imapd.conf** should satisfy your curiosity. ==== Restart and check ==== We have imap open on localhost, and imaps globally. Let's try to connect to the second one using the openssl client: # openssl s_client -connect localhost:993 CONNECTED(00000003) --- Certificate chain 0 s:/C=FR/ST=France/O=testdomain/CN=imap.testdomain.info i:/C=FR/ST=France/L=Paris/O=testdomain/CN=testdomain Root Certificate/emailAddress=root@testdomain.info 1 s:/C=FR/ST=France/L=Paris/O=testdomain/CN=testdomain oot Certificate/emailAddress=root@testdomain.info i:/C=FR/ST=France/L=Paris/O=testdomain/CN=testdomain Root Certificate/emailAddress=root@testdomain.info --- Server certificate -----BEGIN CERTIFICATE----- MIIFBjCCA+6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBoTELMAkGA1UEBhMCRlIx [...] MmTjsl7DE8AFpWru49udHC5AiQBD51Z3aNL9z849Wd0hcwM1QIulAMH5 -----END CERTIFICATE----- subject=/C=FR/ST=France/O=testdomain/CN=imap.testdomain.info issuer=/C=FR/ST=France/L=Paris/O=testdomain/CN=testdomain Root Certificate/emailAddress=root@testdomain.info --- No client certificate CA names sent --- SSL handshake has read 2419 bytes and written 444 bytes --- New, TLSv1/SSLv3, Cipher is AES256-SHA Server public key is 2048 bit Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES256-SHA Session-ID: F067E10CA08531374E7D0BF379A571F234A196B94C187CE1182E93259BFB022D Session-ID-ctx: Master-Key: B496E9DE5A5BF9B872AEFE1836B3B923DA2412A554EE08FE67091AFEDCF983F3F859B73D2F3F7FC61662BF3761A18577 Key-Arg: None Start Time: 1266508567 Timeout: 300 (sec) Verify return code: 19 (self signed certificate in certificate chain) --- * OK samchiel Cyrus IMAP4 v2.2.13-Debian-2.2.13-19 server ready This trace confirms our configuration. Only the very last line is from the IMAP protocol. All the rest is SSL junk. And we confirm that the cipher algorithm is AES256-SHA, which is pretty high security. So we now have a working IMAP server, but without any account. We then need to configure SASL and also OpenLDAP. ===== Cyrus SASL and OpenLDAP ===== There are many ways to store users's credentials. One of them is to have everything regarding our users into a LDAP directory and tell Cyrus-Imapd to query that directory. However, setting up LDAP querying in Cyrus-Imapd is not that straightforward. Imapd relies on Cyrus-SASL for everything that concerns authentication. SASL is the Simple Authentication and Security Layer, a method for adding authentication support to connection-based protocols. To use SASL, a protocol includes a command for identifying and authenticating a user to a server and for optionally negotiating protection of subsequent protocol interactions. If its use is negotiated, a security layer is inserted between the protocol and the connection. [[http://asg.web.cmu.edu/sasl/|source]] To connect to a LDAP directory, Cyrus-Imapd will need several things: - A SASL library with the ldapdb plugin activated - A //proxy// user to log into the directory - A proxy authorization rule in the directory The items 2 and 3 are described in **[[http://wiki.linuxwall.info/doku.php/en:ressources:dossiers:openldap:openldap_debian|The OpenLDAP Chapter]]** (section SASL). We will detail item 1 below. ==== Configuring ldapdb ==== We will need some additionnal components for this: The SASL binaries, and the LDAP library module for SASL. As always: # aptitude install sasl2-bin libsasl2-modules-ldap The package **sasl2-bin** installs also the saslauthd daemon. But we will not use this last one. However, we need this package for the saslpluginviewer binary, that will list the available authentication plugins activated on the system: # saslpluginviewer Installed SASL (server side) mechanisms are: LOGIN ANONYMOUS PLAIN DIGEST-MD5 NTLM CRAM-MD5 EXTERNAL [ .... ] The description is pretty long. The information we need is the list of **auxprop** modules: Installed auxprop mechanisms are: sasldb List of auxprop plugins follows Plugin "sasldb" , API version: 4 supports store: yes OK, so we miss **ldapdb**. To activate it, we have to add a file into **/usr/lib/sasl2/** that contains the location of the LDAP directory: # echo "ldapdb_uri: ldap://localhost" > /usr/lib/sasl2/pluginviewer.conf # cat /usr/lib/sasl2/pluginviewer.conf ldapdb_uri: ldap://localhost Now, check **saslpluginviewer** again. ldapdb should be available in the auxprop plugins. # saslpluginviewer [ ... ] Installed auxprop mechanisms are: ldapdb sasldb List of auxprop plugins follows Plugin "ldapdb" , API version: 4 supports store: yes [ ... ] ==== Back to imapd.conf ==== The ldapdb plugin is now available. Now, we need to tell imapd to connect to the LDAP directory using the ldapdb plugin. It also needs a username and a password. Make sure that the user you chose has the **Proxy Authorization** capability (as seen in [[http://wiki.linuxwall.info/doku.php/en:ressources:dossiers:openldap:openldap_debian#sasl_proxy_authorization|the OpenLDAP chapter]]). In clear, user 'cyrus' must have an attribute like **authzTo: ldap:///dc=example,dc=net??sub?(objectclass=inetOrgPerson)**. Then, in imapd.conf, the following parameters will do the job: # grep -E "sasl|ldap" /etc/imapd.conf |grep -v "^#" sasl_pwcheck_method: auxprop sasl_auxprop_plugin: ldapdb sasl_auto_transition: no sasl_ldapdb_uri: ldap://localhost sasl_ldapdb_id: cyrus sasl_ldapdb_pw: highsecuritypassword sasl_ldapdb_mech: DIGEST-MD5 We connect from cyrus-imapd to ldap://localhost using user cyrus and SASL mechanism DIGEST-MD5. Now restart cyrus with these parameters and try to login as user 'toto'. # openssl s_client -connect localhost:993 * OK samchiel Cyrus IMAP4 v2.2.13-Debian-2.2.13-19 server ready . login toto highsecuritypassword . OK User logged in . list "" "*" . OK Completed (0.000 secs 1 calls) That's a success ! Some more imap command here if you want to play around: [[http://bobpeers.com/technical/telnet_imap.php|Accessing IMAP email accounts using telnet]] In **/var/log/mail.info**, you see the following: May 10 13:11:28 samchiel cyrus/imap[4891]: login: localhost [127.0.0.1] toto plaintext User logged in In **/var/log/auth.log**: May 10 13:11:28 samchiel cyrus/imap[4891]: DIGEST-MD5 client step 2 May 10 13:11:28 samchiel cyrus/imap[4891]: DIGEST-MD5 client step 2 May 10 13:11:28 samchiel cyrus/imap[4891]: DIGEST-MD5 client step 3 And in **/var/log/slapd.log**: May 10 13:11:28 samchiel slapd[2482]: conn=40 fd=16 ACCEPT from IP=[::1]:58180 (IP=[::]:389) May 10 13:11:28 samchiel slapd[2482]: conn=40 op=0 BIND dn="" method=163 May 10 13:11:28 samchiel slapd[2482]: conn=40 op=0 RESULT tag=97 err=14 text=SASL(0): successful result: May 10 13:11:28 samchiel slapd[2482]: conn=40 op=1 BIND dn="" method=163 May 10 13:11:28 samchiel slapd[2482]: conn=40 op=1 BIND authcid="cyrus" authzid="cyrus" May 10 13:11:28 samchiel slapd[2482]: conn=40 op=1 BIND dn="cn=cyrus administrator,ou=people,dc=example,dc=net" mech=DIGEST-MD5 sasl_ssf=128 ssf=128 May 10 13:11:28 samchiel slapd[2482]: conn=40 op=1 RESULT tag=97 err=0 text= May 10 13:11:28 samchiel slapd[2482]: conn=40 op=2 PROXYAUTHZ dn="cn=toto tata,ou=people,dc=example,dc=net" May 10 13:11:28 samchiel slapd[2482]: conn=40 op=2 EXT oid=1.3.6.1.4.1.4203.1.11.3 May 10 13:11:28 samchiel slapd[2482]: conn=40 op=2 WHOAMI May 10 13:11:28 samchiel slapd[2482]: conn=40 op=2 RESULT oid= err=0 text= May 10 13:11:28 samchiel slapd[2482]: conn=40 op=3 PROXYAUTHZ dn="cn=toto tata,ou=people,dc=example,dc=net" May 10 13:11:28 samchiel slapd[2482]: conn=40 op=3 SRCH base="cn=toto tata,ou=people,dc=example,dc=net" scope=0 deref=0 fil ter="(objectClass=*)" May 10 13:11:28 samchiel slapd[2482]: conn=40 op=3 SRCH attr=userPassword cmusaslsecretPLAIN May 10 13:11:28 samchiel slapd[2482]: conn=40 op=3 SEARCH RESULT tag=101 err=0 nentries=1 text= May 10 13:11:28 samchiel slapd[2482]: conn=40 op=4 UNBIND May 10 13:11:28 samchiel slapd[2482]: conn=40 fd=16 closed As explained in the OpenLDAP chapter, your passwords must be stored in cleartext in the LDAP directory. This is necessary for DIGEST-MD5 to work. ===== Create the mailboxes ===== Now that we have a working authentication backend, to create the mailboxes, we need to use the Cyrus Administration tools. # apt-get install cyrus-admin-2.2 This will install the 'cyradm' tool, which is in fact a Perl module. cyradm - Cyrus administration shell, alter ego of Cyrus::IMAP::Shell