Installing qmail and courier-imap on OpenBSD

Last updated: 2016-12-21T20:08:55-0500

uname -a
OpenBSD th.inri.net 6.0 GENERIC#2229 amd64

NOTE: th.inri.net is the name of my machine. If you use any of these files you will need to change every occurrence of th.inri.net to match your own system.

Why

Djb software is abandonware written by a political dissident. Furthermore, it was removed from the OpenBSD ports tree prior to the 9/11 attacks on New York City and Washington, D.C. Critical functionality is provided by unofficial patches of questionable origin. To make matters worse, most of the required software does not build on OpenBSD without patching. Therefore, to save myself trouble in the future, I have documented the process of acquiring, patching, installing, and configuring all of the software needed to stand up a fully functioning mail server under qmail and courier-imap on OpenBSD.

daemontools

We'll use daemontools to ensure qmail does not crash to death, but instead re-spawns upon failure. To install:

cd $HOME/src
wget http://openbsd.stanleylieber.com/src/daemontools-0.76.tar.gz
tar zxvf daemontools-0.76.tar.gz
cd admin/
wget http://openbsd.stanleylieber.com/src/daemontools-0.76.errno.patch
cd daemontools-0.76
patch -p1 <../daemontools-0.76.errno.patch
package/install

qmail

Features like SMTP authentication and SPF checking are not present in qmail as it was created by djb. To add these features we rely upon patches uploaded to the Internet by miscellaneous qmail users. I have not reviewed these at source level but they seem to work. YMMV.

cd $HOME/src
wget http://openbsd.stanleylieber.com/src/netqmail-1.06.patched.tgz

NOTE: Rather than manually patching a distribuion of qmail which essentially never changes, I have patched my copy in advance. My tarball, netqmail-1.06.patched, was created thusly:

# on freebsd
cd /usr/ports/mail/qmail
make config	# enable DNS_CNAME, SMTP_AUTH_PATCH, and SPF_PATCH
make extract
cd work
mv netqmail-1.06 netqmail-1.06.patched
tar zcvf netqmail-1.06.patched.tgz netqmail-1.06.patched
# and, on openbsd
tar zxvf netqmail-1.06.patched.tgz
cp qmail-1.03/auto_uids.c.dist netqmail-1.06/patched/
cp qmail-1.03/qbiff.c netqmail-1.06.patched/
cd netqmail-1.06.patched
ed Makefile
114
c
        cp auto_uids.c.dist auto_uids.c
.
w
q

NOTE: There is no need to perform the above steps unless you don't trust my netqmail-1.06.patched tarball.

Back to installation:

