1This file describes the design goals and the reasoning behind some of
2the design decisions for my tiny POP3 daemon, popa3d.
3
4
5	Why popa3d?
6
7There're lots of different POP3 servers -- with different feature
8sets, performance, and reliability.  However, as far as I know, before
9I started the work on popa3d, there had been only one with security as
10one of its primary design goals: qmail-pop3d.  Unfortunately, it would
11only work with qmail, and only with its new maildir format.  While
12both qmail and maildirs do indeed have some advantages, a lot of
13people continue running other MTAs, and/or use the older mailbox
14format, for various reasons.  Many of them need a POP3 server.
15
16
17	The design goals.
18
19Well, the goals themselves are obvious; they're probably the same for
20most other POP3 servers as well.  It's their priority that differs.
21For popa3d, the goals are:
22
231. Security (to the extent that is possible with POP3 at all, of
24course).
25
262. Reliability (again, as limited by the mailbox format and the
27protocol).
28
293. RFC compliance (slightly relaxed to work with real-world POP3
30clients).
31
324. Performance (limited by the more important goals, above).
33
34Obviously, just like the comments indicate, none of the goals can be
35met completely, and balanced decisions need to be made.
36
37
38	Security.
39
40First, it is important that none of the popa3d users get a false sense
41of security just because it was the primary design goal.  The POP3
42protocol transmits passwords in plaintext and thus, if you care about
43the security of your individual user accounts, should only be used
44either in trusted networks or tunneled over encrypted channels.
45There exist extensions to the protocol that are supposed to fix this
46problem.  I am not supporting them yet, partly because this isn't
47going to fully fix the problem.  In fact, APOP and the weaker defined
48SASL mechanisms such as CRAM-MD5 may potentially be even less secure
49than transmission of plaintext passwords because of the requirement
50that plaintext equivalents be stored on the server.
51
52It is also important to understand that nothing can be perfectly
53secure.  I can make mistakes.  While the design of popa3d makes it
54harder for those to turn into security holes, this is nevertheless
55still possible.
56
57Having that said, let's get to the security-critical design decisions.
58
59
60	Privilege management.
61
62Initially, popa3d is started as root to handle a connection.  However,
63it does very little work as root: switching to less privileged UIDs,
64communication with child processes, and authentication information
65checks (which often involve accessing shadow or master.passwd files).
66
67The following privilege switches happen during a successful POP3
68session, with /etc/shadow authentication:
69
70			 startup as root
71				|
72			-----------------
73			|child		|parent
74			v		v
75	drop to user popa3d,		still as root,
76	handle the AUTHORIZATION	wait for and
77	state, write the results, - - >	read the authentication
78	and exit			information
79					|
80			-----------------
81			|child		|parent
82			v		v
83	getspnam(3), crypt(3),		wait for and
84	check, write the result,  - - >	read the authentication
85	and exit (to clean up)		result
86					|
87					v
88					drop to the authenticated user,
89					handle the TRANSACTION state,
90					possibly UPDATE the mailbox,
91					and exit
92
93
94	Trust.
95
96No part of popa3d trusts any information obtained from external
97sources (that is, the data is never assumed to be of the expected
98format, and is treated as subject to authorization checks).  This
99includes POP3 commands, mailbox contents, and even popa3d's own
100less-privileged child process for the AUTHORIZATION state handling.
101
102
103	DoS attacks.
104
105Just like with most other software, there exist ways to cause a Denial
106of Service, by supplying popa3d with an enormous amount of otherwise
107valid input.  I am aware of the following attacks on popa3d itself:
108
1091. Connection flood.  When running in the standalone mode, popa3d does
110quite a few checks to significantly reduce the impact of such attacks
111by limiting resource consumption (child processes and logging rate),
112while still providing full service for other source IP addresses and
113logging everything that might be important.  However, when running
114from an inetd clone, the handling of these attacks is left up to your
115inetd and the kernel.
116
1172. Huge mailbox sizes, either in message count or bytes.  There're
118limits in popa3d (see params.h) that are intended to prevent this
119attack from stopping the entire service.  Depending on your disk and
120other quotas, it may still be possible to stop individual users from
121getting their mail.
122
123
124	Reliability.
125
126Quoting Dan Bernstein, "the mbox format ... is inherently unreliable".
127
128While popa3d, just like other mail software that deals with mailboxes,
129doesn't guarantee reliability over system crashes, it still makes
130sense to talk about its operation on an otherwise stable system.
131
132
133	Interaction with other MUAs.
134
135Similarly to cucipop (but unlike qpopper), popa3d works on the
136original mailbox file, without copying.  However, unlike cucipop,
137popa3d is able to ensure that the mailbox doesn't get corrupted if
138another MUA modifies it during the POP session.  Before each mailbox
139access, popa3d checks its timestamp and, if that has changed,
140determines if that is due to new mail that has just been delivered, or
141other changes made to the mailbox.  In the latter case, the POP
142session is silently aborted (which doesn't violate the RFC).  popa3d
143is careful to make sure the timestamp will change if the mailbox is
144written to, by keeping the lock for up to a second if necessary.
145
146
147	Mailbox access.
148
149Except for the total size and message count limits mentioned above
150(and you can disable even those), there're no other artificial limits
151on the mailbox contents.  In particular, there're no line length
152limits; unlike with qmail-pop3d, lines don't even need to fit in the
153available memory.  NUL bytes are allowed in messages as well.
154
155
156	Locking.
157
158Because of dropping to the user "completely" (that is, not even
159keeping a GID of mail like some other POP3 servers do), popa3d only
160uses fcntl(2) or flock(2) for locking.  As a result, it may not be
161safe over NFS.  This is where I choose security over either
162functionality or reliability.
163
164
165	RFC compliance.
166
167I tried to make popa3d as strictly RFC 1939 compliant as possible.
168Most other POP3 servers have extra "features" that violate the RFC.
169Examples include: wrapping long commands (no matter if they're valid
170or not) and thus generating multiple -ERR responses (if not even
171worse: processing something from the middle of the line as a command)
172to a single command, processing "LIST 4294967297" as "LIST 1" instead
173of reporting the error, ignoring past a NUL byte till end of line and
174thus misinterpreting the command.  While these are mostly harmless,
175they can theoretically cause a POP3 client not to detect the
176unavailability of a protocol extension.
177
178There's however one place where popa3d's RFC compliance is
179deliberately relaxed: popa3d accepts commands terminated by single
180LFs, even though the RFC says the commands are terminated by a CRLF
181pair.
182
183
184	Performance.
185
186Despite the two extra "security" fork(2) calls, popa3d seems to behave
187fairly efficiently: the efficient mailbox parsing code and the lack of
188mailbox copying compensate for the extra fork's.
189
190Here's some real performance data that I've collected (popa3d running
191via inetd; larger sites would use the standalone mode instead):
192
193	24864     295.50re      16.92cp   popa3d*
194	12749    4578.88re      15.50cp   popa3d
195
196That is, 12749 POP3 sessions took 32.42 minutes of CPU time (on a 350
197MHz Pentium II); of those, more than a half was spent in the temporary
198child processes.  It's not that bad though, as this system was running
199an (intentionally) expensive crypt(3) that got accounted to the child
200/etc/shadow authentication processes.
201
202Before upgrading to popa3d, the same machine was running qpopper (out
203of inetd, too):
204
205	12025    3169.38re      35.56cp   popper
206
207It used to take a bit more CPU for less POP3 sessions.
208
209--
210Solar Designer <solar at openwall.com>
211