Cyrus, SASL, and Multiple Domains
This took quite some time to figure out, but it was actually a lot simpler then I originally thought. Let me first give a huge thank you to Kevin M. Myer who originally had the foresight to see Cyrus' ability to do this, and who shared his knowledge with me. Now, lets start out with the advantages and disadvantages:
ADVANTAGES
- Cyrus IMAPd was designed to run with Cyrus SASL, so they work very well together. This is easy to configure and get working.
- Full support for multiple domains with the same username in multiple domains.
- Users can login with 'username' instead of 'username@domain.com'
DISADVANTAGES
- Web-cyradm doesn't work with this setup. At all. It will choke and die. We're not talking some small config changes, we're talking large amounts of rewriting. I'm working on adding SQL to this setup and them modifying web-cyradm to work with that setup.
- If you want the user to be able to change their password - you're a bit screwed. But I'm planning on hacking masssaslpasswd to work with this setup. Gime me time.
- Requires one IP per domain
COMPILING CYRUS
First thing we'll do is configure. In most cases this should be as simple as:
$ ./configure --with-auth=unix
You will need the --with-auth=unix, it doesn't mean you'll be using unix users for authentication, it means it CAN, and you'll need this for your first authentication and for testing.
After that do:
$ make depend
$ make all CFLAGS=-O
If you get problems with -lssl not being found and if your openssl installation is in /usr/local/ssl and it put your libraries in /usr/local/ssl/lib/openssl (default for source install), you may need to edit perl/sieve/acap/Makefile.PL and perl/sieve/managesieve/Makefile.PL and modify the LIBS line and add -L/usr/local/ssl/lib
. The configure script was able to pick this up for most Makefiles (although I had LD_LIBRARY_PATH set, I'm sure if I needed to), not not the perl ones for some reason. Once you do this, run make clean; made depend; make all CFLAGS=-O
and you should be set to go.
INSTALLING CYRUS
This part is easy. First make the necessary user and group:
# groupadd mail
# useradd -d /usr/cyrus -g mail cyrus
# passwd cyrus
And set a password for cyrus. When your done with that you can install with:
# make install
Additionally, there's a directory in the source called tools with necessary tools that don't get installed anywhere. These are good to keep around so I like to do the following, as root, from within the source directory:
# mkdir /usr/cyrus/bin/tools
# cp tools/* /usr/cyrus/bin/tools
# chown -R cyrus:mail /usr/cyrus/bin/tools
Now you will want to setup syslog to do some logging for you. We will start by doing lots of logging incase you run into trouble - but we'll drop down the level later. Edit /etc/syslog.conf and add these two lines:
local6.debug /var/log/imapd.log
auth.debug /var/log/auth.log
NOTE: Many systems already log auth stuff to a file (often auth.log) - look in your syslog.conf, if you already have a line like this, don't add it again. Either way you'll need the imapd line. Now we'll want to touch those files:
# touch /var/log/imapd.log /var/log/auth.log
Up until now, we've been following the included documentation almost word-for-word, but here's where we'll change a few things.
You'll need one IP address for each domain you want to host. For our examples, we'll use 1.1.1.1 for domain1.com and 1.1.1.2 for domain2.com. Obviously these need to be real IP addresses in your address space. So setup a virtual interface for your IP addresses (set these in your system configuration files so they will stay on reboot, for example, on redhat-like systems, you'll use the files in /etc/sysconfig/network-scripts/). Then edit your /etc/hosts file so it's something like:
127.0.0.1 localhost localhost.localdomain
1.1.1.1 mail.domain1.com
1.1.1.2 mail.domain2.com
This works equally well if you use subdomains instead of domains, by the way (i.e. mail1.domain.com and mail2.domain.com). Now, make a directory /etc/cyrus like this (as root):
# mkdir /etc/cyrus
# chown cyrus:mail /etc/cyrus
Then create config files for your domains (note these will be used instead of /etc/imapd.conf):
# touch /etc/cyrus/domain1.com.conf /etc/cyrus/domain2.com.conf
Now, edit each domain-specific configuration file giving it it's own configdirectory, partition-default, and servername. For example, domain1.conf would probably look like:
configdirectory: /var/imap/domain1.com
partition-default: /var/spool/imap/domain1.com
servername: mail.domain1.com
admins: cyrus
allowanonymouslogin: no
sasl_pwcheck_method: sasldb
Note the lack of a trailing slash... that's important. Here the servername attribute will determine the realm automatically. So when someone contacts the imapd daemons using this config file, it will allow the user to use just 'username' and realm is 'domain1.com.' Additionally configdirectory and partitiondirectory specify a unique directory for this specific domain eliminating any problems with similarly named mailboxes.
Repeat the above for domain2.com.conf (changing domain1 to domain2 where necessary).
Next we need to make our directories:
# cd /var
# mkdir imap
# chown cyrus:mail imap
# chmod 750 imap
# for domain in domain1.com domain2.com; do
> mkdir $domain;
> chown cyrus:mail $domain;
> chmod 750 $domain;
> done
# cd /var/spool
# mkdir imap
# chown cyrus:mail imap
# chmod 750 imap
# for domain in domain1.com domain2.com; do
> mkdir $domain;
> chown cyrus:mail $domain;
> chmod 750 $domain;
> done
#
Now the directories are almost done, a script from the source (that we copied to /usr/cyrus/bin/tools) can do the rest! So the next step is:
# su - cyrus
$ for domain in domain1.com domain2.com; do
> /usr/cyrus/bin/tools/mkimap /etc/cyrus/${domain}.conf;
> done;
$ exit
#
Although undocumented the mkimap script takes an arguement of the configuration file to use as a reference. One more directory related thing ONLY IF YOU ARE ON LINUX (all other unices, skip on down): We need to set the user, quota, and partition directories to update synchronously. This is fairly simple:
# cd /var/imap
# for domain in domain1.com domain2.com; do
> cd /var/imap/$domain;
> chattr +S user quota user/* quota/*;
> chattr +S /var/spool/imap/$domain /var/spool/imap/$domain/*;
> cd ..;
> done;
# chattr +S /var/spool/mqueue
Next ensure all of the following are in /etc/services:
pop3 110/tcp
imap 143/tcp
imsp 406/tcp
acap 674/tcp
imaps 993/tcp
pop3s 995/tcp
kpop 1109/tcp
sieve 2000/tcp
lmtp 2003/tcp
fud 4201/udp
Don't forget those need to be TABS and not SPACES! Also be sure to remove any entries from /etc/inetd.conf or /etc/xinetd.d/ for imap, imaps, pop3, pop3s, kpop, lmtp, or sieve.
Now we need to tell Cyrus about our domains and where to find their custom configuration files. First you'll want a base configration file to start with, so from the source directory do:
# cp master/conf/normal.conf /etc/cyrus.conf
Now, edit your /etc/cyrus.conf. Make one copy of everything for each domain you have. Make sure that the service names (the first word on the left) is ALWAYS UNIQUE! We will specify the specific configuration files we created above in this file, as well as specify an interface to bind to:
START {
# do not delete these entries!
mboxlist-d1 cmd="ctl_mboxlist -C /etc/cyrus/domain1.com.conf -r"
mboxlist-d2 cmd="ctl_mboxlist -C /etc/cyrus/domain2.com.conf -r"
deliver-d1 cmd="ctl_deliver -C /etc/cyrus/domain1.com.conf -r"
deliver-d2 cmd="ctl_deliver -C /etc/cyrus/domain2.com.conf -r"
# this is only necessary if using idled for IMAP IDLE
# idled cmd="idled"
}
SERVICES {
# DOMAIN 1
imap-d1 cmd="imapd -C /etc/cyrus/domain1.com.conf" listen="mail.domain1.com:imap" prefork=1
imaps-d1 cmd="imapd -s -C /etc/cyrus/domain1.com.conf" listen="mail.domain1.com:imaps" prefork=1
pop3s-d1 cmd="pop3d -s -C /etc/cyrus/domain1.com.conf" listen="mail.domain1.com:pop3s" prefork=1
lmtpunix-d1 cmd="lmtpd -C /etc/cyrus/domain1.com.conf" listen="/var/imap/domain1.com/socket/lmtp" prefork=0
# DOMAIN 2
imap-d2 cmd="imapd -C /etc/cyrus/domain2.com.conf" listen="mail.domain2.com:imap" prefork=1
imaps-d2 cmd="imapd -s -C /etc/cyrus/domain2.com.conf" listen="mail.domain2.com:imaps" prefork=1
pop3s-d2 cmd="pop3d -s -C /etc/cyrus/domain2.com.conf" listen="mail.domain2.com:pop3s" prefork=1
lmtpunix-d2 cmd="lmtpd -C /etc/cyrus/domain2.com.conf" listen="/var/imap/domain2.com/socket/lmtp" prefork=0
## I keep these here for refernce in case I ever want to use the services
# pop3 cmd="pop3d" listen="pop3" prefork=1
# pop3s cmd="pop3d -s" listen="pop3s" prefork=1
# sieve cmd="timsieved" listen="sieve" prefork=0
## at least one LMTP is required for delivery
# lmtp cmd="lmtpd" listen="lmtp" prefork=0
# lmtpunix cmd="lmtpd" listen="/var/imap/domain2.com/socket/lmtp" prefork=0
}
EVENTS {
# this is required
checkpoint-domain1 cmd="ctl_mboxlist -C /etc/cyrus/domain1.com.conf -c" period=30
checkpoint-domain2 cmd="ctl_mboxlist -C /etc/cyrus/domain2.com.conf -c" period=30
# this is only necessary if using duplicate delivery suppression
delprune-domain1 cmd="ctl_deliver -C /etc/cyrus/domain1.com.conf -E 3" period=1440
delprune-domain2 cmd="ctl_deliver -C /etc/cyrus/domain2.com.conf -E 3" period=1440
}
Now two copies of all your services will be launched - one using each configuration file, and hence using the right directories. Additionally all maintenance stuff will now launch once for each domain. Notice here that I have all the services preforked. It is up to you whether or not you want services preforked, but I recommend preforking them for testing.
NOTE: In the configuration file above I have included imaps and pop3s, the secure versions of imap and pop3. I have not yet added the section on setting up Cyrus to do secure imap and pop (expect it very shortly), so you should comment those lines out unless you can configure them for yourself).
We're almost done! Lets set an sasl password for cyrus in each domain:
# saslpasswd -u mail.domain1.com cyrus
Password:
# saslpasswd -u mail.domain2.com cyrus
Password:
Once that's done, we'll want to a test user to each domain with the same username to ensure everything works:
# su - cyrus
$ cyradm mail.domain1.com
mail.domain1.com> cm user.test
mail.domain1.com> quit
$ cyradm mail.domain2.com
mail.domain2.com> cm user.test
mail.domain2.com> quit
$ ^D
# saslpasswd -u mail.domain1.com test
Password:
# saslpasswd -u mail.domain2.com test
Note that -u to saslpasswd signifies "realm" (why it's -u, I don't know). You can double check this did what you thought it did with sasldblistusers
. I suggest using a different password for both users (while using the same username) to ensure you're seperate domains are setup properly.
Now we can fire up cyrus:
$ sdu -
# /usr/cyrus/bin/master &
Check everything is as you expect by doing netstat -an | grep LIST
and looking for cyrus listening in pop3 (110), and imap (143).
You can test authentication with:
# imtest -a test -u test -p imap mail.domain1.com
# imtest -a test -u test -p imap mail.domain2.com
If that works you should be set! Note that you may want to change your syslog.conf file and turn the debugging level down on local6 once you have this working. Don't forget to enable SSL, and configure your MTA, desribed below.
Making Cyrus Start On Boot
Unfortunately, Cyrus doesn't come with a SYSV init script. But that's ok, we can make one easily enough. Create a file called /etc/init.d/cyrus, and make it look something like this:
#!/bin/bash
# This script starts, stops, or restarts the
# Cyrus master.
# It was written by Phil Dibowitz
# http://home.earthlink.net/~jaymzh666/
case "$1" in
start)
echo -n "Starting Cyrus IMAPd..."
/usr/cyrus/bin/master &
echo $! > /var/run/cyrus.pid
echo "done"
;;
stop)
echo -n "Stopping Cyrus IMAPd..."
if [ -e /var/run/cyrus.pid ] ; then
kill `cat /var/run/cyrus.pid`
rm /var/run/cyrus.pid
echo "done"
else
echo "Sorry, can't find PID file, is it running?"
fi
;;
restart)
$0 stop
sleep 2
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
;;
esac
NOTE WELL: If you use postfix stop/restart will KILL postfix! You either need to modify this script, OR rename the postfix 'master' to 'pf_master' (or something like that), and change postfix's initscript, or some combination thereof.
So now you have an init script, lets make it active. Assuming your default runleve is 3, do:
cd /etc/rc3.d
ln -s ../init.d/cyrus S95cyrus
Adjust the number to taste. If you are on Solaris you should probably make a similar link to K05cyrus so the server stops when you leave runlevel 3.
Coming Soon
A patch for masssaslpasswd to support realms.
Adding SSL to Cyrus
I've put this on a different page.
Configuring SMTP
I've also moved this to it's own page.
Troubleshooting
Find troubleshooting info here.
Last Updated: 06/23/02
This page is © Phil Dibowitz 2001 - 2004