tar zxvf netqmail-1.06.patched.tgz
cd netqmail-1.06.patched
mkdir -p /var/qmail
groupadd nofiles
useradd -g nofiles -d /var/qmail/alias alias
useradd -g nofiles -d /var/qmail qmaild
useradd -g nofiles -d /var/qmail qmaill
useradd -g nofiles -d /var/qmail qmailp
groupadd qmail
useradd -g qmail -d /var/qmail qmailq
useradd -g qmail -d /var/qmail qmailr
useradd -g qmail -d /var/qmail qmails
make setup check
cd /var/qmail
wget http://openbsd.stanleylieber.com/qmail/rc
chmod 755 /var/qmail/rc
mkdir /var/log/qmail
mkdir /var/qmail/control
cd /var/qmail/control
echo 20 >concurrencyincoming
chmod 644 concurrencyincoming
echo ./Maildir/ >defaultdelivery
echo th.inri.net >defaultdomain
echo th.inri.net >locals
echo th.inri.net >me
echo inri.net >plusdomain
echo th.inri.net >rcpthosts
cd /var/qmail/bin
wget http://openbsd.stanleylieber.com/qmail/qmailctl
chmod 775 qmailctl
mkdir /usr/local/qmail
mv /var/qmail/bin /usr/local/qmail/
ln -s /usr/local/qmail/bin /var/qmail/bin
ln -s /usr/local/qmail/bin/qmailctl /usr/local/bin/
mkdir -p /var/qmail/supervise/qmail-send/log
mkdir -p /var/qmail/supervise/qmail-smtpd/log
mkdir -p /var/qmail/supervise/qmail-smtpd-ssl/log
cd /var/qmail/supervise/qmail-send
wget http://openbsd.stanleylieber.com/qmail/supervise/qmail-send-run
mv qmail-send-run run
cd /var/qmail/supervise/qmail-send/log
wget http://openbsd.stanleylieber.com/qmail/supervise/qmail-send-log-run
mv qmail-send-log-run run
cd /var/qmail/supervise/qmail-smtpd
wget http://openbsd.stanleylieber.com/qmail/supervise/qmail-smtpd-run
mv qmail-smtpd-run run
cd /var/qmail/supervise/qmail-smtpd/log
wget http://openbsd.stanleylieber.com/qmail/supervise/qmail-smtpd-log-run
mv qmail-smtpd-log-run run
cd /var/qmail/supervise/qmail-smtpd-ssl
wget http://openbsd.stanleylieber.com/qmail/supervise/qmail-smtpd-ssl-run
mv qmail-smtpd-ssl-run run
cd /var/qmail/supervise/qmail-smtpd-ssl/log
wget http://freebsd.stanleylieber.com/qmail/supervise/qmail-smtpd-ssl-log-run
mv qmail-smtpd-ssl-log-run run
chmod 755 /var/qmail/supervise/qmail-send/run
chmod 755 /var/qmail/supervise/qmail-send/log/run
chmod 755 /var/qmail/supervise/qmail-smtpd/run
chmod 755 /var/qmail/supervise/qmail-smtpd/log/run
chmod 755 /var/qmail/supervise/qmail-smtpd-ssl/run
chmod 755 /var/qmail/supervise/qmail-smtpd-ssl/log/run
mkdir -p /var/log/qmail/smtpd
chown qmaill /var/log/qmail /var/log/qmail/smtpd
mkdir -p /var/log/qmail/smtpd-ssl
chown qmaill /var/log/qmail /var/log/qmail/smtpd-ssl
rcctl stop smtpd
rcctl disable smtpd
/etc/rc.d/sendmail stop
mv /usr/lib/sendmail /usr/lib/sendmail.old                  # ignore errors
mv /usr/sbin/sendmail /usr/sbin/sendmail.old                # ignore errors
chmod 0 /usr/lib/sendmail.old /usr/sbin/sendmail.old        # ignore errors
ln -s /var/qmail/bin/sendmail /usr/lib
ln -s /var/qmail/bin/sendmail /usr/sbin
echo sl > /var/qmail/alias/.qmail-root
echo sl > /var/qmail/alias/.qmail-postmaster
ln -s .qmail-postmaster /var/qmail/alias/.qmail-mailer-daemon
ln -s .qmail-postmaster /var/qmail/alias/.qmail-abuse
chmod 644 /var/qmail/alias/.qmail-root /var/qmail/alias/.qmail-postmaster
echo doublebounce >/var/qmail/control/doublebounceto
# silently discard double bounces
echo '#' >/var/qmail/alias/.qmail-doublebounce
# silently discard all messages to non-existent accounts
echo '#' >/var/qmail/alias/.qmail-default
ln -s \
	/var/qmail/supervise/qmail-send \
	/var/qmail/supervise/qmail-smtpd \
	/var/qmail/supervise/qmail-smtpd-ssl \
	/service
qmailctl stop	# until you're ready

ucspi-tcp

The ucspi-tcp tcpserver(1) program will answer incoming TCP connections and hand them off to either qmail-smtpd directly, or to the ucspi-tools tlss(1) program (which will in turn hand them off to qmail-smtpd). For now, we will only allow relaying from localhost.

pkg_add ucspi-tcp
echo '127.:allow,RELAYCLIENT=""' >>/etc/tcp.smtp
qmailctl cdb

ucspi-tools

The ucspi-tools tlss(1) program will handle TLS for incoming TCP connections. After the TLS connection is established, tlss(1) spawns qmail-stmpd.

pkg_add ucspi-tools
openssl genrsa -out /etc/ssl/qmail.server.key 2048
openssl req -new -key /etc/ssl/qmail.server.key \
	-out /etc/ssl/qmail.server.csr
openssl x509 -sha256 -req -days 365 \
             -in /etc/ssl/qmail.server.csr \
             -signkey /etc/ssl/qmail.server.key \
             -out /etc/ssl/qmail.server.crt
