1 |
******************** |
2 |
*** INTRODUCTION *** |
3 |
******************** |
4 |
|
5 |
STARTTLS is the standard (RFC 2487) way of doing SMTP encrypted with |
6 |
SSL/TLS. Although it does not provide end-to-end encryption of email |
7 |
messages, it can be useful to protect the passwords of an AUTH PLAIN |
8 |
login, and possibly to protect mail which will travel a very specific |
9 |
route known in advance. |
10 |
|
11 |
qmail-smtpd doesn't have native support for STARTTLS. Many people run |
12 |
qmail for it's extremely good security record, and are reluctant to |
13 |
have the security of their mail system depend on the many thousands of |
14 |
lines of code in openssl. One way to avoid this is to run a proxy |
15 |
which can handle the encryption and the STARTTLS command itself, and |
16 |
then have it hand off to the standard qmail-smtpd. Even better is if |
17 |
the proxy can run in an environment secured by chroot(), setuid(), and |
18 |
setgid(). |
19 |
|
20 |
That's the approach that this document describes, with stunnel acting |
21 |
as the proxy. Basic SMTP/STARTTLS proxy support is already included |
22 |
in stunnel, and that support has been extended to do a plaintext proxy |
23 |
of the SMTP session if STARTTLS isn't used. stunnel runs chrooted in |
24 |
its own directory, as a special user and group. This means that even |
25 |
a grievous security error in stunnel or openssl wouldn't allow |
26 |
significant access to your system, or even allow interfering with |
27 |
mail. |
28 |
|
29 |
|
30 |
******************** |
31 |
*** INSTRUCTIONS *** |
32 |
******************** |
33 |
|
34 |
WARNING: These are not for the faint-hearted. They are confusing and |
35 |
may not work for you. This is still experimental; if you get stuck, |
36 |
email me at <sgifford@suspectclass.com>. |
37 |
|
38 |
1. Download stunnel-3.22. Apply the patch "stunnel3.22-sg2.patch". |
39 |
Compile and install it somewhere. This patch improves the SMTP |
40 |
proxy support, adds options to tell it to communicate via an |
41 |
already opened file descriptor, adds chroot() support, and improves |
42 |
setuid/setgid support; see: |
43 |
|
44 |
http://www.suspectclass.com/~sgifford/qmail-smtp-tls-proxy/stunnel3.22-sg2.README |
45 |
|
46 |
for a full description of the patch. |
47 |
|
48 |
2. Compile and install "makesock.c". |
49 |
|
50 |
3. Create your service directory for smtp-tls |
51 |
|
52 |
4. Set up a log directory for smtp-tls. |
53 |
|
54 |
5. Create a user called "stunnel" with a primary group of "stunnel". |
55 |
|
56 |
6. Create a directory in your service directory called "ssl". |
57 |
|
58 |
6a. Copy in your certificate as "stunnel.pem" |
59 |
|
60 |
6b. Copy in your SSL configuration as openssl.cnf |
61 |
|
62 |
6c. Create a seed file with "dd if=/dev/random of=seed count=10k" |
63 |
or something. |
64 |
|
65 |
6d/1. Some copies of OpenSSL will require you to create a fake |
66 |
'usr/share/ssl' directory, to placate openssl in chroot. |
67 |
Something like: |
68 |
|
69 |
mkdir -p usr/share/ssl |
70 |
|
71 |
. If your ssl expects to find its configuration elsewhere, |
72 |
make that directory instead. |
73 |
|
74 |
6d/2. If your copy of OpenSSL requires it, make a symlink to |
75 |
openssl.cnf from the fake config dir. Something like: |
76 |
|
77 |
ln -s ../../../openssl.cnf usr/share/ssl/ |
78 |
|
79 |
should do the trick, if your openssl expects its config file in |
80 |
/usr/share/ssl normally. |
81 |
|
82 |
6e. Set group-ownership of the ssl directory to "stunnel" (leaving |
83 |
user-ownership at "root") and permissions to "owner read-write, |
84 |
group read, other none" on everything in the ssl directory: |
85 |
|
86 |
chgrp -R stunnel ssl |
87 |
chmod -R u=rwX,g=rX,o= ssl |
88 |
|
89 |
7. Install the run file "smtp-tls-run" as "run" in your service |
90 |
directory. Make sure it's executable. If you've installed the |
91 |
modified stunnel somewhere other than /usr/local/bin, add that to |
92 |
the PATH near the top. |
93 |
|
94 |
8. Run the "run" file in the service directory, and find and fix any |
95 |
errors. |
96 |
|
97 |
9. Active the service, perhaps by symlinking it into /service. |
98 |
|
99 |
|
100 |
|
101 |
******************* |
102 |
*** EXPLANATION *** |
103 |
******************* |
104 |
|
105 |
Here's what the run script does. It expects everything it runs to be |
106 |
in your PATH. |
107 |
|
108 |
First, it gathers up some information from control files and from the |
109 |
system user and group database, and gets some hardcoded configuration |
110 |
information. |
111 |
|
112 |
softlimit limits the memory usage for each process to 5 MB. |
113 |
|
114 |
tcpserver listens on the SMTP port. We continue running as root from |
115 |
here (so we can do chroot() and set[ug]id() later), and when we get a |
116 |
connection we run... |
117 |
|
118 |
...makesock. This is a small C program that creates a socket with |
119 |
socketpair(), and provides one end of that socket on file descriptor 3 |
120 |
to the first program it's asked to run, and the other end on standard |
121 |
input and output to the second program it's asked to run. The first |
122 |
and second programs are separated by the command line option |
123 |
"-makesock_connect_to". |
124 |
|
125 |
The first program, the STARTTLS proxy, is stunnel. Debugging is |
126 |
turned on, since this is still experimental. "-/ ssl" (an option |
127 |
added by my patch) asks it to chroot to the "ssl" directory. "-s |
128 |
$SSLUID" asks it to change to the stunnel user. "-g $SSLGID" asks it |
129 |
to change to the stunnel group. "-i" (an option added by my patch) |
130 |
asks it to switch users immediately, instead of after binding to the |
131 |
local port for listening (which we don't ask stunnel to do, since |
132 |
tcpserver has done it for us). "-R seed" tells it to get the seed for |
133 |
the random number generator from the file "seed". "-p stunnel.pem" |
134 |
tells it to use the certificate in "stunnel.pem". "-n" smtp-" tells |
135 |
it to act as an SMTP proxy, and to act as a plaintext proxy if TLS |
136 |
isn't negotiated. "-f" asks it to stay in the foreground and write |
137 |
its errors to stderr, perfect for running under supervise! "-F 3" (an |
138 |
option added by my patch) asks it to connect to file descriptor 3 (set |
139 |
up by makesock) as the plaintext end of the proxy. |
140 |
|
141 |
The second program is the SMTP server. We first have to change to a |
142 |
safer UID than root; in most installations, tcpserver would to this |
143 |
for us, but we couldn't do that here (because we needed the ability to |
144 |
chroot() and setuid()/setgid() to a different user/group in stunnel), |
145 |
so "setuidgid" changes to the "qmaild" user and their primary group. |
146 |
stunnel doesn't seem to be very good about passing along CR/LF's |
147 |
properly, and rather than fixing that right now, I just threw in |
148 |
"fixcrio" to take care of it. Finally, the real qmail-smtpd is run. |
149 |
|
150 |
************* |
151 |
*** NOTES *** |
152 |
************* |
153 |
|
154 |
It is tempting to run this proxy as a simple TCP proxy, but that makes |
155 |
authorizing relays by IP address hard. |
156 |
|
157 |
|
158 |
************ |
159 |
*** BUGS *** |
160 |
************ |
161 |
|
162 |
* RFC 2487 requires that we restart the SMTP session completely after |
163 |
STARTTLS, in particular throwing away the EHLO information we have. |
164 |
We don't do that, because: this architecture makes it hard, qmail |
165 |
doesn't mind if it gets multiple ehlo commands, and qmail doesn't |
166 |
really do much with the ehlo argument anyways. |
167 |
|
168 |
* STARTTLS is only supported if the first command we get is an EHLO, |
169 |
and the second is STARTTLS. |
170 |
|
171 |
* makesock.c is a single-purpose ugly hack. It should take more |
172 |
command-line options, to make it a flexible tool. |
173 |
|
174 |
* There's no way for the SMTP server to know whether TLS was |
175 |
negotiated. This could be useful to, for example, only offer AUTH |
176 |
PLAIN authentication after STARTTLS. |