debian/rules: Use `git' potty wrapper.
[qmail] / THOUGHTS
CommitLineData
2117e02e
MW
1Please note that this file is not called ``Internet Mail For Dummies.''
2It _records_ my thoughts on various issues. It does not _explain_ them.
3Paragraphs are not organized except by section. The required background
4varies wildly from one paragraph to the next.
5
6In this file, ``sendmail'' means Allman's creation; ``sendmail-clone''
7means the program in this package.
8
9
101. Security
11
12There are lots of interesting remote denial-of-service attacks on any
13mail system. A long-term solution is to insist on prepayment for
14unauthorized resource use. The tricky technical problem is to make the
15prepayment enforcement mechanism cheaper than the expected cost of the
16attacks. (For local denial-of-service attacks it's enough to be able to
17figure out which user is responsible.)
18
19qmail-send's log was originally designed for profiling. It subsequently
20sprouted some tracing features. However, there's no way to verify
21securely that a particular message came from a particular local user;
22how do you know the recipient is telling you the truth about the
23contents of the message? With QUEUE_EXTRA it'd be possible to record a
24one-way hash of each outgoing message, but a user who wants to send
25``bad'' mail can avoid qmail entirely.
26
27I originally decided on security grounds not to put qmail advertisements
28into SMTP responses: advertisements often act as version identifiers.
29But this problem went away when I found a stable qmail URL.
30
31As qmail grows in popularity, the mere knowledge that rcpthosts is so
32easily available will deter people from setting up unauthorized MXs.
33(I've never seen an unauthorized MX, but I can imagine that it would be
34rather annoying.) Note that, unlike the bat book checkcompat() kludge,
35rcpthosts doesn't interfere with mailing lists.
36
37qmail-start doesn't bother with tty dissociation. On some old machines
38this means that random people can send tty signals to the qmail daemons.
39That's a security flaw in the job control subsystem, not in qmail.
40
41The resolver library isn't too bloated (before 4.9.4, at least), but it
42uses stdio, which _is_ bloated. Reading /etc/resolv.conf costs lots of
43memory in each qmail-remote process. So it's tempting to incorporate a
44smaller resolver library into qmail. (Bonus: I'd avoid system-specific
45problems with old resolvers.) The problem is that I'd then be writing a
46fundamentally insecure library. I'd no longer be able to blame the BIND
47authors and vendors for the fact that attackers can easily use DNS to
212b6f5d
MW
48steal mail. Solution: insist that the resolver run on the same host; the
49kernel can guarantee the security of low-numbered 127.0.0.1 UDP ports.
2117e02e
MW
50
51NFS is the primary enemy of security partitioning under UNIX. Here's the
52story. Sun knew from the start that NFS was completely insecure. It
53tried to hide that fact by disallowing root access over NFS. Intruders
54nevertheless broke into system after system, first obtaining bin access
55and then obtaining root access. Various people thus decided to compound
56Sun's error and build a wall between root and all other users: if all
57system files are owned by root, and if there are no security holes other
58than NFS, someone who breaks in via NFS won't be able to wipe out the
59operating system---he'll merely be able to wipe out all user files. This
60clueless policy means that, for example, all the qmail users have to be
61replaced by root. See what I mean by ``enemy''? ... Basic NFS comments:
62Aside from the cryptographic problem of having hosts communicate
63securely, it's obvious that there's an administrative problem of mapping
64client uids to server uids. If a host is secure and under your control,
65you shouldn't have to map anything. If a host is under someone else's
66control, you'll want to map his uids to one local account; it's his
67client's job to decide which of his users get to talk NFS in the first
68place. Sun's original map---root to nobody, everyone else left alone---
69is, as far as I can tell, always wrong.
70
71
722. Injecting mail locally (qmail-inject, sendmail-clone)
73
212b6f5d
MW
74RFC 822 section 3.4.9 prohibits certain visual effects in headers, and
75the 822bis draft prohibits even more. qmail-inject could enforce these
76absurd restrictions, but why waste the time? If you will suffer from
77someone sending you ``flash mail,'' go find a better mail reader.
2117e02e
MW
78
79qmail-inject's ``Cc: recipient list not shown: ;'' successfully stops
80sendmail from adding Apparently-To. Unfortunately, old versions of
81sendmail will append a host name. This wasn't fixed until sendmail 8.7.
82How many years has it been since RFC 822 came out?
83
84sendmail discards duplicate addresses. This has probably resulted in
85more lost and stolen mail over the years than the entire Chicago branch
86of the United States Postal Service. The qmail system delivers messages
87exactly as it's told to do. Along the same lines: qmail-inject is both
88unable and unwilling to support anything like sendmail's (default)
89nometoo option. Of course, a list manager could support nometoo.
90
91There should be a mechanism in qmail-inject that does for envelope
92recipients what Return-Path does for the envelope sender. Then
93qmail-inject -n could print the recipients.
94
95Should qmail-inject bounce messages with no recipients? Should there be
96an option for this? If it stays as is (accept the message), qmail-inject
97could at least avoid invoking qmail-queue.
98
99It is possible to extract non-unique Message-IDs out of qmail-inject.
100Here's how: stop qmail-inject before it gets to the third line of
101main(), then wait until the pids wrap around, then restart qmail-inject
102and blast the message through, then start another qmail-inject with the
212b6f5d
MW
103same pid in the same second. I'm not sure how to fix this without
104system-supplied sequence numbers. (Of course, the user could just type
105in his own non-unique Message-IDs.)
2117e02e
MW
106
107The bat book says: ``Rules that hide hosts in a domain should be applied
108only to sender addresses.'' Recipient masquerading works fine with
109qmail. None of sendmail's pitfalls apply, basically because qmail has a
110straight paper path.
111
212b6f5d
MW
112I predicted that I would receive some pressure to make up for the
113failings of MUA writers who don't understand the concept of reliability.
114(``Like, duh, you mean I'm supposed to check the sendmail exit code?'')
115I was right.
2117e02e
MW
116
117
1183. Receiving mail from the network (tcp-env, qmail-smtpd)
119
212b6f5d
MW
120qmail-smtpd doesn't allow privacy-invading commands like VRFY and EXPN.
121If you really want to publish such information, use a mechanism that
122legitimate users actually know about, such as fingerd or httpd.
123
124RFC 1123 says that VRFY and EXPN are important to track down cross-host
125mailing list loops. With Delivered-To, mailing list loops do no damage,
126_and_ one of the list administrators gets a bounce message that shows
127exactly how the loop occurred. Solve the problem, not the symptom.
2117e02e
MW
128
129Should dns.c make special allowances for 127.0.0.1/localhost?
130
131badmailfrom (like 8BITMIME) is a waste of code space.
132
212b6f5d
MW
133In theory a MAIL or RCPT argument can contain unquoted LFs. In practice
134there are a huge number of clients that terminate commands with just LF,
135even if they use CR properly inside DATA.
136
2117e02e
MW
137
1384. Adding messages to the queue (qmail-queue)
139
140Should qmail-queue try to make sure enough disk space is free in
141advance? When qmail-queue is invoked by qmail-local or (with ESMTP)
212b6f5d
MW
142qmail-smtpd or qmail-qmtpd or qmail-qmqpd, it could be told a size in
143advance. I wish UNIX had an atomic allocate-disk-space routine...
2117e02e
MW
144
145The qmail.h interface (reflecting the qmail-queue interface, which in
146turn reflects the current queue file structure) is constitutionally
147incapable of handling an address that contains a 0 byte. I can't imagine
148that this will be a problem.
149
150Should qmail-queue not bother queueing a message with no recipients?
151
152
1535. Handling queued mail (qmail-send, qmail-clean)
154
155The queue directory must be local. Mounting it over NFS is extremely
156dangerous---not that this stops people from running sendmail that way!
212b6f5d 157Diskless hosts should use mini-qmail instead.
2117e02e
MW
158
159Queue reliability demands that single-byte writes be atomic. This is
160true for a fixed-block filesystem such as UFS, and for a logging
161filesystem such as LFS.
162
163qmail-send uses 8 bytes of memory per queued message. Double that for
164reallocation. (Fix: use a small forest of heaps; i.e., keep several
165prioqs.) Double again for buddy malloc()s. (Fix: be clever about the
166heap sizes.) 32 bytes is worrisome, but not devastating. Even on my
167disk-heavy memory-light machine, I'd run out of inodes long before
168running out of memory.
169
170Some mail systems organize the queue by host. This is pointless as a
171means of splitting up the queue directory. The real issue is what to do
172when you suddenly find out that a host is up. For local SLIP/PPP links
173you know in advance which hosts need this treatment, so you can handle
174them with virtualdomains and serialmail.
175
176For the old queue structure I implemented recipient list compression:
177if mail goes out to a giant mailing list, and most of the recipients are
178delivered, make a new, compressed, todo list. But this really isn't
179worth the effort: it saves only a tiny bit of CPU time.
180
181qmail-send doesn't have any notions of precedence, priority, fairness,
182importance, etc. It handles the queue in first-seen-first-served order.
183One could put a lot of work into doing something different, but that
184work would be a waste: given the triggering mechanism and qmail's
185deferral strategy, it is exceedingly rare for the queue to contain more
186than one deliverable message at any given moment.
187
188Exception: Even with all the concurrency tricks, qmail-send can end up
189spending a few minutes on a mailing list with thousands of remote
190entries. A user might send a new message to a remote address in the
212b6f5d
MW
191meantime. The simplest way to handle this would be to put big messages
192on a separate channel.
2117e02e
MW
193
194qmail-send will never start a pass for a job that it already has. This
195means that, if one delivery takes longer than the retry interval, the
196next pass will be delayed. I implemented the opposite strategy for the
197old queue structure. Some hassles: mark() had to understand how job
198input was buffered; every new delivery had to check whether the same
199mpos in the same message was already being done.
200
201Some things that qmail-send does synchronously: queueing a bounce
202message; doing a cleanup via qmail-clean; classifying and rewriting all
203the addresses in a new message. As usual, making these asynchronous
204would require some housekeeping, but could speed things up a bit.
212b6f5d
MW
205(I'm willing to assume POSIX waitpid() for asynchronous bounces; putting
206an unbounded buffer into wait_pid() for the sake of NeXTSTEP 3 is not
207worthwhile.)
208
209Disk I/O is a bottleneck; UFS is reliable but it isn't fast. A good
210logging filesystem offers much better performance, but logging
211filesystems aren't widely available. Solution: Keep a journal, separate
212from the queue, adequate to rebuild the queue (with at worst some
213duplicate deliveries). Compress the journal. This would dramatically
214reduce total disk I/O.
215
216Bounce aggregation is a dubious feature. Bounce records aren't
217crashproof; there can be a huge delay between a failure and a bounce;
218the resulting bounce format is unnecessarily complicated. I'm tempted to
219scrap the bounce directory and send one bounce for each failing
220recipient, with appropriate modifications in the accompanying text.
221
222qmail-stop implementation: setuid to UID_SEND; kill -TERM -1. Or run
223qmail-start under an external service controller, such as supervise;
224that's why it runs in the foreground.
2117e02e
MW
225
226The readdir() interface hides I/O errors. Lower-level interfaces would
227lead me into a thicket of portability problems. I'm really not sure what
228to do about this. Of course, a hard I/O error means that mail is toast,
229but a soft I/O error shouldn't cause any trouble.
230
231job_open() or pass_dochan() could be paranoid about the same id,channel
232already being open; but, since messdone() is so paranoid, the worst
233possible effect of a bug along these lines would be double delivery.
234
235Mathematical amusement: The optimal retry schedule is essentially,
236though not exactly, independent of the actual distribution of message
237delay times. What really matters is how much cost you assign to retries
238and to particular increases in latency. qmail's current quadratic retry
239schedule says that an hour-long delay in a day-old message is worth the
240same as a ten-minute delay in an hour-old message; this doesn't seem so
241unreasonable.
242
243Insider information: AOL retries their messages every five minutes for
244three days straight. Hmmm.
245
246
2476. Sending mail through the network (qmail-rspawn, qmail-remote)
248
249Are there any hosts, anywhere, whose mailers are bogged down by huge
250messages to multiple recipients at a single host? For typical hosts,
251multiple RCPTs per SMTP aren't an ``efficiency feature''; they're a
252_slowness_ feature. Separate SMTP transactions have much lower latency.
253
212b6f5d
MW
254I've heard three complaints about bandwidth use from masochists sending
255messages through a modem through a smarthost to thousands of users---
256without sublists! They can get much better performance with QMQP.
2117e02e
MW
257
258In the opposite direction: It's tempting to remove the @host part of the
259qmail-remote recip argument. Or at least avoid double-dns_cname.
260
261There are lots of reasons that qmail-rspawn should take a more active
262role in qmail-remote's activities. It should call separate programs to
212b6f5d
MW
263do (1) MX lookups, (2) SMTP connections, (3) QMTP connections. (But this
264wouldn't be so important if the DNS library didn't burn so much memory.)
2117e02e
MW
265
266I bounce ambiguous MXs. (An ``ambiguous MX'' is a best-preference MX
267record sending me mail for a host that I don't recognize as local.)
268Automatically treating ambiguous MXs as local is incompatible with my
269design decision to keep local delivery working when the network goes
270down. It puts more faith in DNS than DNS deserves. Much better: Have
271your MX records generated automatically from control/locals.
272
273If I successfully connect to an MX host but it temporarily refuses to
274accept the message, I give up and put the message back into the queue.
275But several documents seem to suggest that I should try further MX
276records. What are they thinking? My approach deals properly with downed
277hosts, hosts that are unreachable through a firewall, and load
278balancing; what else do people use multiple MX records for?
279
280Currently qmail-remote sends data in 1024-byte buffers. Perhaps it
281should try to take account of the MTU.
282
283Perhaps qmail-remote should allocate a fixed amount of DNS/connect()
284time across any number of MXs; this idea is due to Mark Delany.
285
286RFC 821 doesn't say what it means by ``text.'' qmail-remote assumes that
287the server's reply text doesn't contain bare LFs.
288
212b6f5d
MW
289RFC 821 and RFC 1123 prohibit host names in MAIL FROM and RCPT TO from
290being aliases. qmail-remote, like sendmail, rewrites aliases in RCPT;
291people who don't list aliases in control/locals or sendmail's Cw are
292implicitly relying on this conversion. It is course quite silly for an
293internal DNS detail to have such an effect on mail delivery, but that's
294how the Internet works. On the other hand, the compatibility arguments
295do not apply to MAIL FROM. qmail-remote no longer bothers with CNAME
296lookups for the envelope sender host.
297
2117e02e
MW
298
2997. Delivering mail locally (qmail-lspawn, qmail-local)
300
301qmail-local doesn't support comsat. comsat is a pointless abomination.
302Use qbiff if you want that kind of notification.
303
304The getpwnam() interface hides I/O errors. Solution: qmail-pw2u.
305
306
3078. sendmail V8's new features
308
309sendmail-8.8.0/doc/op/op.me includes a list of big improvements of
310sendmail 8.8.0 over sendmail 5.67. Here's how qmail stacks up against
311each of those improvements. (Of course, qmail has its own improvements,
312but that's not the point of this list.)
313
314Connection caching, MX piggybacking: Nope. (Profile. Don't speculate.)
315
316Response to RCPT command is fast: Yup.
317
318IP addresses show up in Received lines: Yup.
319
320Self domain literal is properly handled: Yup.
321
322Different timeouts for QUIT, RCPT, etc.: No, just a single timeout.
323
324Proper <> handling, route-address pruning: Yes, but not configurable.
325
326ESMTP support: Yup. (Server-side, including PIPELINING.)
327
3288-bit clean: Yup. (Including server-side 8BITMIME support; same as
329sendmail with the 8 option.)
330
331Configurable user database: Yup.
332
333BIND support: Yup.
334
212b6f5d 335Keyed files: Yes, in fastforward.
2117e02e
MW
336
337931/1413/Ident/TAP: Yup.
338
339Correct 822 address list parsing: Yup. (Note that sendmail still has
340some major problems with quoting.)
341
342List-owner handling: Yup.
343
344Dynamic header allocation: Yup.
345
212b6f5d
MW
346Minimum number of disk blocks: Yes, via tunefs -m. (Or quotas; the right
347setup has qmailq with a small quota, qmails with a larger quota, so that
348qmail-send always has room to work.)
2117e02e
MW
349
350Checkpointing: Yes, but not configurable---qmail always checkpoints.
351
352Error message configuration: Nope.
353
354GECOS matching: Not directly, but easy to hook in.
355
356Hop limit configuration: No. (qmail's limit is 100 hops. qmail offers
357automatic loop protection much more advanced than hop counting.)
358
359MIME error messages: No. (qmail uses QSBMF error messages, which are
360much easier to parse.)
361
362Forward file path: Yes, via /etc/passwd.
363
364Incoming SMTP configuration: Yes, via inetd or tcpserver.
365
366Privacy options: Yes, but they're not options.
367
368Best-MX mangling: Nope. See section 6 for further discussion.
369
3707-bit mangling: Nope. qmail always uses 8 bits.
371
372Support for up to 20 MX records: Yes, and more. qmail has no limits
373other than memory.
374
375Correct quoting of name-and-address headers: Yup.
376
377VRFY and EXPN now different: Nope. qmail always hides this information.
378
379Multi-word classes, deferred macro expansion, separate envelope/header
380$g processing, separate per-mailer envelope and header processing, new
381command line flags, new configuration lines, new mailer flags, new
382macros: These are sendmail-specific; they wouldn't even make sense for
383qmail. For example, _of course_ qmail handles envelopes and headers
384separately; they're almost entirely different objects!
385
386
3879. Miscellany
388
389sendmail-clone and qsmhook are too bletcherous to be documented. (The
390official replacement for qsmhook is preline, together with the
391qmail-command environment variables.)
392
393I've considered making install atomic, but this is very difficult to do
394right, and pointless if it isn't done right.
395
396RN suggests automatically putting together a reasonable set of lines for
397/etc/passwd. I perceive this as getting into the adduser business, which
398is worrisome: I'll be lynched the first time I screw up somebody's
399passwd file. This should be left to OS-specific installation scripts.
400
401The BSD 4.2 inetd didn't allow a username. I think I can safely forget
402about this. (DS notes that the username works under Ultrix even though
403it's undocumented.)
404
405I should clean up the bput/put choices.
406
407Some of the stralloc_0()s indicate that certain lower-level routines
408should grok stralloc.
409
2117e02e
MW
410qmail assumes that all times are positive; that pid_t, time_t and ino_t
411fit into unsigned long; that gid_t fits into int; that the character set
412is ASCII; and that all pointers are interchangeable. Do I care?
413
414The bat book justifies sendmail's insane line-splitting mechanism by
415pointing out that it might be useful for ``a 40-character braille
416print-driving program.'' C'mon, guys, is that your best excuse?
417
418qmail's mascot is a dolphin.