chown root:nofiles /etc/ssl/qmail.server.csr /etc/ssl/qmail.server.key
chmod 640 /etc/ssl/qmail.server.csr /etc/ssl/qmail.server.key

courier-authlib

This suite handles authentication for the other courier tools and for qmail's SMTP auth.

pkg_add courier-authlib
# compile the userdb portion from ports if OpenBSD <= 6.0
cd /usr/ports/mail/courier-authlib
env SUBPACKAGE=-userdb make install clean
ed /etc/courier/authdaemonrc
27
c
authmodulelist="authuserdb"
.
w
q
rcctl enable courier_authdaemond
rcctl start courier_authdaemond

courier-imap

This is how you will access your mail on your awful mobile phone.

pkg_add courier-imap
cd /etc/courier
ed imapd.cnf	# edit to match your site
ed imapd
60
c
MAXPERIP=40	# many folders == many connections
.
w
q
mkdhparams
mkimapdcert
rcctl enable courier_imap_ssl
rcctl start courier_imap_ssl

courierpasswd

Called directly by the qmail-smtpd and qmail-smtpd-ssl run scripts.

pkg_add gmake	# ugh
cd $HOME/src
wget http://openbsd.stanleylieber.com/src/courierpasswd-1.1.3.tar.gz
tar zxvf courierpasswd-1.1.3.tar.gz
cd courierpasswd-1.1.3
export CPPFLAGS=-I/usr/local/include
export LDFLAGS=-L/usr/local/lib
./configure
make
make install
chgrp courier /usr/local/sbin/courierpasswd
chmod g+s /usr/local/sbin/courierpasswd

Add an SMTP/IMAP user

User accounts are managed separately from user accounts on the host operating system. Both instances of authentication will rely upon the same mechanism: courierpasswd backed by courier-authlib.

# as $USER
maildirmake $HOME/Maildir
>$HOME/.th-imap-password
chmod 600 $HOME/.th-imap-password
echo password >$HOME/.th-imap-password
# as root
username=username userdb $username set \
	home=/home/$username \
	mail=/home/$username/Maildir \
	uid=`id -u $username` \
	gid=`id -g $username`

# update SMTP/IMAP user password db based on
# the contents of of $HOME/.th-imap-password
cd /usr/local/qmail/bin
wget http://openbsd.stanleylieber.com/qmail/updatepass.sh
chmod 775 updatepass.sh
ln -s /usr/local/qmail/bin/updatepass.sh /usr/local/bin
/usr/local/bin/updatepass.sh	# read this, suitable to run from cron

# create new IMAP folder called newfolder
# as $USER
maildirmake -f newfolder /home/$USER/Maildir

SpamAssassin and maildrop

Now that everything sort of works, let's assume we'd like to mitigate spam. We'll allow individual users to control the filtering via $HOME/.qmail (used by qmail) and $HOME/.mailfilter (used by maildrop).

pkg_add maildrop p5-Mail-SpamAssassin
sa-update
crontab -e
,p
a
1 7 * * * /usr/local/bin/sa-update
.
w
q
rcctl enable spamassassin
rcctl start spamassassin
## do this as root to enable SpamAssassin for all users by default
#echo '| /usr/local/bin/spamc | maildir ./Maildir/' \
#	>/var/qmail/control/defaultdelivery
# OR do this as $USER to enable SpamAssassin for only that user
cd
wget http://openbsd.stanleylieber.com/qmail/dot.mailfilter &&
	mv dot.mailfilter .mailfilter	# edit to suit
chmod 600 .mailfilter
echo '| /usr/local/bin/spamc | maildrop' >.qmail

Turn on qmail

qmailctl start
qmailctl stat	# trust, but verify

Logs

tail -f /var/log/qmail/current | tai64nlocal	# qmail-send
tail -f /var/log/qmail/smtpd/current | tai64nlocal	# qmail-smtpd
tail -f /var/log/qmail/smtpd-ssl/current | tai64nlocal	# qmail-smtpd-ssl

Troubleshooting

DO NOT UNDER ANY CIRCUMSTANCES run the add-on program queue-fix. Pending further investigation.