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