******************** *** INTRODUCTION *** ******************** STARTTLS is the standard (RFC 2487) way of doing SMTP encrypted with SSL/TLS. Although it does not provide end-to-end encryption of email messages, it can be useful to protect the passwords of an AUTH PLAIN login, and possibly to protect mail which will travel a very specific route known in advance. qmail-smtpd doesn't have native support for STARTTLS. Many people run qmail for it's extremely good security record, and are reluctant to have the security of their mail system depend on the many thousands of lines of code in openssl. One way to avoid this is to run a proxy which can handle the encryption and the STARTTLS command itself, and then have it hand off to the standard qmail-smtpd. Even better is if the proxy can run in an environment secured by chroot(), setuid(), and setgid(). That's the approach that this document describes, with stunnel acting as the proxy. Basic SMTP/STARTTLS proxy support is already included in stunnel, and that support has been extended to do a plaintext proxy of the SMTP session if STARTTLS isn't used. stunnel runs chrooted in its own directory, as a special user and group. This means that even a grievous security error in stunnel or openssl wouldn't allow significant access to your system, or even allow interfering with mail. ******************** *** INSTRUCTIONS *** ******************** WARNING: These are not for the faint-hearted. They are confusing and may not work for you. This is still experimental; if you get stuck, email me at . 1. Download stunnel-3.22. Apply the patch "stunnel3.22-sg2.patch". Compile and install it somewhere. This patch improves the SMTP proxy support, adds options to tell it to communicate via an already opened file descriptor, adds chroot() support, and improves setuid/setgid support; see: http://www.suspectclass.com/~sgifford/qmail-smtp-tls-proxy/stunnel3.22-sg2.README for a full description of the patch. 2. Compile and install "makesock.c". 3. Create your service directory for smtp-tls 4. Set up a log directory for smtp-tls. 5. Create a user called "stunnel" with a primary group of "stunnel". 6. Create a directory in your service directory called "ssl". 6a. Copy in your certificate as "stunnel.pem" 6b. Copy in your SSL configuration as openssl.cnf 6c. Create a seed file with "dd if=/dev/random of=seed count=10k" or something. 6d/1. Some copies of OpenSSL will require you to create a fake 'usr/share/ssl' directory, to placate openssl in chroot. Something like: mkdir -p usr/share/ssl . If your ssl expects to find its configuration elsewhere, make that directory instead. 6d/2. If your copy of OpenSSL requires it, make a symlink to openssl.cnf from the fake config dir. Something like: ln -s ../../../openssl.cnf usr/share/ssl/ should do the trick, if your openssl expects its config file in /usr/share/ssl normally. 6e. Set group-ownership of the ssl directory to "stunnel" (leaving user-ownership at "root") and permissions to "owner read-write, group read, other none" on everything in the ssl directory: chgrp -R stunnel ssl chmod -R u=rwX,g=rX,o= ssl 7. Install the run file "smtp-tls-run" as "run" in your service directory. Make sure it's executable. If you've installed the modified stunnel somewhere other than /usr/local/bin, add that to the PATH near the top. 8. Run the "run" file in the service directory, and find and fix any errors. 9. Active the service, perhaps by symlinking it into /service. ******************* *** EXPLANATION *** ******************* Here's what the run script does. It expects everything it runs to be in your PATH. First, it gathers up some information from control files and from the system user and group database, and gets some hardcoded configuration information. softlimit limits the memory usage for each process to 5 MB. tcpserver listens on the SMTP port. We continue running as root from here (so we can do chroot() and set[ug]id() later), and when we get a connection we run... ...makesock. This is a small C program that creates a socket with socketpair(), and provides one end of that socket on file descriptor 3 to the first program it's asked to run, and the other end on standard input and output to the second program it's asked to run. The first and second programs are separated by the command line option "-makesock_connect_to". The first program, the STARTTLS proxy, is stunnel. Debugging is turned on, since this is still experimental. "-/ ssl" (an option added by my patch) asks it to chroot to the "ssl" directory. "-s $SSLUID" asks it to change to the stunnel user. "-g $SSLGID" asks it to change to the stunnel group. "-i" (an option added by my patch) asks it to switch users immediately, instead of after binding to the local port for listening (which we don't ask stunnel to do, since tcpserver has done it for us). "-R seed" tells it to get the seed for the random number generator from the file "seed". "-p stunnel.pem" tells it to use the certificate in "stunnel.pem". "-n" smtp-" tells it to act as an SMTP proxy, and to act as a plaintext proxy if TLS isn't negotiated. "-f" asks it to stay in the foreground and write its errors to stderr, perfect for running under supervise! "-F 3" (an option added by my patch) asks it to connect to file descriptor 3 (set up by makesock) as the plaintext end of the proxy. The second program is the SMTP server. We first have to change to a safer UID than root; in most installations, tcpserver would to this for us, but we couldn't do that here (because we needed the ability to chroot() and setuid()/setgid() to a different user/group in stunnel), so "setuidgid" changes to the "qmaild" user and their primary group. stunnel doesn't seem to be very good about passing along CR/LF's properly, and rather than fixing that right now, I just threw in "fixcrio" to take care of it. Finally, the real qmail-smtpd is run. ************* *** NOTES *** ************* It is tempting to run this proxy as a simple TCP proxy, but that makes authorizing relays by IP address hard. ************ *** BUGS *** ************ * RFC 2487 requires that we restart the SMTP session completely after STARTTLS, in particular throwing away the EHLO information we have. We don't do that, because: this architecture makes it hard, qmail doesn't mind if it gets multiple ehlo commands, and qmail doesn't really do much with the ehlo argument anyways. * STARTTLS is only supported if the first command we get is an EHLO, and the second is STARTTLS. * makesock.c is a single-purpose ugly hack. It should take more command-line options, to make it a flexible tool. * There's no way for the SMTP server to know whether TLS was negotiated. This could be useful to, for example, only offer AUTH PLAIN authentication after STARTTLS.