commit af9625ddf9464e85fd781e8ad889201ce340d9fc Author: D. J. Bernstein <djb@cr.yp.to> Date: Tue, 28 Oct 1997 00:00:00 +0100 qmail 1.01 Diffstat:
A | BLURB | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | BLURB2 | | | 26 | ++++++++++++++++++++++++++ |
A | BLURB3 | | | 90 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | BLURB4 | | | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
A | CHANGES | | | 1204 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | FAQ | | | 574 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | FILES | | | 401 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | INSTALL | | | 181 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | INSTALL.alias | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | INSTALL.boot | | | 16 | ++++++++++++++++ |
A | INSTALL.ctl | | | 29 | +++++++++++++++++++++++++++++ |
A | INSTALL.ids | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | INSTALL.mbox | | | 112 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | INSTALL.qsmhook | | | 53 | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | INTERNALS | | | 155 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Makefile | | | 2181 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | README | | | 199 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | RFCHCSC | | | 37 | +++++++++++++++++++++++++++++++++++++ |
A | RFCLOOPS | | | 338 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | RFCMXPS | | | 122 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | RFCNETSTR | | | 88 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | RFCNRUDT | | | 89 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | RFCQMTP | | | 229 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | RFCQSBMF | | | 155 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | RFCVERP | | | 88 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | SECURITY | | | 131 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | SYSDEPS | | | 17 | +++++++++++++++++ |
A | TARGETS | | | 353 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | THANKS | | | 217 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | THOUGHTS | | | 437 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | TODO | | | 9 | +++++++++ |
A | UPGRADE | | | 145 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | VERSION | | | 1 | + |
A | addresses.5 | | | 260 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | alloc.3 | | | 62 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | alloc.c | | | 32 | ++++++++++++++++++++++++++++++++ |
A | alloc.h | | | 8 | ++++++++ |
A | alloc_re.c | | | 17 | +++++++++++++++++ |
A | auto-gid.c | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | auto-int.c | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | auto-int8.c | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | auto-str.c | | | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
A | auto-uid.c | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | auto_break.h | | | 6 | ++++++ |
A | auto_patrn.h | | | 6 | ++++++ |
A | auto_qmail.h | | | 6 | ++++++ |
A | auto_spawn.h | | | 6 | ++++++ |
A | auto_split.h | | | 6 | ++++++ |
A | auto_uids.h | | | 16 | ++++++++++++++++ |
A | auto_usera.h | | | 6 | ++++++ |
A | byte.h | | | 13 | +++++++++++++ |
A | byte_chr.c | | | 20 | ++++++++++++++++++++ |
A | byte_copy.c | | | 14 | ++++++++++++++ |
A | byte_cr.c | | | 16 | ++++++++++++++++ |
A | byte_diff.c | | | 16 | ++++++++++++++++ |
A | byte_rchr.c | | | 23 | +++++++++++++++++++++++ |
A | byte_zero.c | | | 13 | +++++++++++++ |
A | case.3 | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | case.h | | | 13 | +++++++++++++ |
A | case_diffb.c | | | 21 | +++++++++++++++++++++ |
A | case_diffs.c | | | 19 | +++++++++++++++++++ |
A | case_lowerb.c | | | 14 | ++++++++++++++ |
A | case_lowers.c | | | 12 | ++++++++++++ |
A | case_starts.c | | | 18 | ++++++++++++++++++ |
A | cdb.3 | | | 62 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | cdb.h | | | 12 | ++++++++++++ |
A | cdb_hash.c | | | 16 | ++++++++++++++++ |
A | cdb_seek.c | | | 95 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | cdb_unpack.c | | | 12 | ++++++++++++ |
A | cdbmake.h | | | 35 | +++++++++++++++++++++++++++++++++++ |
A | cdbmake_add.c | | | 117 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | cdbmake_hash.c | | | 10 | ++++++++++ |
A | cdbmake_pack.c | | | 11 | +++++++++++ |
A | cdbmss.c | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | cdbmss.h | | | 16 | ++++++++++++++++ |
A | chkshsgr.c | | | 9 | +++++++++ |
A | chkspawn.c | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | coe.3 | | | 25 | +++++++++++++++++++++++++ |
A | coe.c | | | 8 | ++++++++ |
A | coe.h | | | 6 | ++++++ |
A | condredirect.1 | | | 54 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | condredirect.c | | | 87 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf-break | | | 9 | +++++++++ |
A | conf-cc | | | 3 | +++ |
A | conf-groups | | | 6 | ++++++ |
A | conf-ld | | | 3 | +++ |
A | conf-patrn | | | 5 | +++++ |
A | conf-qmail | | | 4 | ++++ |
A | conf-spawn | | | 5 | +++++ |
A | conf-split | | | 3 | +++ |
A | conf-users | | | 15 | +++++++++++++++ |
A | constmap.c | | | 123 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | constmap.h | | | 22 | ++++++++++++++++++++++ |
A | control.c | | | 129 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | control.h | | | 10 | ++++++++++ |
A | date822fmt.c | | | 29 | +++++++++++++++++++++++++++++ |
A | date822fmt.h | | | 7 | +++++++ |
A | datemail.sh | | | 1 | + |
A | datetime.3 | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | datetime.c | | | 55 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | datetime.h | | | 20 | ++++++++++++++++++++ |
A | datetime_un.c | | | 35 | +++++++++++++++++++++++++++++++++++ |
A | direntry.3 | | | 36 | ++++++++++++++++++++++++++++++++++++ |
A | direntry.h1 | | | 8 | ++++++++ |
A | direntry.h2 | | | 8 | ++++++++ |
A | dns.c | | | 402 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | dns.h | | | 14 | ++++++++++++++ |
A | dnscname.c | | | 25 | +++++++++++++++++++++++++ |
A | dnsdoe.c | | | 16 | ++++++++++++++++ |
A | dnsdoe.h | | | 6 | ++++++ |
A | dnsfq.c | | | 32 | ++++++++++++++++++++++++++++++++ |
A | dnsip.c | | | 34 | ++++++++++++++++++++++++++++++++++ |
A | dnsmxip.c | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | dnsptr.c | | | 27 | +++++++++++++++++++++++++++ |
A | dot-qmail.9 | | | 394 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | elq.sh | | | 1 | + |
A | env.3 | | | 31 | +++++++++++++++++++++++++++++++ |
A | env.c | | | 113 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | env.h | | | 17 | +++++++++++++++++ |
A | envelopes.5 | | | 231 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | envread.c | | | 30 | ++++++++++++++++++++++++++++++ |
A | error.3 | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
A | error.c | | | 95 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | error.h | | | 23 | +++++++++++++++++++++++ |
A | error_str.3 | | | 19 | +++++++++++++++++++ |
A | error_str.c | | | 276 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | error_temp.3 | | | 27 | +++++++++++++++++++++++++++ |
A | error_temp.c | | | 80 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | exit.h | | | 6 | ++++++ |
A | extra.h | | | 7 | +++++++ |
A | fd.h | | | 7 | +++++++ |
A | fd_copy.3 | | | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
A | fd_copy.c | | | 13 | +++++++++++++ |
A | fd_move.3 | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
A | fd_move.c | | | 11 | +++++++++++ |
A | fifo.c | | | 10 | ++++++++++ |
A | fifo.h | | | 6 | ++++++ |
A | fifo_make.3 | | | 24 | ++++++++++++++++++++++++ |
A | find-systype.sh | | | 144 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | fmt.h | | | 25 | +++++++++++++++++++++++++ |
A | fmt_str.c | | | 12 | ++++++++++++ |
A | fmt_strn.c | | | 12 | ++++++++++++ |
A | fmt_uint.c | | | 6 | ++++++ |
A | fmt_uint0.c | | | 10 | ++++++++++ |
A | fmt_ulong.c | | | 13 | +++++++++++++ |
A | fmtqfn.c | | | 24 | ++++++++++++++++++++++++ |
A | fmtqfn.h | | | 8 | ++++++++ |
A | forgeries.7 | | | 104 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | fork.h1 | | | 7 | +++++++ |
A | fork.h2 | | | 7 | +++++++ |
A | forward.1 | | | 24 | ++++++++++++++++++++++++ |
A | forward.c | | | 58 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | gen_alloc.h | | | 7 | +++++++ |
A | gen_allocdefs.h | | | 34 | ++++++++++++++++++++++++++++++++++ |
A | getln.3 | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | getln.c | | | 20 | ++++++++++++++++++++ |
A | getln.h | | | 7 | +++++++ |
A | getln2.3 | | | 64 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | getln2.c | | | 31 | +++++++++++++++++++++++++++++++ |
A | gfrom.c | | | 10 | ++++++++++ |
A | gfrom.h | | | 6 | ++++++ |
A | headerbody.c | | | 87 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | headerbody.h | | | 6 | ++++++ |
A | hfield.c | | | 124 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | hfield.h | | | 37 | +++++++++++++++++++++++++++++++++++++ |
A | hostname.c | | | 17 | +++++++++++++++++ |
A | install.c | | | 167 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | instcheck.c | | | 120 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ip.c | | | 53 | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ip.h | | | 11 | +++++++++++ |
A | ipalloc.c | | | 7 | +++++++ |
A | ipalloc.h | | | 14 | ++++++++++++++ |
A | ipme.c | | | 95 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ipme.h | | | 12 | ++++++++++++ |
A | ipmeprint.c | | | 24 | ++++++++++++++++++++++++ |
A | lock.h | | | 8 | ++++++++ |
A | lock_ex.c | | | 11 | +++++++++++ |
A | lock_exnb.c | | | 11 | +++++++++++ |
A | lock_un.c | | | 11 | +++++++++++ |
A | maildir.5 | | | 239 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | maildir.c | | | 108 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | maildir.h | | | 12 | ++++++++++++ |
A | maildir2mbox.1 | | | 53 | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | maildir2mbox.c | | | 162 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | maildirmake.1 | | | 15 | +++++++++++++++ |
A | maildirmake.c | | | 22 | ++++++++++++++++++++++ |
A | maildirwatch.1 | | | 23 | +++++++++++++++++++++++ |
A | maildirwatch.c | | | 125 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | mailsubj.1 | | | 38 | ++++++++++++++++++++++++++++++++++++++ |
A | mailsubj.sh | | | 7 | +++++++ |
A | make-compile.sh | | | 1 | + |
A | make-load.sh | | | 2 | ++ |
A | make-makelib.sh | | | 16 | ++++++++++++++++ |
A | mbox.5 | | | 235 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | myctime.c | | | 37 | +++++++++++++++++++++++++++++++++++++ |
A | myctime.h | | | 6 | ++++++ |
A | ndelay.c | | | 9 | +++++++++ |
A | ndelay.h | | | 7 | +++++++ |
A | ndelay_off.c | | | 9 | +++++++++ |
A | newfield.c | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | newfield.h | | | 12 | ++++++++++++ |
A | now.3 | | | 14 | ++++++++++++++ |
A | now.c | | | 8 | ++++++++ |
A | now.h | | | 8 | ++++++++ |
A | open.h | | | 10 | ++++++++++ |
A | open_append.c | | | 6 | ++++++ |
A | open_excl.c | | | 6 | ++++++ |
A | open_read.c | | | 6 | ++++++ |
A | open_trunc.c | | | 6 | ++++++ |
A | open_write.c | | | 6 | ++++++ |
A | pinq.sh | | | 1 | + |
A | predate.c | | | 125 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | preline.1 | | | 57 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | preline.c | | | 87 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | prioq.c | | | 58 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | prioq.h | | | 15 | +++++++++++++++ |
A | prot.c | | | 21 | +++++++++++++++++++++ |
A | prot.h | | | 7 | +++++++ |
A | qail.sh | | | 1 | + |
A | qbiff.1 | | | 31 | +++++++++++++++++++++++++++++++ |
A | qbiff.c | | | 113 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qlist.1 | | | 112 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qlist.c | | | 333 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qlist2.sh | | | 1 | + |
A | qlx.h | | | 18 | ++++++++++++++++++ |
A | qmail-clean.8 | | | 13 | +++++++++++++ |
A | qmail-clean.c | | | 98 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-command.8 | | | 123 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-config.sh | | | 64 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-control.9 | | | 74 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-getpw.9 | | | 109 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-getpw.c | | | 86 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-header.5 | | | 331 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-hier.c | | | 248 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-inject.8 | | | 294 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-inject.c | | | 735 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-limits.9 | | | 30 | ++++++++++++++++++++++++++++++ |
A | qmail-local.8 | | | 99 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-local.c | | | 672 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-log.5 | | | 270 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-lspawn.8 | | | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-lspawn.c | | | 234 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-newu.9 | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-newu.c | | | 137 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-pop3d.8 | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-pop3d.c | | | 397 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-popup.8 | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-popup.c | | | 219 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-pw2u.9 | | | 235 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-pw2u.c | | | 308 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-qmtpd.8 | | | 29 | +++++++++++++++++++++++++++++ |
A | qmail-qmtpd.c | | | 281 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-qread.8 | | | 24 | ++++++++++++++++++++++++ |
A | qmail-qread.c | | | 175 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-qstat.8 | | | 18 | ++++++++++++++++++ |
A | qmail-qstat.sh | | | 3 | +++ |
A | qmail-queue.8 | | | 58 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-queue.c | | | 254 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-remote.8 | | | 206 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-remote.c | | | 480 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-rspawn.8 | | | 21 | +++++++++++++++++++++ |
A | qmail-rspawn.c | | | 103 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-send.9 | | | 264 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-send.c | | | 1652 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-showctl.8 | | | 12 | ++++++++++++ |
A | qmail-showctl.c | | | 233 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-smtpd.8 | | | 125 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-smtpd.c | | | 449 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-start.9 | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-start.c | | | 120 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-tcpto.8 | | | 29 | +++++++++++++++++++++++++++++ |
A | qmail-tcpto.c | | | 85 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-upgrade.9 | | | 201 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail-upq.sh | | | 14 | ++++++++++++++ |
A | qmail-users.9 | | | 113 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail.7 | | | 67 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail.c | | | 103 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qmail.h | | | 36 | ++++++++++++++++++++++++++++++++++++ |
A | qreceipt.1 | | | 33 | +++++++++++++++++++++++++++++++++ |
A | qreceipt.c | | | 131 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qsmhook.c | | | 137 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | qsutil.c | | | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
A | qsutil.h | | | 12 | ++++++++++++ |
A | quote.c | | | 82 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | quote.h | | | 8 | ++++++++ |
A | readsubdir.c | | | 49 | +++++++++++++++++++++++++++++++++++++++++++++++++ |
A | readsubdir.h | | | 20 | ++++++++++++++++++++ |
A | readwrite.h | | | 7 | +++++++ |
A | received.c | | | 71 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | received.h | | | 6 | ++++++ |
A | remoteinfo.c | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | remoteinfo.h | | | 6 | ++++++ |
A | scan.h | | | 27 | +++++++++++++++++++++++++++ |
A | scan_8long.c | | | 11 | +++++++++++ |
A | scan_nbblong.c | | | 33 | +++++++++++++++++++++++++++++++++ |
A | scan_ulong.c | | | 11 | +++++++++++ |
A | seek.h | | | 15 | +++++++++++++++ |
A | seek_cur.c | | | 7 | +++++++ |
A | seek_end.c | | | 7 | +++++++ |
A | seek_set.c | | | 7 | +++++++ |
A | seek_trunc.c | | | 5 | +++++ |
A | select.h1 | | | 8 | ++++++++ |
A | select.h2 | | | 9 | +++++++++ |
A | sendmail.c | | | 98 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | sgetopt.3 | | | 28 | ++++++++++++++++++++++++++++ |
A | sgetopt.c | | | 54 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | sgetopt.h | | | 21 | +++++++++++++++++++++ |
A | sig.h | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | sig_alarm.c | | | 7 | +++++++ |
A | sig_block.c | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | sig_bug.c | | | 17 | +++++++++++++++++ |
A | sig_catch.c | | | 18 | ++++++++++++++++++ |
A | sig_child.c | | | 7 | +++++++ |
A | sig_hup.c | | | 7 | +++++++ |
A | sig_misc.c | | | 17 | +++++++++++++++++ |
A | sig_pause.c | | | 14 | ++++++++++++++ |
A | sig_pipe.c | | | 5 | +++++ |
A | sig_term.c | | | 7 | +++++++ |
A | slurpclose.c | | | 17 | +++++++++++++++++ |
A | slurpclose.h | | | 6 | ++++++ |
A | spawn.c | | | 259 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | splogger.8 | | | 60 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | splogger.c | | | 72 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | str.h | | | 14 | ++++++++++++++ |
A | str_chr.c | | | 19 | +++++++++++++++++++ |
A | str_cpy.c | | | 16 | ++++++++++++++++ |
A | str_diff.c | | | 17 | +++++++++++++++++ |
A | str_diffn.c | | | 18 | ++++++++++++++++++ |
A | str_len.c | | | 15 | +++++++++++++++ |
A | str_rchr.c | | | 22 | ++++++++++++++++++++++ |
A | str_start.c | | | 15 | +++++++++++++++ |
A | stralloc.3 | | | 160 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | stralloc.h | | | 21 | +++++++++++++++++++++ |
A | stralloc_arts.c | | | 12 | ++++++++++++ |
A | stralloc_cat.c | | | 9 | +++++++++ |
A | stralloc_catb.c | | | 15 | +++++++++++++++ |
A | stralloc_cats.c | | | 10 | ++++++++++ |
A | stralloc_copy.c | | | 9 | +++++++++ |
A | stralloc_eady.c | | | 6 | ++++++ |
A | stralloc_opyb.c | | | 14 | ++++++++++++++ |
A | stralloc_opys.c | | | 10 | ++++++++++ |
A | stralloc_pend.c | | | 5 | +++++ |
A | strerr.h | | | 80 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | strerr_die.c | | | 37 | +++++++++++++++++++++++++++++++++++++ |
A | strerr_sys.c | | | 12 | ++++++++++++ |
A | subfd.h | | | 15 | +++++++++++++++ |
A | subfderr.c | | | 7 | +++++++ |
A | subfdin.c | | | 13 | +++++++++++++ |
A | subfdins.c | | | 13 | +++++++++++++ |
A | subfdout.c | | | 7 | +++++++ |
A | subfdouts.c | | | 7 | +++++++ |
A | subgetopt.3 | | | 357 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | subgetopt.c | | | 79 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | subgetopt.h | | | 24 | ++++++++++++++++++++++++ |
A | substdi.c | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | substdio.c | | | 15 | +++++++++++++++ |
A | substdio.h | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
A | substdio_copy.c | | | 18 | ++++++++++++++++++ |
A | substdo.c | | | 108 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | tcp-env.1 | | | 67 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | tcp-env.c | | | 129 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | tcp-environ.5 | | | 62 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | tcpto.c | | | 165 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | tcpto.h | | | 8 | ++++++++ |
A | tcpto_clean.c | | | 20 | ++++++++++++++++++++ |
A | timeoutconn.c | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | timeoutconn.h | | | 6 | ++++++ |
A | timeoutread.c | | | 25 | +++++++++++++++++++++++++ |
A | timeoutread.h | | | 8 | ++++++++ |
A | timeoutwrite.c | | | 25 | +++++++++++++++++++++++++ |
A | timeoutwrite.h | | | 8 | ++++++++ |
A | token822.c | | | 511 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | token822.h | | | 37 | +++++++++++++++++++++++++++++++++++++ |
A | trigger.c | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
A | trigger.h | | | 8 | ++++++++ |
A | triggerpull.c | | | 16 | ++++++++++++++++ |
A | triggerpull.h | | | 6 | ++++++ |
A | trycpp.c | | | 7 | +++++++ |
A | trydrent.c | | | 8 | ++++++++ |
A | tryflock.c | | | 8 | ++++++++ |
A | trylsock.c | | | 4 | ++++ |
A | trymkffo.c | | | 7 | +++++++ |
A | trynpbg1.c | | | 26 | ++++++++++++++++++++++++++ |
A | tryrsolv.c | | | 4 | ++++ |
A | trysalen.c | | | 11 | +++++++++++ |
A | trysgact.c | | | 10 | ++++++++++ |
A | trysgprm.c | | | 10 | ++++++++++ |
A | tryshsgr.c | | | 14 | ++++++++++++++ |
A | trysysel.c | | | 8 | ++++++++ |
A | trysyslog.c | | | 9 | +++++++++ |
A | tryulong32.c | | | 11 | +++++++++++ |
A | tryvfork.c | | | 4 | ++++ |
A | trywaitp.c | | | 7 | +++++++ |
A | uint32.h1 | | | 6 | ++++++ |
A | uint32.h2 | | | 6 | ++++++ |
A | wait.3 | | | 93 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | wait.h | | | 14 | ++++++++++++++ |
A | wait_nohang.c | | | 12 | ++++++++++++ |
A | wait_pid.c | | | 13 | +++++++++++++ |
A | warn-auto.sh | | | 2 | ++ |
A | warn-shsgr | | | 3 | +++ |
401 files changed, 30689 insertions(+), 0 deletions(-)
diff --git a/BLURB b/BLURB @@ -0,0 +1,43 @@ +qmail is a secure, reliable, efficient, simple message transfer agent. +It is meant as a replacement for the entire sendmail-binmail system on +typical Internet-connected UNIX hosts. + +Secure: Security isn't just a goal, but an absolute requirement. Mail +delivery is critical for users; it cannot be turned off, so it must be +completely secure. (This is why I started writing qmail: I was sick of +the security holes in sendmail and other MTAs.) + +Reliable: qmail's straight-paper-path philosophy guarantees that a +message, once accepted into the system, will never be lost. qmail also +supports maildir, a new, super-reliable user mailbox format. Maildirs, +unlike mbox files and mh folders, won't be corrupted if the system +crashes during delivery. Even better, not only can a user safely read +his mail over NFS, but any number of NFS clients can deliver mail to him +at the same time. + +Efficient: On a Pentium under BSD/OS, qmail can easily sustain 200000 +local messages per day---that's separate messages injected and delivered +to mailboxes in a real test! Although remote deliveries are inherently +limited by the slowness of DNS and SMTP, qmail overlaps 20 simultaneous +deliveries by default, so it zooms quickly through mailing lists. (This +is why I finished qmail: I had to get a big mailing list set up.) + +Simple: qmail is vastly smaller than any other Internet MTA. Some +reasons why: (1) Other MTAs have separate forwarding, aliasing, and +mailing list mechanisms. qmail has one simple forwarding mechanism that +lets users handle their own mailing lists. (2) Other MTAs offer a +spectrum of delivery modes, from fast+unsafe to slow+queued. qmail-send +is instantly triggered by new items in the queue, so the qmail system +has just one delivery mode: fast+queued. (3) Other MTAs include, in +effect, a specialized version of inetd that watches the load average. +qmail's design inherently limits the machine load, so qmail-smtpd can +safely run from your system's inetd. + +Replacement for sendmail: qmail supports host and user masquerading, +full host hiding, virtual domains, null clients, list-owner rewriting, +relay control, double-bounce recording, arbitrary RFC 822 address lists, +cross-host mailing list loop detection, per-recipient checkpointing, +downed host backoffs, independent message retry schedules, etc. In +short, it's up to speed on modern MTA features. qmail also includes a +drop-in ``sendmail'' wrapper so that it will be used transparently by +your current UAs. diff --git a/BLURB2 b/BLURB2 @@ -0,0 +1,26 @@ +Mailing list management is one of qmail's strengths. Notable features: + +* qmail lets each user handle his own mailing lists. The delivery +instructions for user-whatever go into ~user/.qmail-whatever. + +* qmail makes it really easy to set up mailing list owners. If the user +touches ~user/.qmail-whatever-owner, all bounces will come back to him. + +* qmail supports VERPs, which permit completely reliable automated +bounce handling for mailing lists of any size. + +* SPEED---qmail blasts through mailing lists an order of magnitude +faster than sendmail. For example, one message was successfully +delivered to 150 hosts around the world in just 70 seconds, with qmail's +out-of-the-box configuration. + +* qmail automatically prevents mailing list loops, even across hosts. + +* qlist, included in the qmail package, deals with subscription requests +safely and automatically. + +* qmail allows inconceivably gigantic mailing lists. No random limits. + +* qmail handles aliasing and forwarding with the same simple mechanism. +For example, Postmaster is controlled by ~alias/.qmail-postmaster. This +means that cross-host loop detection also applies to aliases. diff --git a/BLURB3 b/BLURB3 @@ -0,0 +1,90 @@ +Here are some of qmail's features. + +Setup: +* automatic adaptation to your UNIX variant---no configuration needed +* AIX, BSD/OS, FreeBSD, HP/UX, Irix, Linux, OSF/1, SunOS, Solaris, and more +* automatic per-host configuration (qmail-config) +* quick installation---no big list of decisions to make + +Security: +* clear separation between addresses, files, and programs +* minimization of setuid code (qmail-queue) +* minimization of root code (qmail-start, qmail-lspawn) +* five-way trust partitioning---security in depth +* optional logging of one-way hashes, entire contents, etc. (QUEUE_EXTRA) + +Message construction (qmail-inject): +* RFC 822, RFC 1123 +* full support for address groups +* automatic conversion of old-style headers to RFC 822 format +* header line length limited only by memory +* host masquerading (control/defaulthost) +* user masquerading (MAILUSER, MAILHOST) +* sendmail hook for compatibility with current user agents + +SMTP service (qmail-smtpd): +* RFC 821, RFC 1123, RFC 1651, RFC 1652, RFC 1854 +* 8-bit clean +* 931/1413/ident/TAP callback (tcp-env) +* relay control---stop unauthorized relaying by outsiders (control/rcpthosts) +* no interference between relay control and forwarding +* tcpd hook---reject SMTP connections from known abusers +* automatic recognition of local IP addresses +* per-buffer timeouts +* hop counting + +Queue management (qmail-send): +* instant handling of messages added to queue +* parallelism limit (control/concurrencyremote, control/concurrencylocal) +* split queue directory---no slowdown when queue gets big +* quadratic retry schedule---old messages tried less often +* independent message retry schedules +* automatic safe queueing---no loss of mail if system crashes +* automatic per-recipient checkpointing +* automatic queue cleanups (qmail-clean) +* queue viewing (qmail-qread) +* detailed delivery statistics (qmailanalog, available separately) + +Bounces (qmail-send): +* QSBMF bounce messages---both machine-readable and human-readable +* HCMSSC support---language-independent RFC 1893 error codes +* double bounces sent to postmaster + +Routing by domain (qmail-send): +* any number of names for local host (control/locals) +* any number of virtual domains (control/virtualdomains) +* domain wildcards (control/virtualdomains) +* configurable percent hack support (control/percenthack) +* UUCP hook + +SMTP delivery (qmail-remote): +* RFC 821, RFC 974, RFC 1123 +* 8-bit clean +* automatic downed host backoffs +* artificial routing---smarthost, localnet, mailertable (control/smtproutes) +* per-buffer timeouts +* passive SMTP queue---perfect for SLIP/PPP (serialmail, available separately) + +Forwarding and mailing lists (qmail-local): +* address wildcards (.qmail-default, .qmail-foo-default, etc.) +* sendmail/smail /etc/aliases compatibility (qmsmac, available separately) +* mailing list owners---automatically divert bounces and vacation messages +* VERPs---automatic recipient identification for mailing list bounces +* Delivered-To---automatic loop prevention, even across hosts +* automatic subscription management (qlist) + +Local delivery (qmail-local): +* user-controlled address hierarchy---fred controls fred-anything +* mbox delivery +* reliable NFS delivery (maildir) +* user-controlled program delivery: procmail etc. (qmail-command) +* optional new-mail notification (qbiff) +* optional NRUDT return receipts (qreceipt) +* conditional filtering (condredirect) + +POP3 service (qmail-popup, qmail-pop3d): +* RFC 1939 +* UIDL support +* TOP support +* APOP hook +* modular password checking (checkpassword, available separately) diff --git a/BLURB4 b/BLURB4 @@ -0,0 +1,44 @@ +qmail's modular, lightweight design and sensible queue management make +it the fastest available message transfer agent. Here's how it stacks up +against the competition in five different speed measurements. + +* Scheduling: I sent a message to 8192 ``trash'' recipients on my home +machine. All the deliveries were done in a mere 78 seconds---a rate of +over 9 MILLION deliveries a day! Compare this to the speed advertised +for Zmailer's scheduling: 1.1 million deliveries a day on a +SparcStation-10/50. (My home machine is a 16MB Pentium-100 under BSD/OS, +with the default qmail configuration. qmail's logs were piped through +accustamp and written to disk as usual.) + +* Local mailing lists: When qmail is delivering a message to a mailbox, +it physically writes the message to disk before it announces success--- +that way, mail doesn't get lost if the power goes out. I tried sending a +message to 1024 local mailboxes on the same disk on my home machine; all +the deliveries were done in 25.5 seconds. That's more than 3.4 MILLION +deliveries a day! Sending 1024 copies to a _single_ mailbox was just as +fast. Compare these figures to Zmailer's advertised rate for throwing +recipients away without even delivering the message---only 0.48 million +per day on the SparcStation. + +* Mailing lists with remote recipients: qmail uses the same delivery +strategy that makes LSOFT's LSMTP so fast for outgoing mailing lists--- +you choose how many parallel SMTP connections you want to run, and qmail +runs exactly that many. Of course, performance varies depending on how +far away your recipients are. The advantage of qmail over other packages +is its smallness: for example, one Linux user is running 60 simultaneous +connections, without swapping, on a machine with just 16MB of memory! + +* Separate local messages: What LSOFT doesn't tell you about LSMTP is +how many _separate_ messages it can handle in a day. Does it get bogged +down as the queue fills up? On my home machine, I disabled qmail's +deliveries and then sent 5000 separate messages to one recipient. The +messages were all safely written to the queue disk in 23 minutes, with +no slowdown as the queue filled up. After I reenabled deliveries, all +the messages were delivered to the recipient's mailbox in under 12 +minutes. End-to-end rate: more than 200000 individual messages a day! + +* Overall performance: What really matters is how well qmail performs +with your mail load. Red Hat Software found one day that their mail hub, +a 48MB Pentium running sendmail 8.7, was running out of steam at 70000 +messages a day. They shifted the load to qmail---on a _smaller_ machine, +a 16MB 486/66---and now they're doing fine. diff --git a/CHANGES b/CHANGES @@ -0,0 +1,1204 @@ +19970415 version: qmail 1.01. +19970414 doc: tightened up qmail-upgrade.7. +19970414 code: rewrote rewrite(). +19970414 code: implemented recipientmap. suggested by RDM. +19970414 doc: auto-configured qmail home directory in qmail-control.5, + qmail-newu.8, qmail-pw2u.8, qmail-start.8, qmail-users.5. +19970414 port: Solaris needs socket libs for gethostname. impact: can't + compile under Solaris. fix: use socket.lib for qmail-local. +19970412 code: introduced stralloc_starts. +19970412 code: introduced str_equal. +19970412 code: introduced str_start. +19970412 code: introduced byte_equal. +19970412 code: made an optional aliasempty arg for qmail-start. +19970412 code: made an aliasempty arg for qmail-lspawn. +19970412 code: changed ALIAS_EMPTY to an arg for qmail-local. +19970412 port: UnixWare returns >0 for SIOCGIFCONF. impact: ipme fails + under UnixWare. fix: check for >=0, not =0. tnx JD. +19970412 port: DGUX does not have ranlib. impact: can't compile under + DGUX. fix: added dgux line to make-makelib. tnx HWM. +19970412 code: changed maildir library to skip any filename beginning + with dot. tnx SP. +19970412 doc: added FAQ entry about aliases with dots. +19970412 doc: clarified in qmail-inject.8 that default envelope sender + is the same as _default_ From address. +19970411 code: renamed qmail-makectl as qmail-config. +19970411 code: renamed qmail-alias as qmail-local. +19970411 code: switched from signal library to sig library. +19970411 code: switched from qqtalk library to qmail library. +19970411 code: switched from getline library to getln library. +19970411 code: massive library cleanups. +19970411 code: revamped autoconfiguration system. +19970411 code: revamped configuration interface. +19970411 code: eliminated qmail-home. +19970411 code: eliminated tokenize. +19970220 qmail 1.00. +19970219 change: various documentation tweaks. +19970218 change: updated THOUGHTS. +19970218 change: talked about SPAWN_NUMD in FAQ. tnx EC. +19970210 change: noted in maildir.5 that readers should skip any name + starting with a dot. tnx SP. +19970209 change: added note to splogger.8 about reliability. tnx BT. +19970209 change: added section to FAQ on slow sendmail switch. tnx BT. +19970206 change: added section to FAQ about dtcm. tnx PJG. +19970206 change: tweaked maildir.5. +19970201 change: added MH spost note to FAQ. tnx TU. +19970131 change: reorganized FAQ. +19970131 change: added web references to FAQ. +19970124 change: tweaked qmail-upgrade man page. +19970120 qmail 0.96, gamma. +19970120 change: removed various try* in auto-configuration. +19970120 bug: qmail-inject fails to quote argument addresses. impact: + addresses containing special characters could be misinterpreted + or rejected. tnx C2F. fix: use quote2(). +19970120 portability problem: ESIX puts syslog() and openlog() into + -lgen. impact: can't compile under ESIX. fix: put -lgen into + LIBS for unix_sv. tnx RN. +19961221 qmail 0.95, gamma. +19961218 change: added various try* to TARGETS. tnx SA. +19961216 change: clarified in qmail-send.8 that virtualdomains does not + apply to domains listed in locals. +19961216 change: slurpclose() now closes fd on out-of-memory. makes it + more widely applicable. +19961215 change: replaced elm instructions in INSTALL.mbox with an + explanation of what source change to make. tnx AB. +19961212 portability problem: under NEWS-OS, time_t needs sys/types.h. + impact: couldn't compile under NEWS-OS. fix: include + sys/types.h in predate.c. tnx TU. +19961211 change: used timeoutread, timeoutwrite in remoteinfo(). tnx + REB. +19961210 portability problem: apparently some SGIs produce a systype of + irix64. impact: couldn't compile on those systems. fix: handle + irix64 in make-cmds. tnx M3S. +19961208 change: added note to maildir2mbox.1 about mbox locking. +19961208 qmail 0.94, gamma. +19961207 change: added QMAILDEFAULTDOMAIN, QMAILDEFAULTHOST, + QMAILIDHOST, QMAILPLUSDOMAIN. tnx BTW. +19961206 cleanup: readsubdir() protects itself against name overflow, + rather than depending on caller. +19961204 change: changed FAQ 7.3 to prohibit fixup relaying. +19961203 change: added note to FAQ about possibly having to put a space + before "$SENDER" for uux. tnx FW. +19961202 change: added FAQ entry on QUEUE_EXTRA. +19961202 change: added FAQ entry on backups. tnx DP. +19961202 change: added note to INSTALL.mbox about qpopper. tnx VV. +19961201 change: replaced logger with splogger in FAQ 5.1. tnx FPL. +19961201 change: used netmask example for tcpcontrol in FAQ. tnx FPL. +19961201 change: added note to README about the mailing list. tnx FPL. +19961201 change: documented rcpthosts wildcards. tnx RN. +19961201 change: added note to FAQ about making mailx use datemail. +19961201 change: added datemail. function requested by several people; + approach suggested by TG. +19961201 change: added predate. +19961129 change: added QUEUE_EXTRA, QUEUE_EXTRALEN. +19961129 change: qmail-remote bounces messages with partial final lines. +19961129 change: added atomcheck() to quote crappy atoms. +19961129 change: revised atomok() to let atoms deal with more crap. +19961127 change: qmail-send adds note to deferral if flagdying. tnx TG. +19961127 change: split off maildirbounce, maildir2qmtp, and maildir2smtp + into a separate serialmail package. +19961126 change: eliminated beta success reports from README. +19961124 change: forced res_query() return value to fit inside incoming + buffer size. allegedly there are buggy versions of res_query() + that don't guarantee this. +19961122 qmail 0.93, gamma. +19961122 change: allowed empty arg list in forward. +19961121 change: qmail-smtpd now uses unknown (like qmail-qmtpd) rather + than dying if environment variables are not set. +19961121 cleanup: reorganized helo handling in qmail-smtpd.c. +19961121 cleanup: eliminated newfield_rec. +19961121 cleanup: introduced DATE822FMT. used it in received.c. +19961121 cleanup: introduced received.c. used it in qmail-qmtpd.c, + qmail-smtpd.c. +19961121 change: qmail-smtpd now generates a new timestamp for each + message. tnx PJG. +19961121 cleanup: used stralloc in newfield. +19961121 cleanup: eliminated newfield_cc. +19961121 change: eliminated hfield_mort(). +19961119 change: added 2-minute damper on tcpto. +19961118 change: wrote defaults for readfile controls in showctl. +19961117 change: control_readfile() now allows comments and blank lines. + tnx LW. +19961117 change: qmail-start sets logger gid to GID_NOFILES. +19961117 bug: ipme_init() uses a fixed-length buffer for SIOCGIFCONF. + impact: qmail-smtpd and qmail-remote will die if there are too + many local IP addresses. tnx MD. fix: ipme_init() now + dynamically allocates space, up to 200000 bytes, as long as + SIOCGIFCONF keeps failing. note that this is a very widespread + bug; it's in amd, exim, mrouted, named, nntpd, rarpd, sendmail, + tcpdump, timed, xntpd, and probably dozens more programs. +19961117 portability problem: on BSD 4.4 and various other systems, + SIOCGIFCONF will truncate long lists and return success. + impact: on those systems, qmail-smtpd and qmail-remote will + miss some local IP addresses if there are too many. fix: + ipme_init() now checks whether there is enough space left in + the buffer for another ifreq, plus 64 bytes JIC. yuck. +19961117 change: ipmeprint now flushes only at end. +19961117 cleanup: introduced subfdinsmall. used it in qmail-clean.c, + qmail-qmtpd.c. +19961117 cleanup: introduced subfdoutsmall. used it in hostname.c, + printbreak.c, printnumd.c, printsplit.c, qmail-alias.c, + qmail-clean.c, qmail-getpw.c, qmail-qmtpd.c, maildir2smtp.c, + maildir2qmtp.c. +19961117 change: moved subfderr buf up to 256 characters. +19961117 change: added maildirbounce. tnx MD, TG. +19961116 change: maildir2smtp and maildir2qmtp now print filenames for + permanent bounces. tnx MD. +19961116 change: in SECURITY, ``eleven most recent sendmail security + holes, five'' -> ``twelve most recent sendmail security holes, + six.'' +19961116 change: rewrote qmail-showctl more professionally. +19961115 change: added several tests to find-systype.sh. this will + affect many systypes. +19961115 change: qmail-alias now treats most exit codes as soft errors. +19961115 change: revamped exit codes everywhere for 0, 100, 111. +19961114 change: added splogger. +19961114 portability problem: Sun's cc recognizes sqrt() as a builtin, + even if math.h is not included and sqrt is defined statically. + yuck. impact: when qmail is compiled with Sun's cc, next-retry + times are all screwed up. tnx PJG. fix: my sqrt() is now called + squareroot(). +19961114 change: dns_ip() now recognizes [1.2.3.4]. tnx DS. +19961112 change: enabled x option in sendmail. tnx DS. +19961111 change: added SIGHUP handling to qmail-send. suggested by many + people. +19961111 bug: control routines returned incorrect codes for some + out-of-memory conditions. impact: none; conditions cannot + happen with sane control files. fix: return -1. +19961111 change: added SIGALRM handling to qmail-send. suggested by many + people. +19961111 change: eliminated flagnobreak (-b/-B) from qmail-pw2u. +19961111 change: qmail-getpw now allows hyphens inside usernames. +19961111 change: added users/append to qmail-pw2u. tnx G2A. +19961111 change: added badmailfrom to qmail-smtpd. requested by several + people. +19961110 change: replaced elm instructions in INSTALL.mbox with a simple + note to set incomingfolders in elm.rc. tnx AB. +19961110 change: replaced ``owner hack'' with ``variable envelope + return paths'' throughout the documentation. tnx DS. +19961110 change: qmail-setup installs man pages as well as cat pages. +19961110 change: renamed qmail-newuser as qmail-newu. tnx G2A. +19961110 change: renamed qmail-pw2user as qmail-pw2u. tnx G2A. +19961105 change: set path in INSTALL.boot. tnx TJH. +19961105 change: noted in qmail-smtpd.8 that addresses without @ are + always allowed through. +19961105 change: indicated at various spots in FAQ that rcpthosts has to + be updated. suggested by various people. +19961105 change: indicated at various spots in FAQ that qmail has to be + restarted. suggested by various people. +19961029 change: fixed typo in maildir2qmtp.1. tnx BG. +19961026 qmail 0.92, gamma. +19961026 bug: qmail-getpw did not 0-terminate usernames. tnx CF. impact: + qmail-getpw would crash on some systems, deferring local + deliveries. fix: 0-terminate. +19961025 cleanup: renamed auto-hassgprm.h to hassgprm.h. +19961025 cleanup: renamed auto-hassgact.h to hassgact.h. +19961024 change: replaced qmail-alias.0 with dot-qmail.0 in + INSTALL.alias. tnx MW. +19961022 change: switched uids as early as possible in qmail-start.c. +19961022 change: in SECURITY, ``ten most recent sendmail security + holes, five'' -> ``eleven most recent sendmail security holes, + five.'' +19961022 change: quote_need() now treats non-ASCII characters the same + way as control characters. +19961022 change: added version and home page to qmail.7. +19961022 cleanup: introduced slurpclose.c. used it in qmail-alias.c, + qmail-lspawn.c. +19961021 portability problem: AT&T NCR boxes need stdio.h before + arpa/nameser.h. impact: dns.c would not compile. fix: include + stdio.h. tnx HS. +19961021 change: added AIX section to INSTALL.ids. tnx SSB. +19961021 change: added qmail-pw2user. +19961020 change: added qmail-pw2user.8. +19961020 change: qmail-alias now dies soft on EACCES/EPERM for .qmail. +19961020 change: eliminated root comments from INSTALL.qsmhook. +19961020 change: various improvements in FAQ. +19961017 change: added QLX_ROOT. +19961017 change: renamed hosts in FAQ. tnx SLB. +19961017 change: in dot-qmail.5, documented envnoathost effects. tnx RN. +19961017 change: revamped addresses.5. +19961017 change: added stripvdomprepend() for better bounces. tnx PT. +19961012 portability problem: under HP-UX 9, can't setgroups() to 65537. + impact: couldn't compile under HP-UX 9. fix: use 0 instead of + 65537 in chkshsgr.c. tnx HHO. +19961008 change: added several qlx codes. +19961008 cleanup: eliminated qlx from qmail-alias. +19961008 change: qmail-lspawn runs qmail-getpw as UID_PW. +19961008 change: added qmail-newuser. +19961008 change: added cdb support to qmail-lspawn. +19961008 change: integrated cdb. +19961007 change: added qmail-users.5. +19961007 change: eliminated usermap. +19961007 cleanup: switched execvp to execv in sendmail, qmail-lspawn. +19961007 change: used qmail-getpw in qmail-lspawn. +19961007 change: renamed LSPAWN_USERLEN as GETPW_USERLEN. +19961007 change: added qmail-getpw. +19961007 change: created users subdirectory of CONF_HOME. +19961007 change: fixed typo in FAQ. tnx J1B. +19961006 change: replaced subfdout with a small ss in qmail-alias. +19961006 change: reduced qmail-alias buffer sizes to 1024. +19961003 change: added note to maildir2smtp.0 about maildirmake. tnx SM. +19961003 bug: if ipme_init() returned -1, qmail-remote would continue, + blindly assuming that all addresses are local. impact: on + systems with too many aliases, all remote deliveries fail. tnx + MD. fix: qmail-remote now dies with temp_oserr() on any result + other than 1. +19961003 portability problem: all pre-4.9.4 versions of bind barf, + badly, on CNAME queries to lame servers. what a crappy system. + even if the resolver doesn't barf, the next name server down + the line may barf. impact: qmail can't get mail through to + domains that are (1) lame and (2) running old versions of bind. + fix: never, ever, do a CNAME query. dns_cname() now does an ANY + query instead. this, like sendmail's analogous procedure, is + unreliable when a CNAME is mixed with other records. +19961001 cleanup: switched to libfd in qmail-start.c. +19960929 cleanup: renamed auto-hasmkffo.h to hasmkffo.h. +19960928 cleanup: reorganized qmail-start.c. +19960928 cleanup: used libfd in preline.c, qmail-lspawn.c, + qmail-popup.c, qmail-rspawn.c, qmail-start.c, qqtalk.c, + qsmhook.c. +19960928 cleanup: added libfd. +19960927 change: in SECURITY, ``nine most recent sendmail security + holes, four'' -> ``ten most recent sendmail security holes, + five.'' +19960926 change: added tcpcontrol notes to FAQ. +19960926 change: qmail-smtpd now immediately closes connection, with a + warning message dedicated to Solaris, if stray newlines show up + in the incoming data. +19960926 change: added INSTALL.boot. +19960926 portability problem: on systems that can handle IP interface + aliases (i.e., on sa_len systems), SIOCGIFADDR returns the + primary address for an alias. impact: ipme_init() did not + include alias addresses. fix: ipme_init() avoids SIOCGIFADDR on + sa_len systems; on these systems, the address we want is + already in ifr. tnx DM. +19960926 change: qmail-alias kills itself if locking takes longer than + 30 seconds. +19960926 change: qmail-pop3d no longer moves messages. tnx RS. +19960924 change: added note to FAQ about descriptors limit. tnx RD. +19960922 change: open_trunc() now uses 644. +19960922 change: qmail-setup now does umask(077). +19960922 change: maildir2mbox now does umask(077). +19960922 change: moved subfderr buf up to 64 characters. +19960920 change: in SECURITY, ``eight most recent sendmail security + holes, three'' -> ``nine most recent sendmail security holes, + four.'' +19960920 portability problem: init run commands are subject to job + control signals under more systems than HP-UX. impact: on some + systems (e.g., Solaris), qmail daemons would be killed. fix: + INSTALL now tells everybody to use csh -cf. +19960920 change: added queue-run section to FAQ. +19960920 change: in pine-crashing question in FAQ, added -oem and -oi, + so that change will work with the real sendmail too. +19960919 change: added CNAME section to FAQ. tnx to various people. +19960919 change: eliminated QQX_EXECHARD and QQT_EXECHARD. this means + that all qmail-queue invocation failures are now soft, even + things like EPERM. +19960919 change: replaced ``No such address'' with ``Sorry, no mailbox + here by that name.'' tnx G2A. +19960919 change: qmail-remote now includes host name in no-such-host + messages. tnx G2A. +19960919 change: replaced ``Temporarily unable to canonicalize address'' + with ``CNAME lookup failed temporarily.'' +19960918 change: improved an error message in qmail-alias.c. tnx TG. +19960918 change: added SHELL=/bin/sh to Makefile. tnx JL. +19960916 change: reorganized INSTALL.ids a bit. +19960916 change: ``from smtpd'' is now ``from network''. +19960916 change: SMTPD is now DAEMON. +19960916 change: qmail-start sets logger uid to UID_LOG. tnx JLH. +19960916 change: added CONF_USERL. +19960916 change: iaafmt() now puts a dot on in-addr.arpa. +19960915 change: added UPGRADE. suggested by several people. +19960915 change: added qsutil error messages to qmail-log.5. +19960915 change: qsutil error messages are now alerts. +19960915 portability problem: on some systems, logger appears to use + syslog(pri,buf) instead of syslog(pri,"%s",buf). tnx JC. + impact: logger could barf or crash if fed messages containing + %. an attacker could easily cause a crash, eliminating qmail's + logs. fix: % is no longer considered safe for logs. +19960912 cleanup: split seek.c into seek_*.c. +19960912 cleanup: replaced seek_to() with seek_set(). +19960912 cleanup: introduced libseek.a. +19960907 cleanup: split case.c into case_*.c. +19960907 cleanup: introduced libcase.a. +19960907 cleanup: split wait.c into wait_*.c. +19960907 cleanup: introduced libwait.a. +19960907 cleanup: renamed auto-haswaitp.h to haswaitp.h. +19960907 cleanup: split open.c into open_*.c. +19960907 cleanup: introduced libopen.a. +19960904 change: added generic pointer to qmail-control.5. tnx HW. +19960904 change: rewrote rcpthosts section in FAQ. tnx HW. +19960904 change: added organization section to FAQ. tnx HW. +19960902 qmail 0.91, gamma. +19960902 change: control_readfile() can now handle partial lines. tnx + JDHB. +19960902 change: eliminated non-fqdn note from FAQ. next version of + tcpserver will use DNS directly. +19960902 change: qlist now uses NEWSENDER, not SENDER. +19960902 change: qmail-pop3d no longer obtains a lock. tnx RS. +19960902 change: put }g on all seds in Makefile. +19960831 change: noted in qmail-control.5 that comments are not allowed + in control files. tnx J2B. +19960829 change: used double union in alloc.c. tnx ME. +19960829 change: replaced semicolon with colon for smtproutes port. +19960829 change: in INSTALL, put make man just before make setup. +19960829 change: changed a few qmail messages into alerts. +19960829 cleanup: renamed datetime_gmt as datetime_tai. +19960829 change: added note to UUCP question that some UUCP software + doesn't want preline -f. tnx SB. +19960829 change: added question 2.4 to FAQ on SLIP/PPP. +19960828 change: replaced owner- with owner-@host-@[] in qmail-inject. +19690828 change: replaced owner- with owner-@host-@[] in qmail-alias. +19960828 change: replaced owner- with owner-@host-@[] in injectbounce(). +19960828 change: replaced owner- with owner-@host-@[] in senderadd() for + owner hack. +19960828 change: qmail-inject -n now prints Return-Path. +19960825 cleanup: revised ending code in token_addrlist(). +19960825 change: tokenize now uses linelen 0 for unparse. +19960825 change: if linelen is 0 in token822_unparse, no length limit. +19960825 change: added LINELEN macro to qmail-inject for unparse. +19960825 change: token822_unparse now takes linelen argument. (leaving + two spaces on the right before linelen.) +19960824 cleanup: renamed token as token822. +19960822 portability problem: under NEWS-OS, /bin/mail and /usr/ucb/mail + invoke sendmail with -E and -J options. tnx TU. impact: + couldn't send mail with those programs. fix: accept opts, + including _optional_ args. ugh. +19960821 change: sendmail now quits if invoked as newaliases. tnx TU. +19960821 portability problem: under NEWS-OS, dirent.h needs sys/types.h. + tnx TU. this POSIX violation also appears in some versions of + FreeBSD. impact: couldn't compile under NEWS-OS. fix: include + sys/types.h in direntry.h* and trydrent.c. [sigh] +19960821 change: added concurrencyremote question to FAQ. +19960821 change: added chkspawn. +19960821 change: moved default SPAWN_NUMD up to 120. +19960818 change: allowed ;port in smtproutes. tnx AL. +19960818 change: introduced port in qmail-remote.c. +19960818 change: qmail-queue records qp in Received lines. 2 lines of + code. tnx ME. +19960818 change: in SECURITY, ``seven most recent sendmail security + holes'' -> ``eight most recent sendmail security holes.'' +19960818 change: qmail-pop3d now appends an extra blank line to every + message, for compatibility with popper. some clients can't + deal with the right thing, unfortunately. tnx FPL. +19960818 change: added qmail-tcpto. +19960818 change: eliminated cc -posix for NeXTs. tnx SA. +19960818 change: eliminated loadfifo. tnx SA. +19960818 change: integrated auto-configured fifo.c code from SA. +19960817 change: put SYSDEPS into a more reasonable order. +19960813 change: indicated possibility of duplication when qmail-remote + gets a dead connection after DATA. tnx ME. +19960813 change: documented qmail-inject environment variables. +19960813 change: supported per-recipient owner hack in qmail-inject. +19960813 change: supported per-message owner hack in qmail-inject. +19960813 change: introduced hackedruser into qmail-inject. +19960813 change: introduced QMAILRUSER, QMAILRHOST. +19960812 change: added QMAILINJECT option to allow address-comment form. +19960812 change: made name-address form the default in qmail-inject. +19960812 change: added QMAILINJECT options f and m to delete From and + Message-ID on input. tnx LL. +19960812 change: added QMAILINJECT environment variable. +19960812 change: added QMAILHOST, QMAILUSER, QMAILNAME to override + MAILHOST, MAILUSER, MAILNAME. tnx MG. +19960812 change: added qmail-showctl. +19960812 portability problem: under Solaris 2.4 and possibly other + systems, the linker does not give generic alignment to an array + of 4096 chars. tnx JP. impact: some subset of the programs + would (reliably) die with a bus error; in the Solaris case, + maildir2mbox. fix: redefine space in alloc.c to be aligned. +19960812 change: qmail-remote no longer does CNAME lookups if there's an + artificial SMTP route. tnx ME. +19960812 change: added flagcname arg to addrmangle() in qmail-remote. +19960812 cleanup: moved host/relayhost processing earlier in + qmail-remote. +19960812 change: qmail-remote stops before DATA if no RCPTs were + successful. tnx JLH. +19960812 change: rewrote rcpthosts explanation in FAQ. +19960811 change: added qmail-log.5. +19960811 change: introduced ALIAS_PATERNALISM. configurability requested + by several people. +19960811 change: eliminated go-writability test for qmeox(). the alleged + value of paternalism is nonexistent if nobody even notices + you're doing it. +19960811 change: in qbiff, changed no-/-allowed to no-/-at-beginning, + no-dots-allowed, must-be-nonempty. tnx MD. +19960811 change: in mbox.5, discouraged mail readers from looking for + From_ lines only after blank lines. too much crap in the world. +19960811 change: added subject line to qreceipt success notices. +19960811 change: added subject line to qmail-send bounce messages. +19960811 change: qmail-alias now expects dash arg. this finally gives + lspawn complete control over the local -> ~user/.qmail-ext map. +19960811 change: qmail-lspawn passes dash arg to qmail-alias. +19960811 change: reorganized qlist acknowledgment format. again. +19960811 change: documented EXT, EXT2, EXT3, EXT4. tnx BB. +19960810 change: qmail-makectl now copies locals to rcpthosts. should be + a better default. suggested by TK. +19960805 portability problem: new makefile generator put in tabs again. + sigh. impact: couldn't compile under some systems. fix: same as + before. tnx TG. +19960804 change: added tcpserver instructions to FAQ. +19960804 change: reorganized FAQ server instructions into a new section. +19960801 qmail 0.90, gamma. +19960801 change: qmail-qmtpd now supports rcpthosts, RELAYCLIENT. +19960731 change: default NUMD is now 29. this prepares for weird systems + where getpwnam() needs more than one descriptor (but the + descriptor limit is still 64! ... you never know), and for + possible future getpwnam() replacements. +19960731 change: popped subfderr buffer up to 32 characters. made sure + that everybody flushed subfderr as necessary. +19960731 change: maildir2qmtp now prints filenames and responses. +19960731 change: maildir2smtp now prints filenames it's trying and + relevant portion of SMTP responses. +19960731 change: used succwrite() in maildir2smtp, maildir2qmtp. + simplifies code quite a bit. +19960731 change: qmail-remote's blast() checks sooner for write errors. +19960731 change: added better -e option to sendmail. tnx TG. +19960731 change: added maildir2qmtp. +19960730 cleanup: eliminated die_nomem() in maildir2smtp.c. +19960730 change: dns_cname now pretends that "foo." is a CNAME for "foo" + to give the desired behavior for people who misuse DNS and + violate RFC 822. tnx RN. +19960730 change: dns_cname now tests for empty names and ] on every + loop. +19960730 change: used LSPAWN_BREAK in qmail-send.c for usermap. +19960730 change: updated header example in qmail-header.5. +19960730 change: added printbreak. auto-configured BREAK in dot-qmail.5, + qmail-lspawn.7, qmail-send.8, qmail-upgrade.7, qlist2. +19960730 change: added printnumd. auto-configured NUMD in qmail-send.8, + qmail-limits.8. +19960730 change: added printsplit. auto-configured split in qmail-upq. +19960730 change: added dot-qmail.5. +19960730 change: qmail-smtpd now treats HELO as including RSET. +19960730 change: added moreinfo to qlist usage message. +19960729 change: improved an error message in qmail-alias. +19960729 cleanup: merged qmeox(), qmeodx(). +19960729 bug: failure to stat .qmail-owner was not an error. impact: if + stat failed temporarily (e.g., because of NFS), .qmail-owner + would be incorrectly ignored, so outgoing message would have + wrong envelope sender. fix: qmail-alias does temp_nfsqmail() if + stat() returns a temporary error. +19960729 change: added RFCOWNER. +19960729 change: added qmtpd setup question to FAQ. +19960729 change: added qmail-qmtpd. +19960728 change: revamped maildir2smtp error messages. +19960728 change: revamped maildirwatch error messages. +19960728 change: revamped maildir2mbox error messages. +19960728 change: used strerr in maildir_scan(). +19960728 change: used strerr in maildir_chdir(). +19960728 change: introduced strerr. +19960728 bug: the new tcp-env tried to read from an ndelay socket. + impact: TCPREMOTEINFO would always be empty. fix: unset ndelay + in remoteinfo.c. +19960728 bug: if maildir2smtp saw a permanent failure after MAIL, it + failed to do RSET. impact: all further messages would be + rejected at the MAIL stage. fix: maildir2smtp now always does + RSET. tnx JW. +19960728 cleanup: qmail-alias now applies lowercase and dot-to-colon + conversion directly to dashext, leaving everything else alone. + this works since all .qmail access is factored through dashext. +19960727 portability problem: under NeXTStep, -posix is almost entirely + broken. impact: qmail daemons would dump core under NeXTStep. + fix: turn off -posix, except for loading qmail-setup, which + needs mkfifo(); NeXT, bless them, didn't put mkfifo() into the + C library where it belongs. this requires a new make command, + namely loadfifo. +19960727 change: all characters 33-126 are now considered safe for logs. + tnx MD. +19960727 cleanup: eliminated qp variable from mailforward(). +19960727 cleanup: maildirwatch.c includes headerbody.h. +19960727 cleanup: eliminated match from maildirwatch.c. +19960727 cleanup: eliminated code variable from maildir2smtp.c:doit(). +19960727 cleanup: maildir2smtp.c includes scan.h. +19960727 cleanup: maildir.c includes str.h. +19960727 cleanup: qmail-popup.c now includes exit.h. +19960727 cleanup: qmail-pop3d.c now includes exit.h. +19960727 cleanup: eliminated path from qmail-start.c. +19960727 cleanup: eliminated birthplusnn from nextretry(). +19960727 cleanup: eliminated r from timeoutconn(). +19960727 cleanup: tcpto.c now includes byte.h. +19960727 cleanup: spawn.c now declares initialize(). +19960727 cleanup: qmail-lspawn.c now includes str.h, byte.h. +19960727 cleanup: qmail-inject.c now includes quote.h. +19960727 change: qmail-check now checks separately for group + readability and other readability. +19960727 bug: maildir2smtp didn't check flagehlo in PIPELINING parsing. + impact: a server that said PIPELINING at any point, not just + EHLO, would receive pipelined data. fix: check flagehlo. +19960727 bug: readsubdir was calling pause(). impact: if a subdirectory + was removed, qmail-send would hang. fix: use rs->pause(). +19960727 change: used error_str in qmail-qread. +19960727 change: qmail-qread now looks for local/remote open errors. +19960727 cleanup: added warn() in qmail-qread.c. +19960727 change: qmail-qread now exits 111 for temporary errors. +19960727 change: used error_str in qmail-setup. +19960727 change: introduced error_str. +19960727 change: replaced qmail-check with make check in INSTALL. +19960727 change: added check target to Makefile. +19960727 change: replaced qmail-setup with make setup in INSTALL. +19960727 change: indirected fake targets through do- targets. +19960727 change: added setup target to Makefile. +19960727 change: qmail-makectl now makes sure that defaultdomain has + at least one dot. e.g., enteract.com -> enteract.com, not com. +19960726 bug: quote() failed to quote commas. impact: addresses + containing commas would not have been quoted correctly for + Return-Path or for SMTP MAIL FROM. fix: quote commas. +19960726 change: sendmail now mentions qmail-qread, not qmail-mailq. +19960726 change: qmail-alias now expects ext arg. this eliminates + LSPAWN_BREAK from qmail-alias and gives lspawn almost complete + control over the local -> ~user/.qmail-ext transformation. the + exception is that qmail-alias always uses ~user/.qmail, + ignoring ext, if local is the same as user. +19960726 change: qmail-lspawn passes ext to qmail-alias. +19960726 change: alloc() now uses up a 4K space before calling malloc(). +19960726 change: ipalloc allocation base is now 10. 100 was silly. +19960726 change: stralloc allocation base is now 30. +19960726 change: injectbounce() now supports the owner hack. +19960726 change: qmail-smtpd no longer requires HELO. tnx K1J. +19960726 cleanup: replaced makereceived() with dohelo(). +19960726 change: qmail-smtpd is back to 555 for syntax errors. +19960725 change: qmail-alias now supports the owner hack. tnx to RN for + prodding me to look at this problem. +19960725 change: senderadd() now supports the owner hack. +19960725 cleanup: split off senderadd(). +19960725 change: added pine-crashing note to FAQ. +19960725 change: added procmail config.h note to INSTALL.mbox. +19960725 change: added elm TMPDIR note to INSTALL.mbox. +19960725 change: added pine.conf note to INSTALL.mbox. +19960724 change: added fixup note to FAQ. +19960724 change: qmail-inject now exits 111 for temporary errors. +19960724 change: qmail-smtpd now appends RELAYCLIENT to incoming + recipient domain names. +19960724 cleanup: moved relayclient out of qmail-smtpd's addrallowed() + into caller. +19960724 change: added rcpthosts wildcards. +19960724 change: added clean target to Makefile. +19960723 change: added virtualdomains exceptions. +19960722 change: added BLURB4. +19960722 change: added BLURB3. +19960722 change: eliminated smarthost and localnet. +19960722 change: incorporated relaymap, contributed by LW. renamed it + as smtproutes. +19960722 change: qmail-popup now supports APOP. suggested by BG, who + distributed similar changes. +19960722 change: qmail-popup now sends APOP timestamp to checkpassword. +19960722 cleanup: in qmail-popup, split off doanddie(). +19960722 change: qmail-popup now prints APOP timestamp in banner. +19960722 change: added hostname argument to qmail-popup. +19960722 cleanup: in qmail-popup, split out() into out(), outflush(). +19960722 cleanup: in qmail-popup, introduced pop3_greet(). +19960721 portability problem: under Unisys SVR4, hostname is not in the + usual path. impact: qmail-makectl fails. fix: added hostname + command here, used it in qmail-makectl. +19960721 portability problem: on some sysctl-based systems, apparently + gethostname() doesn't write anything if the output buffer is + too small. it should write a truncated name. impact: if anyone + has a hostname longer than 64 characters, maildirs could get up + to 64 characters of garbage, rather than a truncated hostname. + fix: qmail-alias now does *host = 0 before calling gethostname. +19960721 change: updated FAQ examples from qsmhook to preline. +19960721 change: added preline. +19960721 change: qsmhook now uses signal_init, signal_uninit. +19960721 change: qsmhook now checks specifically for empty args. +19960721 change: documented mbox. +19960721 change: added EXT, EXT2, EXT3, EXT4. +19960721 change: added LAST response to qmail-pop3d, always returning + OK 0. tnx RN. +19960721 change: added qmail home page to README. +19960721 change: added HELP response to qmail-smtpd. tnx RN. +19960720 change: expanded, vertically, the qmail-inject error message + for unparseable header fields. +19960720 change: logo is now dolphin. tnx CEJ. +19960719 qmail 0.76, beta. +19960719 change: used LSPAWN_BREAK in qmail-alias for deciding how to + handle extensions. this should produce better behavior in the + (unsupported) case that LSPAWN_BREAK is not a hyphen. +19960719 bug: qmail-smtpd didn't check for null arg on MAIL, RCPT. + impact: qmail-smtpd would deref 0 and crash. fix: qmail-smtpd + now gives syntax error on null arg. +19960719 change: documented UFLINE in qmail-command.8. tnx TG. +19960718 change: added maildir2smtp. +19960718 cleanup: introduced maildir.c. used it in maildir2mbox.c, + maildirwatch.c. +19960718 change: added maildirwatch. +19960718 cleanup: maildir2mbox now sets up pq2 as it is deleting from + pq, rather than simultaneously with pq. +19960718 change: added H_DELIVEREDTO. +19960718 portability problem: Unisys requires -lsocket -lnsl. impact: + couldn't compile under Unisys. fix: added unix_sv section to + make-cmds.sh. tnx TVP. +19960718 change: added unix_sv section in find-systype. tnx TVP. +19960717 change: qmail-alias now appends newline if .qmail does not end + with a newline. tnx MC. +19960717 change: qmail-alias now defers delivery for a blank line only + if it is the first line of the file. handles user behavior + described by MC of putting many newlines at end of file. +19960717 bug: qmail-inject looked for dots in user part, not just host + part, when deciding whether to use defaultdomain. impact: the + address joe.bloggs@here didn't have defaultdomain added. fix: + qmail-inject now stops at the @. +19960717 change: updated INSTALL.alias to mention qmsmac. +19960717 change: syntax error code for SMTP is now 501. +19960717 change: added -e option to sendmail. tnx TG. +19960716 change: changed ~alias files to .qmail-local, not .qmaillocal. + suggested by many people. +19960716 change: redid qmail-alias/qmail-lspawn interface. +19960716 change: replaced EXTENSION, USEREXT with LOCAL. +19960716 change: qmail-queue now removes intd, mess upon error, as long + as it doesn't time out. suggested by BB et al. +19960716 change: added flagmademess, flagmadeintd to qmail-queue.c. +19960716 cleanup: changed todofd to intdfd in qmail-queue.c. +19960716 cleanup: added cleanup() to qmail-queue.c. +19960716 change: added timeout to tcp-env.c, default 30 seconds. +19960716 change: remoteinfo_get() now uses timeoutconn(). +19960715 change: added procmail config.h note to FAQ. +19960704 change: qmail-upgrade.7 now warns administrators that ~alias + generally doesn't apply to addresses starting with a user name. +19960703 change: added echo \c note to FAQ. tnx PJG. +19960702 change: qmail-smtpd now accepts HELO without an argument. + tnx K1J, J1B. +19960627 change: qmail-lspawn.8 now mentions that qmail-lspawn doesn't + set up supplementary groups. tnx TG. +19960625 portability problem: under Linux, read(,,0) doesn't do proper + error slippage. impact: timeoutconn() would always report + success; if a connection failed, qmail-remote would report a + greeting failure and skip all further MX records. tnx ME. fix: + timeoutconn() now uses getpeername() to check for success. +19960625 change: qmail-smtpd now mentions disk full for QQT_WRITE. +19960625 change: qmail-inject now mentions disk full for QQT_WRITE. +19960622 change: if RELAYCLIENT is set, qmail-smtpd skips rcpthosts. +19960609 change: updated INSTALL for current SMTP responses. +19960607 change: clarified INSTALL.qsmhook examples. tnx S1R. +19960607 change: added subject parsing to qlist.c. tnx RN. +19960607 cleanup: used case_diffb in qlist.c. +19960607 change: added extra log information to INSTALL examples. +19960606 change: added -Pn to uucp line in FAQ. tnx DWS. +19960605 portability problem: under Solaris, /usr/bin/groups incorrectly + reports your groups in /etc/group, rather than the results of + getgroups(). tnx MD, PJG. impact: test #19 in INSTALL fails. + fix: added special note to test #19 (sigh) about Solaris. +19960605 change: improved maildir setup commands in INSTALL.mbox. +19960605 change: on success, qmail-alias logs forwarding qp. 9 lines + extra code. +19960605 change: qmail-send logs qp for bounce. 6 lines extra code. +19960605 change: qmail-smtpd includes qp in its response when it accepts + a message. 7 lines extra code. requested by MD and others. +19960605 change: added qqtalk_qp. +19960605 change: qmail-send now logs uid and qp from todo file. 14 lines + extra code. +19960605 change: qmail-queue now records uid and qp in u and p lines + in todo file. 7 lines extra code. +19960605 change: improved qmail-alias x-bit error messages. +19960605 change: newline in log is now converted to /, not underscore. +19960604 change: when it accepts a message, qmail-smtpd includes the + local time in its 250 response. +19960604 change: on success, qmail-alias prints delivery counts, + file+forward+program. +19960603 change: qmail-remote now reports IP address on success. tnx MD. +19960603 change: qmail-send now logs success and failure reports, not + just deferral reports. +19960603 change: added netbsd section in find-systype, same as bsd.os + section. this will affect netbsd-* systypes. tnx MBS. +19960530 qmail 0.75, beta. +19960528 change: added qmail.7. tnx MD. +19960525 change: added qmail-pop3d. tnx RN. +19960525 change: added qmail-popup. tnx RN. +19960525 change: added elm filter section to FAQ. tnx GB. +19960502 portability problem: on many systems, select() on an + almost-full pipe incorrectly says writable. tnx ME for running + into this and helping track it down. impact: if qmail-send + writes a pipeful to qmail-lspawn or qmail-rspawn before they + can react (because of high concurrency, high load, or long + addresses), it will receive an incorrect -1/EAGAIN, and will + conclude that spawn died. sysadmin will have to restart qmail, + and messages will be duplicated. fix: in qmail-send.c, + busy-loop if write() to spawn returns any error other than + EPIPE. +19960501 bug: qmail-alias treated NAMETOOLONG and NOTDIR as temporary + errors. impact: qmail-alias never looked for -default; even if + mail was destined to bounce, it would have to time out first. + fix: qmail-alias now uses error_temp(). +19960430 bug: qmail-smtpd treated qq crash as permanent error. impact: + if somebody actively kills qq, mail will be incorrectly + bounced. tnx SS. fix: qmail-smtpd now treats only TOOLONG and + EXECHARD as permanent errors. +19960430 cleanup: eliminated QQT_TTY from qqtalk.h. +19960428 change: added ``warning: '' before trouble-marking message. +19960428 change: added percenthack. requested by GB. +19960428 cleanup: switched to auto-generated Makefile. +19960428 cleanup: switched to auto-generated .o dependencies. +19960428 cleanup: eliminated fmt.o, scan.o from Makefile. +19960428 portability problem: under HP-UX 10, the rc pgrp is sent HUP + when rc finishes. tnx BG. impact: the qmail daemons are killed + when rc finishes. fix: added special note in INSTALL (sigh) to + use csh -cf. +19960427 cleanup: added PORT_SMTP in qmail-remote.c. +19960427 cleanup: introduced timeoutwrite.c. used it in qmail-remote.c. +19960427 cleanup: introduced timeoutread.c. used it in qmail-remote.c. +19960427 cleanup: introduced timeoutconn.c. used it in qmail-remote.c. +19960427 change: added timeoutconnect. default: 60 seconds. +19960427 change: added pop3d instructions to FAQ. tnx RN. +19960427 change: eliminated env manipulation from qmail-start. tnx BG. +19960427 change: headerbody now ends header, inserting blank line, if + first line of a header field doesn't pass hfield_valid. tnx TG. +19960427 change: headerbody now prepends MBOX-Line: to any header line + starting From_. this lets qmail-inject work with elm's bounce. + tnx OR, K1J, et al. +19960426 change: added moreinfo arg to qlist and qlist2. +19960426 change: added signal_uncatchchild() to qmail-send.c. tnx BG. + now, if sysadmin sets SIGCHLD to SIG_IGN before invoking + qmail-send [sigh], qmail-send won't screw up bounce messages. +19960426 change: dns_cname now checks whether last character is ], + rather than whether first character is [, for quick return. +19960426 cleanup: glue is now global in dns.c. +19960426 cleanup: qmail-remote no longer does stralloc_0 for host and + canonhost. +19960426 change: dns_mxip no longer rejects [foo].bar. +19960426 change: dns_mxip no longer requires for bracket that input + be 0-terminated. +19960426 change: qmail-start can now take logger as an argument. +19960426 change: qmail-start now invokes qmail-send in foreground (as + parent of other processes). +19960426 change: added mailsubj. tnx GAW. +19960426 portability problem: under some systems, can't lock read-only + file. impact: maildir2mbox would always fail on those systems. + fix: maildir2mbox now opens a separate lock fd. tnx BG. +19960426 cleanup: removed unnecessary #!/bin/sh and # AUTO from mctl.sh. +19960426 change: added qmail-qstat. +19960426 change: added qmail-qread.8. +19960426 change: renamed qmail-mailq as qmail-qread. +19960419 change: qmail-alias now defers delivery rather than skipping + blank lines in .qmail. +19960419 change: in qmail-lspawn.c, lowercased name before getpwnam(). + really getpwnam() should do this, but oh well. +19960419 change: added username to qmail-lspawn.c, with LSPAWN_USERLEN + in conf-unusual.h. names longer than LSPAWN_USERLEN will skip + getpwnam(). +19960419 change: if qlist doesn't see any cmds, it presumes that you + meant to subscribe. +19960419 change: reorganized qlist acknowledgment format. +19960415 change: reorganized and rewrote FAQ. +19960415 change: renamed HOWTO as FAQ. +19960414 change: in qmail-alias, converted extension to lowercase just + before qmeopen(), qmeox() calls. thus EXTENSION and USEREXT and + RECIPIENT will preserve case passed by qmail-lspawn, while + .qmailext lookups will not. +19960414 change: removed case_lowers(r) from qmail-lspawn.c. tnx JLH. +19960414 change: moved extension . -> : conversion to just before + qmeopen(), qmeox() calls in qmail-alias.c. thus EXTENSION and + USEREXT and RECIPIENT will preserve dots. +19960414 change: qsmhook -x now does case-independent comparison. +19960413 change: added procmail instructions to HOWTO. +19960409 bug: qmail-alias does not check for newlines when it generates + Return-Path. impact: resulting Return-Path header field will be + illegal, if sender address contains newline followed by + something other than whitespace. fix: qmail-alias now replaces + newline with underscore in rpline. +19960409 change: added leaf UUCP description to HOWTO. tnx J2K. +19960409 change: added -B option to sendmail. tnx OR. +19960409 change: qlist now makes lists unwritable (after renaming from + .qtemp to .qmail). tnx MLH. +19960409 change: added flagdtline to qsmhook.c, based on -l option. +19960409 change: added PIPELINING declaration to qmail-smtpd. tnx JGM. +19960409 change: qmail-smtpd now flushes output instantly after DATA, + QUIT, HELO, EHLO, NOOP, VRFY, or any 502. +19960409 change: qmail-smtpd now flushes output upon read() and death. +19960409 change: qmail-smtpd no longer flushes output in out(). +19960409 change: increased qmail-smtpd outbuf size from 128 to 512. +19960409 cleanup: in qmail-smtpd, eliminated ssinit() in favor of FDBUF. +19960409 bug: qmail-alias produced aliasfoo-owner rather than foo-owner + as envelope sender for ~alias/.qmailfoo. tnx DS. impact: wrong + envelope sender whenever ~alias/.qmailfoo-owner existed. fix: + qmail-alias now checks for hyphen at beginning of extension. +19960409 change: added _ESMTP to end of 220. tnx JLH. +19960409 change: moved out("\r\n") out of smtp_greet() into callers. + this improves the flushing behavior on 221. +19960328 qmail 0.74, beta. +19960326 change: changed subdirectory split from 32 to 23. +19960326 portability problem: some versions of make don't understand + that a line with just a tab is blank. impact: couldn't compile + under those systems. fix: eliminated extra tab from Makefile. + tnx TG. +19960325 change: added qmail-mailq. +19960325 change: introduced readsubdir. +19960325 change: qmail-setup makes split; qmail-check checks split. +19960325 change: used split in qmail-send, qmail-clean, qmail-queue + for mess, info, local, remote. +19960325 change: fmtqfn now supports split queue subdirectories. +19960325 cleanup: eliminated cat2s(). +19960325 cleanup: introduced fmtqfn.c. used it in qmail-queue.c, + qmail-send.c, qmail-clean.c. +19960325 change: in protocol between qmail-clean and qmail-send, now + using intd/ instead of mess/. +19960325 change: qmail-queue.c and triggerpull.c now work inside queue + subdirectory. +19960325 change: spawn.c now checks whether message is a regular file. +19960325 change: spawn.c now allows slashes in messid except at + beginning. +19960325 cleanup: introduced fnmake_split in qmail-send.c. +19960325 cleanup: eliminated strnum in qmail-send.c in favor of + fnmake_{info,todo,mess,chanaddr} and fnmake2_bounce. +19960325 cleanup: introduced strnum3 in qmail-send.c for the logging + uses of strnum. +19960325 cleanup: in qmail-send.c, getinfo() now takes id argument. +19960325 cleanup: qmail-send.c now preallocates space for fn, fn2. +19960325 change: time zone is now -0000 instead of +0000. encouraging + DRUMS to use this as an i-don't-know-the-local-time indicator. +19960324 change: qmail-rspawn.c now calls tcpto_clean(). +19960324 cleanup: spawn.c now calls initialize(). +19960324 change: qmail-setup makes lock/tcpto; qmail-check checks it. +19960324 change: qmail-remote now quickly skips connect() to a host that + seems to be down. tnx BP for pressuring me to get this done. +19960323 change: in qmail-alias.8, renamed mboxg as mboxrd. tnx RD. + idea was popularized by RD in June 1995. +19960322 cleanup: eliminated subfd_init(). +19960322 change: qbiff now removes the word Subject. +19960322 change: now /bin/true instead of /dev/null in the generic + INSTALL.ids instructions. tnx JPR. +19960322 change: added hfield_skipname(). tnx RN. +19960322 bug: qmail-inject did not check whether USER needed quoting. + impact: if USER had weird characters, the From address would + generally be wrong, unless the user manually set up MAILUSER + with proper quoting. fix: qmail-inject sets up a quoted-string + if necessary. +19960322 cleanup: separated out quote_need() in quote.c. +19960322 cleanup: added stralloc_catb.c. used it in qmail-alias.c, + qmail-send.c. +19960322 change: qmail-send now uses a quadratic retry schedule from + birth of each message. this also eliminates clustering. +19960322 cleanup: separated out nextretry() in qmail-send.c. +19960322 change: qmail-remote now passes all non-@ addresses through + without comment, not just <> and <#>. +19960322 change: replaced # test with anything@[] test in qmail-inject. +19960322 change: replaced # with #@[] in qlist.c, qmail-alias.c, + qmail-send.c, qreceipt.c. +19960322 change: qmail-lspawn no longer discards messages to <#>. +19960322 cleanup: in qlist, used str_diff for <> and <#> tests. +19960322 change: qmail-alias is now back to testing envelope sender for + <> and <#>, rather than things without an @. +19960321 change: added 8BITMIME support to qmail-smtpd. +19960321 change: added ESMTP support to qmail-smtpd. +19960318 change: used NEWSENDER in place of SENDER for |forward. +19960318 change: added NEWSENDER. +19960318 change: added HCMSSC support to qmail-alias.c. +19960318 change: added HCMSSC support to spawn.c. +19960318 change: added HCMSSC support to qmail-remote.c. +19960318 change: added HCMSSC support to qmail-smtpd.c. +19960317 portability problem: SCO requires -lsocket -lnsl. impact: + couldn't compile under SCO. fix: added SCO section in + make-cmds.sh. tnx JPR. note that this is for OSR 5; 3.2v4.2 + will need more fixes, and old 3.2 is basically hopeless. +19960317 bug: newfield_datemake would leave newfield_date alone if it + was already initialized, even though qmail-send calls + newfield_datemake anew for each bounce. impact: bounce messages + would usually have an incorrect Date field. fix: redid + newfield_datemake to update newfield_date each time. +19960317 change: allowed . and @ in 822 phrases; 822 doesn't allow them, + but they do show up. tnx to the DRUMS group. +19960317 change: replaced GMT with +0000 in date822fmt.c. this confuses + a few versions of getdate(), but the DRUMS group is going to + outlaw GMT, not just recommend against it as in 1123. +19960317 change: redefined ALIAS_EMPTY to take advantage of . for file + deliveries. tnx RN. +19960317 change: qmail-alias now allows . as well as / to start file + deliveries. tnx RN. +19960317 change: qmail-alias now dies (soft) if .qmail is writable to + others, rather than silently ignoring it. +19960317 change: qmail-alias now dies (soft) if flagforwardonly is + violated, rather than silently ignoring the bad instructions. +19960317 change: qmail-alias now ignores x bit on empty .qmail files. +19960317 bug: if RCPT gave 4xx and DATA gave 5xx, qmail-rspawn would + incorrectly assign a permanent failure to that recipient. + impact: in that case, mail would be incorrectly bounced. fix: + remove orr > 0 test from qmail-rspawn.c. +19960310 change: tcp-env now uses signal_uninit(). [sigh] +19960310 change: tcp-env now specifically unsets HOST and INFO if they + are not applicable. just trying to make it more widely usable. +19960310 cleanup: used byte_* in remoteinfo.c, ipme.c, tcp-env.c. +19960310 cleanup: added readwrite.h, eliminated sys.h. +19960310 cleanup: included byte.h in qmail-send.c. +19960310 cleanup: eliminated i and j from forward.c's main(). +19960310 cleanup: eliminated wstat from qlist.c. +19960310 cleanup: eliminated die_nomem() parameter in qmail-setup.c. +19960310 cleanup: eliminated i from qmail-remote's addrmangle(). +19960310 cleanup: added exit.h. +19960310 cleanup: split ipalloc.c off of ip.c. +19960310 cleanup: added fmt_strn.c, eliminated fmt_strncpy.c. +19960310 change: reorganized INSTALL to do some pre-upgrade tests. + tnx RN. +19960310 change: reordered steps in upgrade procedure in INSTALL. +19960308 change: eliminated ownership test in qmail-alias.c. tnx DS. +19960304 change: in SECURITY, ``six most recent sendmail security + holes'' -> ``seven most recent sendmail security holes.'' +19960303 qmail 0.73, beta. +19960303 change: added SYSDEPS. +19960303 cleanup: revamped select.h autoconfiguration. +19960303 cleanup: revamped fork.h autoconfiguration. +19960303 cleanup: revamped direntry.h autoconfiguration. target is now + direntry.h; auto-hasdrent.h is gone. +19960303 change: tryflock.c now includes <sys/types.h>, for consistency + with lock.c. may affect portability. +19960302 portability problem: under BSDI, can't set sticky on normal + files. dorks. impact: the new qlist doesn't work under BSDI; + be glad I test things before release. fix: qmail-alias and + qlist now use executable instead of sticky. +19960302 change: gfrom now quotes >From and >>From etc. as well as From; + in other words, I'm switching from mbox format to mboxg format. +19960302 cleanup: added gfrom.c. used it in qmail-alias.c, maildir2mbox.c. +19960302 change: addbounce() now substitutes \n\n -> \n/ in reports, + and \n -> _ in recips. thus bounces can now be reliably parsed. +19960302 change: if qmail-send had trouble reading the original message + or the list of addresses for a bounce, it used to give up and + send a bounce with "Oh no! I had trouble reading the rest of + your message" or some such. now it aborts the bounce attempt + and tries again later. +19960302 cleanup: added qqtalk_fail(). used it in qmail-alias.c, + qmail-smtpd.c. +19960302 bug: if mailforward() had trouble reading message (e.g., + because of an I/O error), it marked an error but kept reading. + impact: could loop forever. fix: upon error, break. +19960302 change: maildir2mbox now scans (restrictively) for return-path. +19960302 change: qbiff now prints subject and body, up to 74 chars. +19960302 change: added H_SUBJECT to hfield. +19960302 change: qbiff now puts TO before FROM. +19960301 cleanup: added fmt_str.c. used it in many places. +19960301 change: qmail-send now says something if you've told it to exit + but it's waiting for some deliveries. tnx RN. +19960301 change: qmail-alias -n now continues (with warning) if home + directory is sticky. tnx RN. +19960301 change: improved usage messages in qmail-alias.c. tnx RN. +19960301 change: put limit on length of addresses in qlist. +19960301 change: added exit 99 support to qmail-alias. tnx RN. +19960301 change: qmail-alias now exits immediately on temporary or + permanent error. rewrote section in qmail-alias.8 accordingly. +19960301 cleanup: eliminated flagsuccesses from qmail-alias.c. +19960301 change: added usermap. +19960301 bug: failure to append to mbox was a permanent error. impact: + if mbox was temporarily unopenable (e.g., because fds were + low), mail would be incorrectly bounced. fix: failure is now + temporary. tnx DS. +19960229 change: qmail-alias now preserves any envelope sender that + doesn't contain an @, not just <> and <#>. +19960229 cleanup: revamped byte_* interface. +19960229 cleanup: renamed str_cpy as str_copy. +19960229 cleanup: added str_chr.c. used it in qbiff.c, qmail-smtpd.c. +19960229 cleanup: added str_rchr.c. used it in qmail-send.c, quote.c, + qmail-remote.c. +19960229 cleanup: added byte_rchr.c. used it in qmail-smtpd.c, spawn.c. +19960229 cleanup: used USEREXT instead of RECIPIENT in qsmhook.c. +19960229 cleanup: used USEREXT instead of RECIPIENT in qbiff.c. +19960229 cleanup: removed j and k from rewrite() in qmail-send.c. +19960229 portability problem: under HP-UX 10 and Solaris 2.5, can't + setgroups()/setgid() to the system's nogroup/nobody gid. dorks. + impact: inetd chokes, so all SMTP connections are rejected; and + ``alias'' mail, including postmaster, bounces. fix: in + INSTALL.ids, set up a separate powerless gid (tentatively + ``nofiles'') for qmaild and alias. tnx DS and PJG. +19960229 change: qreceipt now uses qqtalk rather than qmail-inject. +19960229 change: qlist now uses qqtalk rather than qmail-inject. +19960229 change: incorporated qmail-setup patch from RN for better + error messages. +19960228 change: added LSPAWN_BREAK in conf-unusual.h; used it in + lspawn.c. configurability requested by PJG. +19960228 portability problem: on several systems, including everything + from DEC, select() on a pipe reader returns 1 if there aren't + any writers yet. pointed out by DS. impact: qmail-send chewed + up lots of CPU time. fix: trigger_set() now opens the pipe for + writing after opening it for reading. also added trynpbg1; on + working systems, no point in wasting the extra fd. +19960228 change: qmail-alias uses .qmail sticky bit for forwardonly. +19960228 change: qlist now sets sticky bit on .qmail file. +19960228 change: un-documented +list. +19960228 portability problem: on HP-UX and possibly other systems, the + supplementary group list does not include the gid. pointed out + by DS. impact: on those systems, tryshsgr could incorrectly set + hasshsgr; this would prevent qmail-send from running. fix: if + tryshsgr sees that getgroups() returns 0, now it actively sets + up a supplementary group list. added chkshsgr to make sure the + setgroups() will work. +19960227 cleanup: eliminated GETSHORT in dns.c in favor of getshort(). +19960227 cleanup: deleted h->len < 3 test from qlist.c:dobody. tnx RN. +19960227 change: replaced ~ with $HOME in INSTALL.mbox. +19960227 change: added note about setgid-mail bits to INSTALL.mbox. +19960227 change: added forward.1. +19960227 change: modified forward to allow multiple addresses. +19960227 change: modified forward to take an entire address, not just a + hostname. +19960227 change: renamed qrelay as forward. +19960227 change: added USEREXT support to qmail-alias. +19960227 change: added -F to sendmail. the need for this was pointed + out by RN. +19960227 change: added 2 bytes of slop in alloc(). +19960227 bug: received_setup() was not allowing space for the final \0. + impact: none; the line length is always between 65 and 75 + characters, which gives at least 45 characters of slop with + existing malloc() implementations. fix: leave space. tnx NH. + note that the bug here is really in fmt_strncpy, which was + written before i was truly free of the curse of libc.a. +19960227 change: added ALIAS_EMPTY in conf-unusual.h; used it in + qmail-alias.c. tnx PJG. +19960227 change: added SPAWN_NUMD in conf-unusual.h; used it in spawn.c. +19960227 change: added conf-unusual.h. +19960227 cleanup: replaced sizeof(short) with 2 in dns.c. +19960227 portability problem: on an Alpha, long is 64 bits. pointed out + by DS. impact: address lookups produced incorrect results on an + Alpha; qmail-makectl and qmail-remote failed. fix: replaced + sizeof(long) with 4 in dns.c. +19960227 portability problem: on an Alpha, bzero() is declared properly + via sys/time.h. impact: couldn't compile on an Alpha. fix: + removed bzero() declaration from select.h. tnx DS. +19960227 portability problem: under SCO, sys/file.h is not protected. + impact: couldn't compile under SCO. fix: include sys/types.h in + lock.c. tnx RN. +19960219 change: added some .qmail-list hints to qlist.1. +19960219 change: added +list support to qmail-alias. +19960215 change: added THANKS. +19960212 bug: foo was not initialized in qrelay.c. impact: depends on + the machine; on some machines, no effect; on other machines, + guaranteed core dump. fix: initialized foo. tnx DS. +19960209 qmail 0.72, beta. +19960209 change: qmail-alias now replaces dot, not slash, with colon. + also, qmeopen() makes sure that .qmail file is S_IFREG; I hope + this doesn't cause portability problems. +19960209 change: added success-reporting procedure to INSTALL. +19960208 change: added VERSION. +19960208 change: added qlist2. +19960208 change: revamped qlist interface. tnx RN. +19960208 change: improved an error message in qlist.c. +19960208 change: added qrelay. added relay section to HOWTO. tnx DS. +19960208 cleanup: included substdio.h in qqtalk.h. +19960207 bug: prioq_delmin() wasn't guaranteeing heap structure on the + last element. impact: scheduled passes could have been delayed, + conceivably as long as half an hour. fix: prioq_delmin() now + checks when it can safely move the last element. +19960207 change: added maildirmake.1, maildir2mbox.1. +19960206 change: revised logo paragraph in THOUGHTS. +19960206 change: replaced nowhere.org with nowhere.mil in examples. + nowhere.org is a real domain... [sigh] +19960206 change: added qreceipt.1. +19960206 portability problem: IRIX doesn't have vfork. pointed out by + DS. impact: couldn't compile under IRIX. fix: added fork.h, + tryvfork.c. +19960206 portability problem: IRIX doesn't have ranlib. pointed out by + DS. impact: couldn't compile under IRIX. fix: added IRIX + section in make-cmds.sh. +19960205 cleanup: removed warning from substdio_copy() documentation; in + fact, substdio_copy() can be used safely on a fed substdio. +19960205 change: added qbiff.1. +19960204 change: implemented localnet. removed relevant paragraph from + THOUGHTS. tnx IS. +19960204 change: in qmail-remote.8, explained the dangers of smarthost. + tnx IS. +19960204 change: implemented virtualdomains wildcards. tnx JLH. +19960203 change: qmail-send now handles virtualdomains _after_ locals. + updated INSTALL.qsmhook appropriately. +19960203 change: added note to INSTALL.alias about ~ftp, ~www, ~uucp + being owned by root. +19960130 cleanup: in qlist.c, renamed flagremoved as flagwasthere. +19960130 bug: qmail-send did not pay attention to flagexitasap in + pass_dochan(). impact: qmail-send would happily start new + deliveries even if it wanted to exit. fix: qmail-send now + returns immediately in pass_selprep() and pass_dochan() if + flagexitasap. +19960130 change: in qlist.c and qlist.1, renamed ext as list. +19960130 change: in qlist.c and qlist.1, renamed manager as owner. +19960129 qmail 0.71, beta. +19960129 change: mentioned djb-qmailbeta in README. tnx MWE. +19960129 change: added a note to INSTALL.mbox making clear that + Mailbox is in mbox format. tnx MWE. +19960129 change: qlist now warns you if it didn't see any cmds. tnx RN. +19960129 change: incorporated qlist patch from RN to refuse double subs. +19960129 change: added qlist.1, contributed by RN. mangled it a bit. +19960129 bug: comment was not allowed in ``phrase (comment) <route>''; + pointed out by RN. impact: some correct address lists could be + mis-parsed by qmail-inject or qlist. fix: token.c now allows + TOKEN_COMMENT in the appropriate scan. +19960128 change: added a logo paragraph to THOUGHTS. +19960127 change: implemented rcpthosts. +19960127 change: split up some uses of putflush in qmail-remote, + qmail-smtpd, spawn.c. eliminated NODELAY and corresponding + paragraph in THOUGHTS. +19960127 change: added quote2(). used it in qmail-alias, qmail-send, + qreceipt. now addresses are properly quoted in the From, To, + and internal Return-Path of bounces; the From and To of + receipts; and the Return-Path/RPLINE of delivered messages. + removed relevant paragraph from THOUGHTS. +19960127 change: in RFCLOOPS, documented fact that Delivered-To address + is conventionally not quoted. +19960127 change: knocked default SMTP timeouts down to 20 minutes. +19960127 change: added INSTALL.ids. tnx RN. +19960127 change: in INSTALL, noted that nogroup should already exist. +19960127 bug: pass_selprep checked pqchan[c] even if pass[c].id. impact: + qmail-send wasted CPU time whenever more than one message was + waiting on a blocked channel. fix: pass_selprep now checks + !pass[c].id. +19960127 bug: programs invoked from qmail-alias were immune to SIGPIPE. + impact: a delivery pipeline such as |yes|head -1000 would loop + forever, since yes does not check for write errors. fix: added + signal_uninit(). used it before execvp in qmail-alias. [sigh] +19960127 cleanup: added date822fmt.c. used it in newfield.c, qmail-queue. +19960127 cleanup: added fmt_uint0.c. used it in myctime.c, newfield.c, + qmail-queue. +19960127 cleanup: added dnsdoe.c. used it in dnscname, dnsfq, dnsip, + dnsmxip, dnsptr. +19960127 cleanup: eliminated temp from dnsfq.c. +19960127 bug: gen_allocdefs was making assumptions incompatible with the + alloc_re interface. impact: qmail-send would dump core if you + ran out of memory. fix: changed alloc_re interface. +19960126 portability problem: some versions of Linux don't have + net/route.h. pointed out by RN. impact: couldn't compile under + those versions. fix: ipme.c no longer includes net/route.h; + hopefully this won't cause new portability problems. +19960126 change: added chmod instructions to INSTALL and INSTALL.alias. + tnx RN. +19960126 change: INSTALL now refers to the traditional sendmail spot + (/usr/lib), not the BSD 4.4 spot (/usr/sbin). tnx RN. +19960126 change: make auto-uids.h now creates auto-uids.h.tmp first. + thus, if someone disobeys the installation instructions, and + his make fails to remove targets upon error, he'll still be + okay. tnx RN. +19960126 change: added forgeries.7. +19960125 cleanup: eliminated flagverbose, flagmetoo in sendmail. +19960125 cleanup: added substdio_copy.c. used it at several spots. +19960125 cleanup: added constmap.c. qmail-send now uses constmap for + locals and virtualdomains. this will speed things up: no + problem now to have thousands of virtual domains. removed + relevant paragraph from THOUGHTS. +19960125 change: added linux section in find-systype. this will affect + linux-* systypes. tnx RN for relevant info. +19960124 change: added -od, -oe, -p, -f to sendmail. the need for + these was pointed out by TN. +19960124 bug: qmail-smtpd was reading from descriptor 1. impact: none; + in normal use, both 0 and 1 point to the network. fix: changed + 1 to 0. +19960124 bug: qmail-alias treated any .qmail open failure as permanent. + impact: if a .qmail file was temporarily unopenable (e.g., + because of NFS), it was incorrectly ignored. fix: qmail-alias + now dies QLX_SOFT on any open failure other than ENOENT. +19960124 change: added freebsd section in find-systype, same as bsd.os + section. this will affect freebsd-* systypes. +19960124 cleanup: find-systype now immediately converts sys to lowercase. +19960124 change: qmail-setup now copies man pages into /var/qmail/man; + qmail-check checks /var/qmail/man. using .0 style, which might + cause trouble on various machines, but better than not trying. +19960124 change: in qmail-remote.c, changed perm_control to temp_control + (and D to Z, thanks); thus failure to read control files (e.g., + because of permissions) is now a temporary error. +19960124 bug: in qmail-remote.c, temp_chdir() used D, not Z. impact: if + chdir() to CONF_HOME failed (e.g., because of NFS), message + would be bounced. fix: changed D to Z. +19960124 change: reorganized README. +19960124 portability problem: Linux has the fifo kernel bug that I had + hoped I'd never run into. impact: messages under Linux (and any + other systems with this bug) were picked up only in sweeps, not + instantly. fix: triggerpull.c now writes a byte (non-blocking) + to the fifo. updated INTERNALS accordingly. +19960124 bug: in qmail-remote.c, if quit() saw a remote write error, it + would call writeerr() even though a message report had already + been produced. impact: the mess report would include an extra + ``ZConnected but communications failed,'' which was confusing + to humans. fix: quit() now simply skips the wait-for-QUIT + smtpcode() upon write error. +19960124 portability problem: Linux does not have SIGSYS or SIGEMT. + impact: couldn't compile under Linux. fix: added appropriate + ifdefs in signal.c. +19960124 qmail 0.70, beta. diff --git a/FAQ b/FAQ @@ -0,0 +1,574 @@ +1. Controlling the appearance of outgoing messages +1.1. How do I set up host masquerading? +1.2. How do I set up user masquerading? + +2. Routing outgoing messages +2.1. How do I send local messages to another host? +2.2. How do I set up a null client? +2.3. How do I send outgoing mail through UUCP? +2.4. How do I set up a separate queue for a SLIP/PPP link? +2.5. How do I deal with ``CNAME lookup failed temporarily''? + +3. Routing incoming messages by host +3.1. How do I receive mail for another host name? +3.2. How do I set up a virtual domain? +3.3. How do I set up several virtual domains for one user? + +4. Routing incoming messages by user +4.1. How do I forward unrecognized usernames to another host? +4.2. How do I set up a mailing list? +4.3. How do I use majordomo with qmail? +4.4. How do I use procmail with qmail? +4.5. How do I use elm's filter with qmail? +4.6. How do I create aliases with dots? + +5. Setting up servers +5.1. How do I run qmail-smtpd under tcpserver? +5.2. How do I set up qmail-qmtpd? +5.3. How do I set up qmail-pop3d? +5.4. How do I allow selected clients to use this host as a relay? +5.5. How do I fix up messages from broken SMTP clients? + +6. Configuring MUAs to work with qmail +6.1. How do I make BSD mail generate a Date with the local time zone? +6.2. How do I stop pine from crashing? +6.3. How do I make MH work with qmail? +6.4. How do I stop Sun's dtcm from hanging? + +7. Managing the mail system +7.1. How do I safely stop qmail-send? +7.2. How do I manually run the queue? +7.3. How do I rejuvenate a message? +7.4. How do I organize a big network? +7.5. How do I back up and restore the queue disk? + +8. Miscellany +8.1. How do I tell qmail to do more deliveries at once? +8.2. How do I keep a copy of all incoming and outgoing mail messages? +8.3. How do I switch slowly from sendmail to qmail? + + + +1. Controlling the appearance of outgoing messages + + +1.1. How do I set up host masquerading? All the users on this host, +zippy.af.mil, are users on af.mil. When joe sends a message to fred, the +message should say ``From: joe@af.mil'' and ``To: fred@af.mil'', without +``zippy'' anywhere. + +Answer: echo af.mil > /var/qmail/control/defaulthost; chmod 644 +/var/qmail/control/defaulthost. + + +1.2. How do I set up user masquerading? I'd like my own From lines to +show boss@af.mil rather than god@heaven.af.mil. + +Answer: Add MAILHOST=af.mil and MAILUSER=boss to your environment. To +override From lines supplied by your MUA, add QMAILINJECT=f to your +environment. + + + +2. Routing outgoing messages + + +2.1. How do I send local messages to another host? All the mail for +af.mil should be delivered to our disk server, pokey.af.mil. I've set up +an MX from af.mil to pokey.af.mil, but when a user on the af.mil host +sends a message to boss@af.mil, af.mil tries to deliver it locally. How +do I stop that? + +Answer: Remove af.mil from /var/qmail/control/locals. If qmail-send is +running, give it a HUP. Make sure the MX is set up properly before you +do this. Also make sure that pokey can receive mail for af.mil---see +question 3.1. + + +2.2. How do I set up a null client? I'd like zippy.af.mil to +send all mail to bigbang.af.mil. + +Answer: echo :bigbang.af.mil > /var/qmail/control/smtproutes; +chmod 644 /var/qmail/control/smtproutes. Disable local delivery as in +question 2.1. Turn off qmail-smtpd in /etc/inetd.conf. + + +2.3. How do I send outgoing mail through UUCP? I need qmail to send all +outgoing mail via UUCP to my upstream UUCP site, gonzo. + +Answer: Put + + :alias-uucp + +into control/virtualdomains and + + |preline -df /usr/bin/uux - -r -gC -a"$SENDER" gonzo!rmail "($EXT2@$HOST)" + +into ~alias/.qmail-uucp-default. (For some UUCP software you will need +to use -d instead of -df. Also, you may need to insert a space between +-a and "$SENDER" for bounces to work properly.) If qmail-send is +running, give it a HUP. + + +2.4. How do I set up a separate queue for a SLIP/PPP link? + +Answer: Use serialmail (http://pobox.com/~djb/serialmail.html). + + +2.5. How do I deal with ``CNAME lookup failed temporarily''? The log +showed that a message was deferred for this reason. Why is qmail doing +CNAME lookups, anyway? + +Answer: The SMTP standard does not permit aliased hostnames, so qmail +has to do a CNAME lookup in DNS for every sender and recipient host. If +the relevant DNS server is down, qmail defers the message. It will try +again soon. + + + +3. Routing incoming messages by host + + +3.1. How do I receive mail for another host name? I'd like our disk +server, pokey.af.mil, to receive mail addressed to af.mil. I've set up +an MX from af.mil to pokey.af.mil, but how do I get pokey to treat +af.mil as a name for the local host? + +Answer: Add af.mil to /var/qmail/control/locals and to +/var/qmail/control/rcpthosts. If qmail-send is running, give it a HUP. + + +3.2. How do I set up a virtual domain? I'd like any mail for +nowhere.mil, including root@nowhere.mil and postmaster@nowhere.mil and +so on, to be delivered to Bob. I've set up the MX already. + +Answer: Put + + nowhere.mil:bob + +into control/virtualdomains. Add nowhere.mil to control/rcpthosts. If +qmail-send is running, give it a HUP. + +Now mail for whatever@nowhere.mil will be delivered locally to +bob-whatever. Bob can set up ~bob/.qmail-default to catch all the +possible addresses, ~bob/.qmail-info to catch info@nowhere.mil, etc. + + +3.3. How do I set up several virtual domains for one user? Bob wants +another virtual domain, everywhere.org, but he wants to handle +nowhere.mil users and everywhere.org users differently. How can we do +that without setting up a second account? + +Answer: Put two lines into control/virtualdomains: + + nowhere.mil:bob-nowhere + everywhere.org:bob-everywhere + +Add nowhere.mil and everywhere.org to control/rcpthosts. If qmail-send +is running, give it a HUP. + +Now Bob can set up separate .qmail-nowhere-* and everywhere-* files. He +can even set up .qmail-nowhere-default and .qmail-everywhere-default. + + + +4. Routing incoming messages by user + + +4.1. How do I forward unrecognized usernames to another host? I'd like +to set up a LUSER_RELAY pointing at bigbang.af.mil. + +Answer: Put + + | forward "$LOCAL"@bigbang.af.mil + +into ~alias/.qmail-default. + + +4.2. How do I set up a mailing list? I'd like me-sos@my.host.name to be +forwarded to a bunch of people. + +Answer: Put a list of addresses into ~me/.qmail-sos, one per line. Then +incoming mail for me-sos will be forwarded to each of those addresses. +You should also touch ~me/.qmail-sos-owner so that bounces come back to +you rather than the original sender. If you want subscriptions to be +handled automatically, put + + | qlist2 sos my.host.name + +into ~me/.qmail-sos-request. Anyone who wants to subscribe can simply +send a message to me-sos-request@my.host.name. + + +4.3. How do I use majordomo with qmail? + +Answer: You need to patch majordomo so that it creates qmail-style +lists. See ftp://koobera.math.uic.edu/pub/software/majordomo+qmail.gz. +Exception: qmsmac understands sendmail-style :include: files, so you +shouldn't patch majordomo if you're using qmsmac. + + +4.4. How do I use procmail with qmail? + +Answer: Put + + | preline procmail + +into ~/.qmail. You'll have to use a full path for procmail unless +procmail is in the system's startup PATH. Note that procmail will try to +deliver to /usr/spool/mail/$USER by default; to change this, change +SYSTEM_MBOX in procmail's config.h. + + +4.5. How do I use elm's filter with qmail? + +Answer: Put + + | preline filter + +into ~/.qmail. You'll have to use a full path for filter unless filter +is in the system's startup PATH. + + +4.6. How do I create aliases with dots? I tried setting up +~alias/.qmail-P.D.Q.Bach, but it doesn't do anything. + +Answer: Use .qmail-p:d:q:bach. Dots are converted to colons, and +uppercase is converted to lowercase. + + + +5. Setting up servers + + +5.1. How do I run qmail-smtpd under tcpserver? inetd is barfing at high +loads, cutting off service for ten-minute stretches. I'd also like +better connection logging. + +Answer: First, install the tcpserver program, part of the ucspi-tcp +package (http://pobox.com/~djb/ucspi-tcp.html). Second, remove the smtp +line from /etc/inetd.conf, and put the line + + tcpserver -u 7770 -g 2108 0 smtp /var/qmail/bin/qmail-smtpd & + +into your system startup files. Replace 7770 with your qmaild uid, and +replace 2108 with your nofiles gid. Don't forget the &. The change will +take effect at your next reboot. + +By default, tcpserver allows at most 40 simultaneous qmail-smtpd +processes. To raise this limit to 400, use tcpserver -c 400. To keep +track of who's connecting and for how long, run (on two lines) + + tcpserver -v -u 7770 -g 2108 0 smtp /var/qmail/bin/qmail-smtpd \ + 2>&1 | /var/qmail/bin/splogger smtpd 3 & + + +5.2. How do I set up qmail-qmtpd? + +Answer: Two steps. First, put a + + qmtp 209/tcp + +line into /etc/services. Second, put (all on one line) + + qmtp stream tcp nowait qmaild + /var/qmail/bin/tcp-env tcp-env /var/qmail/bin/qmail-qmtpd + +into /etc/inetd.conf, and give inetd a HUP. + +If you have tcpserver installed, skip the inetd step, and set up + + tcpserver -u 7770 -g 2108 0 qmtp /var/qmail/bin/qmail-qmtpd & + +replacing 7770 and 2108 with the qmaild uid and nofiles gid. See +question 5.1 for more details. + + +5.3. How do I set up qmail-pop3d? + +Answer: Four steps. First, install the checkpassword program +(http://pobox.com/~djb/checkpwd.html). Second, make sure you have a + + pop3 110/tcp + +line in /etc/services. Third, put (all on one line) + + pop3 stream tcp nowait root /var/qmail/bin/qmail-popup + qmail-popup YOURHOST /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir + +into /etc/inetd.conf, and give inetd a HUP; replace YOURHOST with your +host's fully qualified domain name. Fourth, set up Maildir delivery for +any user who wants to read mail via POP. + +If you have tcpserver installed, skip the inetd step, and set up (on two +lines) + + tcpserver 0 pop3 /var/qmail/bin/qmail-popup YOURHOST \ + /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir & + +replacing YOURHOST with your host's fully qualified domain name. See +question 5.1 for more details. + +Security note: pop3d should be used only within a secure network; +otherwise an eavesdropper can steal passwords. + + +5.4. How do I allow selected clients to use this host as a relay? I see +that qmail-smtpd rejects messages to any host not listed in +control/rcpthosts. I know I could entirely disable this feature by +removing control/rcpthosts, but I want to be more selective. + +Answer: Three steps. First, install tcp-wrappers, available separately, +including hosts_options. Second, change your qmail-smtpd line in +inetd.conf to + + smtp stream tcp nowait qmaild /usr/local/bin/tcpd + /var/qmail/bin/tcp-env /var/qmail/bin/qmail-smtpd + +(all on one line) and give inetd a HUP. Third, in tcpd's hosts.allow, +make a line setting the environment variable RELAYCLIENT to the empty +string for the selected clients: + + tcp-env: 1.2.3.4, 1.2.3.5: setenv = RELAYCLIENT + +Here 1.2.3.4 and 1.2.3.5 are the clients' IP addresses. qmail-smtpd +ignores control/rcpthosts when RELAYCLIENT is set. (It also appends +RELAYCLIENT to each envelope recipient address. See question 5.5 for an +application.) + +Alternative procedure, if you are using tcpserver: Install tcpcontrol +(http://pobox.com/~djb/tcpcontrol.html). Create /etc/tcp.smtp containing + + 1.2.3.6:allow,RELAYCLIENT="" + 127.:allow,RELAYCLIENT="" + +to allow clients with IP addresses 1.2.3.6 and 127.*. Run + + tcpmakectl /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp + +Finally, insert + + tcpcontrol /etc/tcp.smtp.cdb + +before /var/qmail/bin/qmail-smtpd in your tcpserver line. + + +5.5. How do I fix up messages from broken SMTP clients? + +Answer: Three steps. First, put + + | [ "@$HOST" = "@fixme" ] || ( echo Permission denied; exit 100 ) + | qmail-inject -f "$SENDER" -- "$EXT2" + +into ~alias/.qmail-fixup-default. Second, put + + fixme:fixup + +into /var/qmail/control/virtualdomains, and give qmail-send a HUP. +Third, follow the procedure in question 5.4, but set RELAYCLIENT to the +string ``@fixme'': + + tcp-env: 1.2.3.6, 1.2.3.7: setenv = RELAYCLIENT @fixme + +Here 1.2.3.6 and 1.2.3.7 are the clients' IP addresses. If you are using +tcpserver and tcpcontrol instead of inetd and tcpd, put + + 1.2.3.6:allow,RELAYCLIENT="@fixme" + 1.2.3.7:allow,RELAYCLIENT="@fixme" + +into /etc/tcp.smtp, and run tcpmakectl as in question 5.4. + + + +6. Configuring MUAs to work with qmail + + +6.1. How do I make BSD mail generate a Date with the local time zone? +When I send mail, I'd rather use the local time zone than GMT, since +some MUAs don't know how to display Date in the receiver's time zone. + +Answer: Put + + set sendmail=/var/qmail/bin/datemail + +into your .mailrc or your system-wide Mail.rc. Beware that BSD mail is +neither secure nor reliable. + + +6.2. How do I stop pine from crashing? When I ask any version of pine +past 3.91 to send mail, it crashes. + +Answer: Put + + sendmail-path=/usr/lib/sendmail -oem -oi -t + +into /usr/local/lib/pine.conf. (This will work with sendmail too.) +Beware that pine is neither secure nor reliable. + + +6.3. How do I make MH work with qmail? + +Answer: Put + + postproc: /usr/mh/lib/spost + +into each user's .mh_profile. (This will work with sendmail too.) Beware +that MH is neither secure nor reliable. + + +6.4. How do I stop Sun's dtcm from hanging? + +Answer: There is a novice programming error in dtcm, known as ``failure +to close the output side of the pipe in the child.'' Sun has, at the +time of this writing, not yet provided a patch. Sorry. + + + +7. Managing the mail system + + +7.1. How do I safely stop qmail-send? Back when we were running +sendmail, it was always tricky to kill sendmail without risking the loss +of current deliveries; what should I do with qmail-send? + +Answer: Go ahead and kill the qmail-send process. It will shut down +cleanly. Wait for ``exiting'' to show up in the log. To restart it, run +qmail-start the same way as it's run from your system boot scripts. + + +7.2. How do I manually run the queue? I'd like qmail to try delivering +all the remote messages right now. + +Answer: Give the qmail-send process an ALRM. + + +7.3. How do I rejuvenate a message? Somebody broke into Eric's computer +again; it's going to be down for at least another two days. I know Eric +has been expecting an important message---in fact, I see it sitting here +in /var/qmail/queue/mess/15/26902. It's been in the queue for six days; +how can I make sure it isn't bounced tomorrow? + +Answer: Just touch /var/qmail/queue/info/15/26902. (This is the only +form of queue modification that's safe while qmail is running.) + + +7.4. How do I organize a big network? I have a lot of machines, and I +don't know where to start. + +Answer: First, choose the domain name where your users will receive +mail. This is normally the shortest domain name you control. If you are +in charge of *.movie.edu, you can use addresses like joe@movie.edu. + +Second, choose the machine that will know what to do with different +users at movie.edu. Set up a host name in DNS for this machine: + + mailhost.movie.edu IN A 1.2.3.4 + 4.3.2.1.in-addr.arpa IN PTR mailhost.movie.edu + +Here 1.2.3.4 is the IP address of that machine. + +Third, make a list of machines where mail should end up. For example, if +mail for Bob should end up on Bob's workstation, put Bob's workstation +onto the list. For each of these machines, set up a host name in DNS: + + bobshost.movie.edu IN A 1.2.3.7 + 7.3.2.1.in-addr.arpa IN PTR bobshost.movie.edu + +Fourth, install qmail on bobshost.movie.edu. qmail will automatically +configure itself to accept messages for bob@bobshost.movie.edu and +deliver them to ~bob/Mailbox on bobshost. Do the same for the other +machines where mail should end up. + +Fifth, install qmail on mailhost.movie.edu. Put + + movie.edu:alias-movie + +into control/virtualdomains on mailhost. Then forward bob@movie.edu to +bob@bobshost.movie.edu, by putting + + bob@bobshost.movie.edu + +into ~alias/.qmail-movie-bob. Do the same for other users. + +Sixth, put movie.edu into control/rcpthosts on mailhost.movie.edu, so +that mailhost.movie.edu will accept messages for users at movie.edu. + +Seventh, set up an MX record in DNS to deliver movie.edu messages to +mailhost: + + movie.edu IN MX 10 mailhost.movie.edu + +Eighth, on all your machines, put movie.edu into control/defaulthost. + + +7.5. How do I back up and restore the queue disk? + +Answer: You can't. + +One difficulty is that you can't get a consistent snapshot of the queue +while qmail-send is running. Another difficulty is that messages in the +queue must have filenames that match their inode numbers. + +However, the big problem is that backups---even twice-daily backups--- +are far too unreliable for mail. If your disk dies, there will be very +little overlap between the messages saved in the last backup and the +messages that were lost. + +There are several ways to add real reliability to a mail server. Battery +backups will keep your server alive, letting you park the disk to avoid +a head crash, when the power goes out. Solid-state disks have their own +battery backups. RAID boxes let you replace dead disks without losing +any data. + + + +8. Miscellany + + +8.1. How do I tell qmail to do more deliveries at once? It's running +only 20 parallel qmail-remote processes. + +Answer: Decide how many deliveries you want to allow at once. Put that +number into control/concurrencyremote. Restart qmail-send as in question +7.1. If your system has resource limits, make sure you set the +descriptors limit to at least double the concurrency plus 5; otherwise +you'll get lots of unnecessary deferrals whenever a big burst of mail +shows up. Note that qmail also imposes a compile-time concurrency limit, +120 by default; this is set in conf-spawn. + + +8.2. How do I keep a copy of all incoming and outgoing mail messages? + +Answer: Set QUEUE_EXTRA to "Tlog\0" and QUEUE_EXTRALEN to 5 in extra.h. +Recompile qmail. Put ./msg-log into ~alias/.qmail-log. + +You can also use QUEUE_EXTRA to, e.g., record the Message-ID of every +message: run + + | awk '/^$/ { exit } /^[mM][eE][sS][sS][aA][gG][eE]-/ { print }' + +from ~alias/.qmail-log. + + +8.3. How do I switch slowly from sendmail to qmail? I'm thinking of +moving the heaven.af.mil network over to qmail, but first I'd like to +give my users a chance to try out qmail without affecting current +sendmail deliveries. We're using NFS. + +Answer: Find a host in your network, say pc.heaven.af.mil, that isn't +running an SMTP server. (If addresses at pc.heaven.af.mil are used, you +should already have an MX pointing pc.heaven.af.mil to your mail hub.) + +Set up a new MX record pointing lists.heaven.af.mil to pc.heaven.af.mil. +Install qmail on pc.heaven.af.mil. Replace pc with lists in the control +files. Make the qmail man pages available on all your machines. + +Now tell your users about qmail. A user can forward joe@heaven.af.mil to +joe@lists.heaven.af.mil to get ~/Mailbox delivery; he can set up .qmail +files; he can start running his own mailing lists @lists.heaven.af.mil. + +When you're ready to turn sendmail off, you can set up pc.heaven.af.mil +as your new mail hub. Add heaven.af.mil to control/locals, and change +the heaven.af.mil MX to point to pc.heaven.af.mil. Make sure you leave +lists.heaven.af.mil in control/locals so that transition addresses will +continue to work. diff --git a/FILES b/FILES @@ -0,0 +1,401 @@ +BLURB +BLURB2 +BLURB3 +BLURB4 +README +FAQ +INSTALL +INSTALL.alias +INSTALL.boot +INSTALL.ctl +INSTALL.ids +INSTALL.mbox +INSTALL.qsmhook +UPGRADE +THOUGHTS +TODO +THANKS +CHANGES +RFCHCSC +RFCLOOPS +RFCMXPS +RFCNETSTR +RFCNRUDT +RFCQMTP +RFCQSBMF +RFCVERP +SECURITY +INTERNALS +FILES +VERSION +SYSDEPS +TARGETS +Makefile +conf-break +auto_break.h +conf-spawn +auto_spawn.h +chkspawn.c +conf-split +auto_split.h +conf-patrn +auto_patrn.h +conf-users +conf-groups +auto_uids.h +auto_usera.h +extra.h +addresses.5 +condredirect.1 +dot-qmail.9 +envelopes.5 +forgeries.7 +forward.1 +maildir2mbox.1 +maildirmake.1 +maildirwatch.1 +mailsubj.1 +mbox.5 +preline.1 +qbiff.1 +qlist.1 +qmail-clean.8 +qmail-command.8 +qmail-control.9 +qmail-getpw.9 +qmail-header.5 +qmail-inject.8 +qmail-limits.9 +qmail-local.8 +qmail-log.5 +qmail-lspawn.8 +qmail-newu.9 +qmail-pop3d.8 +qmail-popup.8 +qmail-pw2u.9 +qmail-qmtpd.8 +qmail-qread.8 +qmail-qstat.8 +qmail-queue.8 +qmail-remote.8 +qmail-rspawn.8 +qmail-send.9 +qmail-showctl.8 +qmail-smtpd.8 +qmail-start.9 +qmail-tcpto.8 +qmail-upgrade.9 +qmail-users.9 +qmail.7 +qreceipt.1 +splogger.8 +tcp-env.1 +qmail-clean.c +qmail-config.sh +qmail-getpw.c +qmail-hier.c +qmail-inject.c +qmail-local.c +qmail-lspawn.c +qmail-newu.c +qmail-pop3d.c +qmail-popup.c +qmail-pw2u.c +qmail-qmtpd.c +qmail-qread.c +qmail-qstat.sh +qmail-queue.c +qmail-remote.c +qmail-rspawn.c +qmail-send.c +qmail-showctl.c +qmail-smtpd.c +qmail-start.c +qmail-tcpto.c +spawn.c +dnscname.c +dnsfq.c +dnsip.c +dnsmxip.c +dnsptr.c +hostname.c +ipmeprint.c +tcp-env.c +sendmail.c +qlist.c +qreceipt.c +qsmhook.c +qbiff.c +forward.c +preline.c +predate.c +condredirect.c +maildirmake.c +maildir2mbox.c +maildirwatch.c +splogger.c +qail.sh +elq.sh +pinq.sh +qlist2.sh +qmail-upq.sh +datemail.sh +mailsubj.sh +qlx.h +constmap.h +constmap.c +dnsdoe.h +dnsdoe.c +fmtqfn.h +fmtqfn.c +gfrom.h +gfrom.c +myctime.h +myctime.c +newfield.h +newfield.c +qsutil.h +qsutil.c +readsubdir.h +readsubdir.c +received.h +received.c +tcpto.h +tcpto.c +tcpto_clean.c +trigger.h +trigger.c +triggerpull.h +triggerpull.c +trynpbg1.c +trysyslog.c +conf-cc +conf-ld +find-systype.sh +make-compile.sh +make-load.sh +make-makelib.sh +trycpp.c +warn-auto.sh +auto-str.c +auto-int.c +auto-int8.c +auto-gid.c +auto-uid.c +install.c +instcheck.c +alloc.3 +alloc.h +alloc.c +alloc_re.c +case.3 +case.h +case_diffb.c +case_diffs.c +case_lowerb.c +case_lowers.c +case_starts.c +cdb.3 +cdb.h +cdb_hash.c +cdb_seek.c +cdb_unpack.c +cdbmake.h +cdbmake_add.c +cdbmake_hash.c +cdbmake_pack.c +cdbmss.h +cdbmss.c +coe.3 +coe.h +coe.c +fd.h +fd_copy.3 +fd_copy.c +fd_move.3 +fd_move.c +fifo_make.3 +fifo.h +fifo.c +trymkffo.c +fork.h1 +fork.h2 +tryvfork.c +now.3 +now.h +now.c +open.h +open_append.c +open_excl.c +open_read.c +open_trunc.c +open_write.c +seek.h +seek_cur.c +seek_end.c +seek_set.c +seek_trunc.c +conf-qmail +auto_qmail.h +qmail.h +qmail.c +gen_alloc.h +gen_allocdefs.h +stralloc.3 +stralloc.h +stralloc_eady.c +stralloc_pend.c +stralloc_copy.c +stralloc_opyb.c +stralloc_opys.c +stralloc_cat.c +stralloc_catb.c +stralloc_cats.c +stralloc_arts.c +strerr.h +strerr_sys.c +strerr_die.c +substdio.h +substdio.c +substdi.c +substdo.c +substdio_copy.c +subfd.h +subfderr.c +subfdouts.c +subfdout.c +subfdins.c +subfdin.c +readwrite.h +exit.h +timeoutconn.h +timeoutconn.c +timeoutread.h +timeoutread.c +timeoutwrite.h +timeoutwrite.c +remoteinfo.h +remoteinfo.c +uint32.h1 +uint32.h2 +tryulong32.c +wait.3 +wait.h +wait_pid.c +wait_nohang.c +trywaitp.c +sig.h +sig_alarm.c +sig_block.c +sig_catch.c +sig_pause.c +sig_pipe.c +sig_child.c +sig_term.c +sig_hup.c +sig_misc.c +sig_bug.c +trysgact.c +trysgprm.c +env.3 +env.h +env.c +envread.c +byte.h +byte_chr.c +byte_copy.c +byte_cr.c +byte_diff.c +byte_rchr.c +byte_zero.c +str.h +str_chr.c +str_cpy.c +str_diff.c +str_diffn.c +str_len.c +str_rchr.c +str_start.c +lock.h +lock_ex.c +lock_exnb.c +lock_un.c +tryflock.c +getln.3 +getln.h +getln.c +getln2.3 +getln2.c +sgetopt.3 +sgetopt.h +sgetopt.c +subgetopt.3 +subgetopt.h +subgetopt.c +error.3 +error_str.3 +error_temp.3 +error.h +error.c +error_str.c +error_temp.c +fmt.h +fmt_str.c +fmt_strn.c +fmt_uint.c +fmt_uint0.c +fmt_ulong.c +scan.h +scan_ulong.c +scan_8long.c +scan_nbblong.c +slurpclose.h +slurpclose.c +quote.h +quote.c +hfield.h +hfield.c +headerbody.h +headerbody.c +token822.h +token822.c +control.h +control.c +datetime.3 +datetime.h +datetime.c +datetime_un.c +prioq.h +prioq.c +date822fmt.h +date822fmt.c +dns.h +dns.c +trylsock.c +tryrsolv.c +ip.h +ip.c +ipalloc.h +ipalloc.c +select.h1 +select.h2 +trysysel.c +ndelay.h +ndelay.c +ndelay_off.c +direntry.3 +direntry.h1 +direntry.h2 +trydrent.c +prot.h +prot.c +chkshsgr.c +warn-shsgr +tryshsgr.c +ipme.h +ipme.c +trysalen.c +maildir.5 +maildir.h +maildir.c +tcp-environ.5 diff --git a/INSTALL b/INSTALL @@ -0,0 +1,181 @@ +SAVE COPIES OF YOUR OUTGOING MAIL! Like any other piece of software (and +information generally), the qmail system comes with NO WARRANTY. It's +much more secure and reliable than sendmail, but that's not saying much. + + +Things you have to decide before starting: + +* The qmail home directory, normally /var/qmail. To change this +directory, edit conf-qmail now. + +* The names of the qmail users and the qmail groups. To change these +names, edit conf-users and conf-groups now. + + +Installation steps that won't interfere with sendmail: + + 1. Create the qmail home directory: + # mkdir /var/qmail + 2. Read INSTALL.ids. You must set up the qmail group and the qmail + users before compiling the programs. + 3. Compile the programs: + # make + 4. Create the formatted man pages, *.0: + # make man + 5. Create the qmail directory tree: + # make setup + 6. Run instcheck to make sure it doesn't print any warnings: + # make check + 7. Read INSTALL.ctl and FAQ. Minimal survival command: + # ./qmail-config + 8. Read INSTALL.alias. Minimal survival command: + # (cd ~alias; touch .qmail-postmaster .qmail-mailer-daemon .qmail-root) + # chmod 644 ~alias/.qmail* + 9. Read INSTALL.mbox. +10. Read qmail-upgrade.0. This is what your users will need to know + about the switch from sendmail to qmail. + + +Pre-upgrade tests: + +11. Enable deliveries of messages injected into qmail: + # env - PATH="/var/qmail/bin:$PATH" \ + qmail-start ./Mailbox splogger qmail & + Make sure to include the ./ in ./Mailbox. +12. Look for a + qmail: running + line in syslog. qmail-send always prints either ``cannot start'' or + ``running''. (The big number is a splogger timestamp.) +13. Do a ps and look for the qmail daemons. There should be four of + them, all idle: qmail-send, running as qmails; qmail-lspawn, running + as root; qmail-rspawn, running as qmailr; and qmail-clean, running + as qmailq. You will also see the splogger process. +14. Local-local test: Send yourself an empty message. (Replace ``me'' + with your username. Make sure to include the ``to:'' colon.) + % echo to: me | /var/qmail/bin/qmail-inject + The message will show up immediately in ~/Mailbox, and syslog will + show something like this: + qmail: new msg 53 + qmail: info msg 53: bytes 246 from <me@domain> qp 20345 uid 666 + qmail: starting delivery 1: msg 53 to local me@domain + qmail: delivery 1: success: did_1+0+0/ + qmail: end msg 53 + (53 is an inode number; 20345 is a process ID; your numbers will + probably be different.) +15. Local-error test: Send a message to a nonexistent local address. + % echo to: nonexistent | /var/qmail/bin/qmail-inject + qmail: new msg 53 + qmail: info msg 53: bytes 246 from <me@domain> qp 20351 uid 666 + qmail: starting delivery 2: msg 53 to local nonexistent@domain + qmail: delivery 2: failure: No_such_address.__#5.1.1_/ + qmail: bounce msg 53 qp 20357 + qmail: end msg 53 + qmail: new msg 54 + qmail: info msg 54: bytes 743 from <> qp 20357 uid 666 + qmail: starting delivery 3: msg 54 to local me@domain + qmail: delivery 3: success: did_1+0+0/ + qmail: end msg 54 + You will now have a bounce message in ~/Mailbox. +16. Local-remote test: Send an empty message to your account on another + machine. + % echo to: me@wherever | /var/qmail/bin/qmail-inject + qmail: new msg 53 + qmail: info msg 53: bytes 246 from <me@domain> qp 20372 uid 666 + qmail: starting delivery 4: msg 53 to remote me@wherever + qmail: delivery 4: success: 1.2.3.4_accepted_message./... + qmail: end msg 53 + There will be a pause between ``starting delivery'' and ``success''; + SMTP is slow. Check that the message is in your mailbox on the other + machine. +17. Local-postmaster test: Send mail to postmaster, any capitalization. + % echo to: POSTmaster | /var/qmail/bin/qmail-inject + Look for the message in ~alias/Mailbox. +18. Double-bounce test: Send a message with a completely bad envelope. + % /var/qmail/bin/qmail-inject -f nonexistent + To: unknownuser + Subject: testing + + This is a test. This is only a test. + % + (Use end-of-file, not dot, to end the message.) Look for the double + bounce in ~alias/Mailbox. +19. Group membership test: + % cat > ~me/.qmail-groups + |groups >> MYGROUPS; exit 0 + % /var/qmail/bin/qmail-inject me-groups < /dev/null + % cat ~me/MYGROUPS + MYGROUPS will show your normal gid and nothing else. (Under Solaris, + make sure to use /usr/ucb/groups; /usr/bin/groups is broken.) + + +Upgrading from sendmail to qmail: + +20. Read INSTALL.boot. You must replace the sendmail invocation in your + boot scripts with an appropriate qmail invocation. +21. Kill the sendmail daemon. You should first kill -STOP the daemon; if + any children are running, you should kill -CONT, wait, kill -STOP + again, and repeat ad nauseam. If there aren't any children, kill + -TERM and then kill -CONT. +22. Replace sendmail with a link to qmail's ``sendmail'' wrapper: + # mv /usr/lib/sendmail /usr/lib/sendmail.bak + # ln -s /var/qmail/bin/sendmail /usr/lib/sendmail +23. Set up qmail-smtpd in /etc/inetd.conf (all on one line): + smtp stream tcp nowait qmaild /var/qmail/bin/tcp-env + tcp-env /var/qmail/bin/qmail-smtpd + Also comment out comsat in /etc/inetd.conf. +24. Reboot. (Or kill -HUP your inetd and make sure the qmail daemons + are running.) +25. Try to flush the sendmail queue: + # /usr/lib/sendmail.bak -q + You can safely run sendmail.bak -q (or even sendmail.bak -q15m) + while qmail is running. Do this until the sendmail queue is empty. + This may take several days. +26. Disable all the sendmail and binmail programs in your system. The + safest approach is to chmod 0 everything. Some locations to check: + /usr/sbin/sendmail, /usr/lib/sendmail.bak, /usr/lib/sendmail.mx, + /bin/mail, /usr/libexec/mail.local. +27. Make sure that ``mail'' still invokes a reasonable mailer. Under + SVR4 you may want to link mail to mailx. + + +Post-upgrade tests (can be done immediately after step 24): + +28. SMTP server test: Forge some mail locally via SMTP. + % telnet 127.0.0.1 25 + Trying 127.0.0.1... + Connected to 127.0.0.1. + Escape character is '^]'. + 220 domain ESMTP + helo dude + 250-domain + 250-PIPELINING + 250 8BITMIME + mail <me@domain> + 250 ok + rcpt <me@domain> + 250 ok + data + 354 go ahead + Subject: testing + + This is a test. + . + 250 ok 812345679 qp 12345 + quit + 221 domain + Connection closed by foreign host. + % + Look for the message in your mailbox. +29. Remote-local test: Send yourself some mail from another machine. +30. Remote-error test: I think you can figure this one out. +31. UA test: Try sending mail, first to a local account, then to a + remote account, with your normal user agent. +32. Remote-postmaster test: Send mail from another machine to + PoStMaStEr@domain. Look for the message in ~alias/Mailbox. + + +That's it! To report success: + % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \ + | mail djb-qst@koobera.math.uic.edu +Replace First M. Last with your name. If you have questions about qmail, +contact qmail@pobox.com. diff --git a/INSTALL.alias b/INSTALL.alias @@ -0,0 +1,40 @@ +qmail lets each user control all addresses of the form user-anything. +Addresses that don't start with a username are controlled by a special +user, alias. Delivery instructions for foo go into ~alias/.qmail-foo; +delivery instructions for user-foo go into ~user/.qmail-foo. See +qmail-upgrade.0 and dot-qmail.0 for the full story. + +qmail doesn't have any built-in support for /etc/aliases. If you have a +big /etc/aliases and you'd like to keep it, install the qmsmac package, +available separately. /etc/aliases should already include the aliases +discussed below---Postmaster, MAILER-DAEMON, and root. + +If you don't have a big /etc/aliases, you'll find it easier to use +qmail's native alias mechanism. Here's a checklist of aliases you should +set up right now. + +* Postmaster. You're not an Internet citizen if this address doesn't +work. Simply touch (and chmod 644) ~alias/.qmail-postmaster; any mail +for Postmaster will be delivered to ~alias/Mailbox. + +* MAILER-DAEMON. Not required, but users sometimes respond to bounce +messages. Touch (and chmod 644) ~alias/.qmail-mailer-daemon. + +* root. Under qmail, root never receives mail. Your system may generate +mail messages to root every night; if you don't have an alias for root, +those messages will bounce. (They'll end up double-bouncing to the +postmaster.) Set up an alias for root in ~alias/.qmail-root. .qmail +files are similar to .forward files, but beware that they are strictly +line-oriented---see dot-qmail.0 for details. + +* Other non-user accounts. Under qmail, non-user accounts don't get +mail; ``user'' means a non-root account that owns ~account. Set up +aliases for any non-user accounts that normally receive mail. + +Note that special accounts such as ftp, www, and uucp should always have +home directories owned by root. + +* Default. If you want, you can touch ~alias/.qmail-default to catch +everything else. Beware: this will also catch typos and other addresses +that should probably be bounced instead. It won't catch addresses that +start with a user name---the user can set up his own ~/.qmail-default. diff --git a/INSTALL.boot b/INSTALL.boot @@ -0,0 +1,16 @@ +The qmail daemons have to be restarted whenever your system reboots. +Meanwhile, sendmail doesn't have to be started any more. Here's what you +should do. + +Find sendmail in your boot scripts. It's usually in either /etc/rc or +/etc/init.d/sendmail. It looks like + + sendmail -bd -q15m + +-q15m means it should run the queue every 15 minutes; you may see a +different number. Comment out this line, and replace it with + + env - PATH="/var/qmail/bin:$PATH" \ + csh -cf 'qmail-start ./Mailbox splogger qmail &' + +That's it. (Make sure you include the ./ and the &.) diff --git a/INSTALL.ctl b/INSTALL.ctl @@ -0,0 +1,29 @@ +As you've seen, qmail has essentially no pre-compilation configuration. +You should never have to recompile it unless you want to change the +qmail home directory, usernames, or uids. + +qmail does allow quite a bit of easy post-installation configuration. If +you care how your machine greets other machines via SMTP, for example, +you can put an appropriate line into /var/qmail/control/smtpgreeting. + +But this is all optional---if control/smtpgreeting doesn't exist, qmail +will do something reasonable by default. You shouldn't worry much about +configuration right now. You can always come back and tune things later. + +There's one big exception. You MUST tell qmail your hostname. The easy +way to do this is to run the qmail-config script: + + # ./qmail-config + +qmail-config finds your fully-qualified hostname in DNS and puts it into +control/me. It also selects good defaults for a few other controls. + +(Why doesn't qmail do these lookups on the fly? This was a deliberate +design decision. qmail does all its local functions---header rewriting, +checking if a recipient is local, etc.---without talking to the network. +The point is that qmail can continue accepting and delivering local mail +even if your network connection goes down.) + +Next, read through FAQ for information on setting up optional features +like masquerading. If you really want to learn right now what all the +configuration possibilities are, see qmail-control.0. diff --git a/INSTALL.ids b/INSTALL.ids @@ -0,0 +1,59 @@ +Here's how to set up the qmail groups and the qmail users. + +On some systems there are commands that make this easy. Solaris: + + # groupadd nofiles + # useradd -g nofiles -d /var/qmail/alias alias + # useradd -g nofiles -d /var/qmail qmaild + # useradd -g nofiles -d /var/qmail qmaill + # useradd -g nofiles -d /var/qmail qmailp + # groupadd qmail + # useradd -g qmail -d /var/qmail qmailq + # useradd -g qmail -d /var/qmail qmailr + # useradd -g qmail -d /var/qmail qmails + +BSDI 2.0: + + # addgroup nofiles + # adduser -g nofiles -H/var/qmail/alias -G,,, -s/dev/null -P'*' alias + # adduser -g nofiles -H/var/qmail -G,,, -s/dev/null -P'*' qmaild + # adduser -g nofiles -H/var/qmail -G,,, -s/dev/null -P'*' qmaill + # adduser -g nofiles -H/var/qmail -G,,, -s/dev/null -P'*' qmailp + # addgroup qmail + # adduser -g qmail -H/var/qmail -G,,, -s/dev/null -P'*' qmailq + # adduser -g qmail -H/var/qmail -G,,, -s/dev/null -P'*' qmailr + # adduser -g qmail -H/var/qmail -G,,, -s/dev/null -P'*' qmails + +AIX: + + # mkgroup -A nofiles + # mkuser pgrp=nofiles home=/var/qmail/alias shell=/bin/true alias + # mkuser pgrp=nofiles home=/var/qmail shell=/bin/true qmaild + # mkuser pgrp=nofiles home=/var/qmail shell=/bin/true qmaill + # mkuser pgrp=nofiles home=/var/qmail shell=/bin/true qmailp + # mkgroup -A qmail + # mkuser pgrp=qmail home=/var/qmail shell=/bin/true qmailq + # mkuser pgrp=qmail home=/var/qmail shell=/bin/true qmailr + # mkuser pgrp=qmail home=/var/qmail shell=/bin/true qmails + +On other systems, you will have to edit /etc/group and /etc/passwd +manually. First add two new lines to /etc/group, something like + + qmail:*:2107: + nofiles:*:2108: + +where 2107 and 2108 are different from the other gids in /etc/group. +Next (using vipw) add six new lines to /etc/passwd, something like + + alias:*:7790:2108::/var/qmail/alias:/bin/true + qmaild:*:7791:2108::/var/qmail:/bin/true + qmaill:*:7792:2108::/var/qmail:/bin/true + qmailp:*:7793:2108::/var/qmail:/bin/true + qmailq:*:7794:2107::/var/qmail:/bin/true + qmailr:*:7795:2107::/var/qmail:/bin/true + qmails:*:7796:2107::/var/qmail:/bin/true + +where 7790 through 7796 are _new_ uids, 2107 is the qmail gid, and 2108 +is the nofiles gid. Make sure you use the nofiles gid for qmaild, +qmaill, qmailp, and alias, and the qmail gid for qmailq, qmailr, and +qmails. diff --git a/INSTALL.mbox b/INSTALL.mbox @@ -0,0 +1,112 @@ +The qmail package includes a local delivery agent, qmail-local, which +provides user-controlled mailing lists, cross-host alias loop detection, +and many other important qmail features. + +There's one part of qmail-local that you need to know about right now: +qmail-local doesn't support an insecure central mail spool. It delivers +mail by default into ~user/Mailbox (in mbox format). + +This file explains what you should do to deal with this change. It also +points out some reasons that you might want to make an even bigger +change, switching from mbox format to a new format, maildir. + +If you desperately don't want to change anything, see INSTALL.qsmhook. + + +Contents: +1. Throw away /usr/spool/mail! +2. The trouble with mbox +3. Sun's Network F_ail_u_re System + + +1. Throw away /usr/spool/mail! + +/usr/spool/mail, often called /var/spool/mail or /var/mail, is a +security disaster. A user's mailbox belongs in his home directory, not a +shared directory. Even if you don't install qmail, you should destroy +/usr/spool/mail. This takes four steps: + + A. Convince your local mailer to deliver to ~user/Mailbox. If you're + using something like procmail, this is easy---just change SYSTEM_MBOX + in config.h. If you're installing qmail, you don't have to do + anything. Otherwise, take a look at hlfsd from + ftp.cs.columbia.edu/pub/amd. + + B. Move each /usr/spool/mail/user to ~user/Mailbox. For safety, do + this in single-user mode---you don't want to risk corrupting + mailboxes. (qmail makes it easy to turn off deliveries temporarily: + just kill the qmail-send daemon. But you aren't running qmail yet.) + When you're done, remove /usr/spool/mail. + + C. Put ``setenv MAIL $HOME/Mailbox'' in your system-wide .cshrc, + ``MAIL=$HOME/Mailbox; export MAIL'' in your system-wide .profile, + ``inbox-path=Mailbox'' in your system-wide pine.conf. If you're using + qpopper 2.2, you'll have to recompile with -DHOMEDIRMAIL in CFLAGS + and with /.mail changed to /Mailbox in pop_dropcopy.c. If you're + using elm on a multiuser system, you'll have to recompile elm with + "mailbox" changed to "Mailbox" around line 388 of newmbox.c. + + D. Announce the change. + +Some vendors, in a misguided attempt to solve the security problems of +/usr/spool/mail, have made all MUAs (e.g., /usr/ucb/Mail) setgid mail. +After you get rid of /usr/spool/mail, you can also disable those +setgid-mail bits. + + +2. The trouble with mbox + +The mbox format---the format of ~user/Mailbox, understood by BSD Mail +and lots of other MUAs---is inherently unreliable. + +Think about it: what happens if the system crashes while a program is +appending a new message to ~user/Mailbox? The message will be truncated. +Even worse, if it was truncated in the middle of a line, it will end up +being merged with the next message! Sure, the mailer understands that it +wasn't successful, so it'll try delivering the message again later, but +it can't fix your corrupted mbox. + +Other formats, such as mh folders, are just as unreliable. + +qmail supports maildir, a crashproof format for incoming mail messages. +maildir is fast and easy for MUAs to use. Even better, maildir works +wonders over NFS---see below. + +I don't want to cram maildir down people's throats, so it's not the +default. Nevertheless, I encourage you to start asking for maildir +versions of your favorite MUAs, and to switch over to maildir as soon as +you can. + +WARNING: qmail uses flock() to lock ~user/Mailbox. This agrees with the +modern mail.local locking choice. If your MUA doesn't use flock(), your +best bet is to switch to maildir, and to set up synchronous maildir2mbox +execution, as described below. + + +3. Sun's Network F_ail_u_re System + +Anyone who tells you that mail can be safely delivered in mbox format +over NFS is pulling your leg---as explained above, mbox format is +inherently unreliable even on a single machine. + +Anyway, NFS is the most unreliable computing environment ever invented, +and qmail doesn't even pretend to support mbox over NFS. + +You should switch to maildir, which works fine over NFS without any +locking. You can safely read your mail over NFS if it's in maildir +format. Any number of machines can deliver mail to you at the same time. +(On the other hand, for efficiency, it's better to get NFS out of the +picture---your mail should be delivered on the server that contains your +home directory.) + +Here's how to set up qmail to use maildir for your incoming mail: + + % maildirmake $HOME/Maildir + % echo ./Maildir/ > ~/.qmail + +Make sure you include the trailing slash on Maildir/. + +Until your MUA supports maildir, you'll probably want to convert maildir +format to (gaaack) mbox format. I've supplied a maildir2mbox utility +that does the trick, along with some tiny qail and elq and pinq wrappers +that call maildir2mbox before calling Mail or elm or pine. diff --git a/INSTALL.qsmhook b/INSTALL.qsmhook @@ -0,0 +1,53 @@ +You can set up qmail to use the same local delivery agent as sendmail, +through a mechanism called qsmhook. This file says how. + +Before you do this, may I ask why? If you simply don't want the hassle +of moving user mailboxes from /usr/spool/mail to ~, please reconsider--- +/usr/spool/mail has always been a big security problem. See, for +example, CERT advisory 95:02. + +If you're trying to preserve /etc/aliases and ~user/.forward, you're +looking the wrong way---those are handled by sendmail internally, not by +the local delivery agent. You can use your old /etc/aliases with qmail +by installing the qmsmac package. + +Perhaps you've set up an advanced agent like procmail. But most people +use procmail for nothing more than sorting mail into several mailboxes; +and that's much easier with qmail's local forwarding mechanism, which +gives each user control over user-anything. If you have a few users who +really do need procmail, they can easily run procmail from their own +.qmail files. + +Do you still want to set up qsmhook? Send me some e-mail and let me know +why. Perhaps I can provide something for you in a future qmail release. + +Here's what to do. First, tack ``:alias'' onto the end of each address +in /var/qmail/control/locals, and put the results into +/var/qmail/control/virtualdomains. For example, if control/locals has + + localhost + silverton.berkeley.edu + +then control/virtualdomains should now have (without extra spaces) + + localhost:alias + silverton.berkeley.edu:alias + +Second, cp /dev/null control/locals. + +Third, put a line into ~alias/.qmail-default, based on sendmail's Mlocal +line. For example, if sendmail.cf has + + Mlocal, P=/bin/mail, F=lsDFMPrmn, S=10, R=20, A=mail -d $u + +then ~alias/.qmail-default should have + + |qsmhook -x alias- -lsDFMPmn /bin/mail -r %g -d %u + +As another example, if sendmail.cf has + + Mlocal, P=/usr/lib/mail.local, F=flsSDFMmnP, S=10, R=20, A=mail.local -d $u + +then ~alias/.qmail-default should have + + |qsmhook -x alias- -lsDFMmnP /usr/lib/mail.local -f %g -d %u diff --git a/INTERNALS b/INTERNALS @@ -0,0 +1,155 @@ +1. Overview + +Here's the data flow in the qmail suite: + + qmail-smtpd --- qmail-queue --- qmail-send --- qmail-rspawn --- qmail-remote + / | \ +qmail-inject _/ qmail-clean \_ qmail-lspawn --- qmail-local + +Every message is added to a central queue directory by qmail-queue. +qmail-queue is invoked as needed, usually by qmail-inject for locally +generated messages, qmail-smtpd for messages received through SMTP, +qmail-local for forwarded messages, or qmail-send for bounce messages. + +Every message is then delivered by qmail-send, in cooperation with +qmail-lspawn and qmail-rspawn, and cleaned up by qmail-clean. These four +programs are long-running daemons. + +The queue is designed to be crashproof, provided that the underlying +filesystem is crashproof. All cleanups are handled by qmail-send and +qmail-clean without human intervention. See section 6 for more details. + + +2. Queue structure + +Each message in the queue is identified by a unique number, let's say +457. The queue is organized into several directories, each of which may +contain files related to message 457: + + mess/457: the message + todo/457: the envelope: where the message came from, where it's going + intd/457: the envelope, under construction by qmail-queue + info/457: the envelope sender address, after preprocessing + local/457: local envelope recipient addresses, after preprocessing + remote/457: remote envelope recipient addresses, after preprocessing + bounce/457: permanent delivery errors + +Here are all possible states for a message. + means a file exists; - +means it does not exist; ? means it may or may not exist. + + S1. -mess -intd -todo -info -local -remote -bounce + S2. +mess -intd -todo -info -local -remote -bounce + S3. +mess +intd -todo -info -local -remote -bounce + S4. +mess ?intd +todo ?info ?local ?remote -bounce (queued) + S5. +mess -intd -todo +info ?local ?remote ?bounce (preprocessed) + +Guarantee: If mess/457 exists, it has inode number 457. + + +3. How messages enter the queue + +To add a message to the queue, qmail-queue first creates a file in a +separate directory, pid/, with a unique name. The filesystem assigns +that file a unique inode number. qmail-queue looks at that number, say +457. By the guarantee above, message 457 must be in state S1. + +qmail-queue renames pid/whatever as mess/457, moving to S2. It writes +the message to mess/457. It then creates intd/457, moving to S3, and +writes the envelope information to intd/457. + +Finally qmail-queue creates a new link, todo/457, for intd/457, moving +to S4. At that instant the message has been successfully queued, and +qmail-queue leaves it for further handling by qmail-send. + +qmail-queue starts a 24-hour timer before touching any files, and +commits suicide if the timer expires. + + +4. How queued messages are preprocessed + +Once a message has been queued, qmail-send must decide which recipients +are local and which recipients are remote. It may also rewrite some +recipient addresses. + +When qmail-send notices todo/457, it knows that message 457 is in S4. It +removes info/457, local/457, and remote/457 if they exist. Then it reads +through todo/457. It creates info/457, possibly local/457, and possibly +remote/457. When it is done, it removes intd/457. The message is still +in S4 at this point. Finally qmail-send removes todo/457, moving to S5. +At that instant the message has been successfully preprocessed. + + +5. How preprocessed messages are delivered + +Messages at S5 are handled as follows. Each address in local/457 and +remote/457 is marked either NOT DONE or DONE. + + DONE: The message was successfully delivered, or the last delivery + attempt met with permanent failure. Either way, qmail-send + should not attempt further delivery to this address. + + NOT DONE: If there have been any delivery attempts, they have all + met with temporary failure. Either way, qmail-send should + try delivery in the future. + +qmail-send may at its leisure try to deliver a message to a NOT DONE +address. If the message is successfully delivered, qmail-send marks the +address as DONE. If the delivery attempt meets with permanent failure, +qmail-send first appends a note to bounce/457, creating bounce/457 if +necessary; then it marks the address as DONE. + +qmail-send may handle bounce/457 at any time, as follows: it (1) injects +a new bounce message, created from bounce/457 and mess/457; (2) deletes +bounce/457. + +When all addresses in local/457 are DONE, qmail-send deletes local/457. +Same for remote/457. + +When local/457 and remote/457 are gone, qmail-send eliminates the +message, as follows. First, if bounce/457 exists, qmail-send handles it +as described above. Once bounce/457 is definitely gone, qmail-send +deletes info/457, moving to S2, and finally mess/457, moving to S1. + + +6. Cleanups + +If the computer crashes while qmail-queue is trying to queue a message, +or while qmail-send is eliminating a message, the message may be left in +state S2 or S3. + +When qmail-send sees a message in state S2 or S3---other than one +it is currently eliminating!---where mess/457 is more than 36 hours old, +it deletes intd/457 if that exists, then deletes mess/457. Note that any +qmail-queue handling the message must be dead. + +Similarly, when qmail-send sees a file in the pid/ directory that is +more than 36 hours old, it deletes it. + +Cleanups are not necessary if the computer crashes while qmail-send is +delivering a message. At worst a message may be delivered twice. (There +is no way for a distributed mail system to eliminate the possibility of +duplication. What if an SMTP connection is broken just before the server +acknowledges successful receipt of the message? The client must assume +the worst and send the message again. Similarly, if the computer crashes +just before qmail-send marks a message as DONE, the new qmail-send must +assume the worst and send the message again. The usual solutions in the +database literature---e.g., keeping log files---amount to saying that +it's the recipient's computer's job to discard duplicate messages.) + + +7. Further notes + +Currently info/457 serves two purposes: first, it records the envelope +sender; second, its modification time is used to decide when a message +has been in the queue too long. In the future info/457 may store more +information. Any non-backwards-compatible changes will be identified by +version numbers. + +When qmail-queue has successfully placed a message into the queue, it +pulls a trigger offered by qmail-send. Here is the current triggering +mechanism: lock/trigger is a named pipe. Before scanning todo/, +qmail-send opens lock/trigger O_NDELAY for reading. It then selects for +readability on lock/trigger. qmail-queue pulls the trigger by writing a +byte O_NDELAY to lock/trigger. This makes lock/trigger readable and +wakes up qmail-send. Before scanning todo/ again, qmail-send closes and +reopens lock/trigger. diff --git a/Makefile b/Makefile @@ -0,0 +1,2181 @@ +SHELL=/bin/sh + +default: it + +addresses.0: \ +addresses.5 + nroff -man addresses.5 > addresses.0 + +alloc.a: \ +makelib alloc.o alloc_re.o + ./makelib alloc.a alloc.o alloc_re.o + +alloc.o: \ +compile alloc.c alloc.h alloc.c error.h alloc.c + ./compile alloc.c + +alloc_re.o: \ +compile alloc_re.c alloc.h alloc_re.c byte.h alloc_re.c + ./compile alloc_re.c + +auto-ccld.sh: \ +conf-cc conf-ld warn-auto.sh + ( cat warn-auto.sh; \ + echo CC=\'`head -1 conf-cc`\'; \ + echo LD=\'`head -1 conf-ld`\' \ + ) > auto-ccld.sh + +auto-gid: \ +load auto-gid.o substdio.a error.a str.a fs.a + ./load auto-gid substdio.a error.a str.a fs.a + +auto-gid.o: \ +compile auto-gid.c auto-gid.c auto-gid.c subfd.h substdio.h subfd.h \ +auto-gid.c substdio.h substdio.h auto-gid.c readwrite.h auto-gid.c \ +exit.h auto-gid.c scan.h auto-gid.c fmt.h auto-gid.c + ./compile auto-gid.c + +auto-int: \ +load auto-int.o substdio.a error.a str.a fs.a + ./load auto-int substdio.a error.a str.a fs.a + +auto-int.o: \ +compile auto-int.c substdio.h auto-int.c readwrite.h auto-int.c \ +exit.h auto-int.c scan.h auto-int.c fmt.h auto-int.c + ./compile auto-int.c + +auto-int8: \ +load auto-int8.o substdio.a error.a str.a fs.a + ./load auto-int8 substdio.a error.a str.a fs.a + +auto-int8.o: \ +compile auto-int8.c substdio.h auto-int8.c readwrite.h auto-int8.c \ +exit.h auto-int8.c scan.h auto-int8.c fmt.h auto-int8.c + ./compile auto-int8.c + +auto-str: \ +load auto-str.o substdio.a error.a str.a + ./load auto-str substdio.a error.a str.a + +auto-str.o: \ +compile auto-str.c substdio.h auto-str.c readwrite.h auto-str.c \ +exit.h auto-str.c + ./compile auto-str.c + +auto-uid: \ +load auto-uid.o substdio.a error.a str.a fs.a + ./load auto-uid substdio.a error.a str.a fs.a + +auto-uid.o: \ +compile auto-uid.c auto-uid.c auto-uid.c subfd.h substdio.h subfd.h \ +auto-uid.c substdio.h substdio.h auto-uid.c readwrite.h auto-uid.c \ +exit.h auto-uid.c scan.h auto-uid.c fmt.h auto-uid.c + ./compile auto-uid.c + +auto_break.c: \ +auto-str conf-break + ./auto-str auto_break \ + "`head -1 conf-break`" > auto_break.c + +auto_break.o: \ +compile auto_break.c + ./compile auto_break.c + +auto_patrn.c: \ +auto-int8 conf-patrn + ./auto-int8 auto_patrn `head -1 conf-patrn` > auto_patrn.c + +auto_patrn.o: \ +compile auto_patrn.c + ./compile auto_patrn.c + +auto_qmail.c: \ +auto-str conf-qmail + ./auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c + +auto_qmail.o: \ +compile auto_qmail.c + ./compile auto_qmail.c + +auto_spawn.c: \ +auto-int conf-spawn + ./auto-int auto_spawn `head -1 conf-spawn` > auto_spawn.c + +auto_spawn.o: \ +compile auto_spawn.c + ./compile auto_spawn.c + +auto_split.c: \ +auto-int conf-split + ./auto-int auto_split `head -1 conf-split` > auto_split.c + +auto_split.o: \ +compile auto_split.c + ./compile auto_split.c + +auto_uids.c: \ +auto-uid auto-gid conf-users conf-groups + ( ./auto-uid auto_uida `head -1 conf-users` \ + &&./auto-uid auto_uidd `head -2 conf-users | tail -1` \ + &&./auto-uid auto_uidl `head -3 conf-users | tail -1` \ + &&./auto-uid auto_uido `head -4 conf-users | tail -1` \ + &&./auto-uid auto_uidp `head -5 conf-users | tail -1` \ + &&./auto-uid auto_uidq `head -6 conf-users | tail -1` \ + &&./auto-uid auto_uidr `head -7 conf-users | tail -1` \ + &&./auto-uid auto_uids `head -8 conf-users | tail -1` \ + &&./auto-gid auto_gidq `head -1 conf-groups` \ + &&./auto-gid auto_gidn `head -2 conf-groups | tail -1` \ + ) > auto_uids.c + +auto_uids.o: \ +compile auto_uids.c + ./compile auto_uids.c + +auto_usera.c: \ +auto-str conf-users + ./auto-str auto_usera `head -1 conf-users` > auto_usera.c + +auto_usera.o: \ +compile auto_usera.c + ./compile auto_usera.c + +byte_chr.o: \ +compile byte_chr.c byte.h byte_chr.c + ./compile byte_chr.c + +byte_copy.o: \ +compile byte_copy.c byte.h byte_copy.c + ./compile byte_copy.c + +byte_cr.o: \ +compile byte_cr.c byte.h byte_cr.c + ./compile byte_cr.c + +byte_diff.o: \ +compile byte_diff.c byte.h byte_diff.c + ./compile byte_diff.c + +byte_rchr.o: \ +compile byte_rchr.c byte.h byte_rchr.c + ./compile byte_rchr.c + +byte_zero.o: \ +compile byte_zero.c byte.h byte_zero.c + ./compile byte_zero.c + +case.a: \ +makelib case_diffb.o case_diffs.o case_lowerb.o case_lowers.o \ +case_starts.o + ./makelib case.a case_diffb.o case_diffs.o case_lowerb.o \ + case_lowers.o case_starts.o + +case_diffb.o: \ +compile case_diffb.c case.h case_diffb.c + ./compile case_diffb.c + +case_diffs.o: \ +compile case_diffs.c case.h case_diffs.c + ./compile case_diffs.c + +case_lowerb.o: \ +compile case_lowerb.c case.h case_lowerb.c + ./compile case_lowerb.c + +case_lowers.o: \ +compile case_lowers.c case.h case_lowers.c + ./compile case_lowers.c + +case_starts.o: \ +compile case_starts.c case.h case_starts.c + ./compile case_starts.c + +cdb.a: \ +makelib cdb_hash.o cdb_unpack.o cdb_seek.o + ./makelib cdb.a cdb_hash.o cdb_unpack.o cdb_seek.o + +cdb_hash.o: \ +compile cdb_hash.c cdb.h uint32.h cdb.h cdb_hash.c + ./compile cdb_hash.c + +cdb_seek.o: \ +compile cdb_seek.c cdb_seek.c cdb_seek.c cdb.h uint32.h cdb.h \ +cdb_seek.c + ./compile cdb_seek.c + +cdb_unpack.o: \ +compile cdb_unpack.c cdb.h uint32.h cdb.h cdb_unpack.c + ./compile cdb_unpack.c + +cdbmake.a: \ +makelib cdbmake_pack.o cdbmake_hash.o cdbmake_add.o + ./makelib cdbmake.a cdbmake_pack.o cdbmake_hash.o \ + cdbmake_add.o + +cdbmake_add.o: \ +compile cdbmake_add.c cdbmake.h uint32.h cdbmake.h cdbmake_add.c + ./compile cdbmake_add.c + +cdbmake_hash.o: \ +compile cdbmake_hash.c cdbmake.h uint32.h cdbmake.h cdbmake_hash.c + ./compile cdbmake_hash.c + +cdbmake_pack.o: \ +compile cdbmake_pack.c cdbmake.h uint32.h cdbmake.h cdbmake_pack.c + ./compile cdbmake_pack.c + +cdbmss.o: \ +compile cdbmss.c readwrite.h cdbmss.c seek.h cdbmss.c alloc.h \ +cdbmss.c cdbmss.h cdbmake.h uint32.h cdbmake.h cdbmss.h substdio.h \ +cdbmss.h cdbmss.c + ./compile cdbmss.c + +check: \ +it man conf-qmail + ./qmail-hier | ./instcheck `head -1 conf-qmail` + +chkshsgr: \ +load chkshsgr.o + ./load chkshsgr + +chkshsgr.o: \ +compile chkshsgr.c exit.h chkshsgr.c + ./compile chkshsgr.c + +chkspawn: \ +load chkspawn.o substdio.a error.a str.a fs.a auto_spawn.o + ./load chkspawn substdio.a error.a str.a fs.a auto_spawn.o + +chkspawn.o: \ +compile chkspawn.c substdio.h chkspawn.c subfd.h substdio.h \ +substdio.h subfd.h chkspawn.c fmt.h chkspawn.c select.h select.h \ +select.h select.h chkspawn.c exit.h chkspawn.c auto_spawn.h \ +chkspawn.c + ./compile chkspawn.c + +clean: \ +TARGETS + rm -f `cat TARGETS` + +coe.o: \ +compile coe.c coe.c coe.h coe.c + ./compile coe.c + +compile: \ +make-compile warn-auto.sh systype + ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \ + compile + chmod 755 compile + +condredirect: \ +load condredirect.o qmail.o fd.a sig.a wait.a seek.a env.a alloc.a \ +substdio.a error.a str.a auto_qmail.o + ./load condredirect qmail.o fd.a sig.a wait.a seek.a env.a \ + alloc.a substdio.a error.a str.a auto_qmail.o + +condredirect.0: \ +condredirect.1 + nroff -man condredirect.1 > condredirect.0 + +condredirect.o: \ +compile condredirect.c sig.h condredirect.c readwrite.h \ +condredirect.c exit.h condredirect.c env.h condredirect.c error.h \ +condredirect.c fork.h condredirect.c wait.h condredirect.c seek.h \ +condredirect.c qmail.h substdio.h qmail.h condredirect.c stralloc.h \ +gen_alloc.h stralloc.h condredirect.c subfd.h substdio.h substdio.h \ +subfd.h condredirect.c substdio.h substdio.h condredirect.c + ./compile condredirect.c + +constmap.o: \ +compile constmap.c constmap.h constmap.c alloc.h constmap.c case.h \ +constmap.c + ./compile constmap.c + +control.o: \ +compile control.c readwrite.h control.c open.h control.c getln.h \ +control.c stralloc.h gen_alloc.h stralloc.h control.c substdio.h \ +control.c error.h control.c control.h control.c alloc.h control.c \ +scan.h control.c + ./compile control.c + +date822fmt.o: \ +compile date822fmt.c datetime.h date822fmt.c fmt.h date822fmt.c \ +date822fmt.h date822fmt.c + ./compile date822fmt.c + +datemail: \ +warn-auto.sh datemail.sh conf-qmail conf-break conf-split + cat warn-auto.sh datemail.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > datemail + chmod 755 datemail + +datetime.a: \ +makelib datetime.o datetime_un.o + ./makelib datetime.a datetime.o datetime_un.o + +datetime.o: \ +compile datetime.c datetime.h datetime.c + ./compile datetime.c + +datetime_un.o: \ +compile datetime_un.c datetime.h datetime_un.c + ./compile datetime_un.c + +direntry.h: \ +compile trydrent.c direntry.h1 direntry.h2 + ( ./compile trydrent.c >/dev/null 2>&1 \ + && cat direntry.h2 || cat direntry.h1 ) > direntry.h + rm -f trydrent.o + +dns.lib: \ +tryrsolv.c compile load socket.lib dns.o ipalloc.o ip.o stralloc.a \ +alloc.a error.a fs.a str.a + ( ( ./compile tryrsolv.c && ./load tryrsolv dns.o \ + ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \ + -lresolv `cat socket.lib` ) >/dev/null 2>&1 \ + && echo -lresolv || exit 0 ) > dns.lib + rm -f tryrsolv.o tryrsolv + +dns.o: \ +compile dns.c dns.c dns.c dns.c dns.c dns.c dns.c dns.c ip.h dns.c \ +ipalloc.h ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h dns.c fmt.h dns.c \ +alloc.h dns.c str.h dns.c stralloc.h gen_alloc.h stralloc.h dns.c \ +dns.h dns.c case.h dns.c + ./compile dns.c + +dnscname: \ +load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnscname dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` + +dnscname.o: \ +compile dnscname.c substdio.h dnscname.c subfd.h substdio.h \ +substdio.h subfd.h dnscname.c stralloc.h gen_alloc.h stralloc.h \ +dnscname.c dns.h dnscname.c dnsdoe.h dnscname.c readwrite.h \ +dnscname.c exit.h dnscname.c + ./compile dnscname.c + +dnsdoe.o: \ +compile dnsdoe.c substdio.h dnsdoe.c subfd.h substdio.h substdio.h \ +subfd.h dnsdoe.c exit.h dnsdoe.c dns.h dnsdoe.c dnsdoe.h dnsdoe.c + ./compile dnsdoe.c + +dnsfq: \ +load dnsfq.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnsfq dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` + +dnsfq.o: \ +compile dnsfq.c substdio.h dnsfq.c subfd.h substdio.h substdio.h \ +subfd.h dnsfq.c stralloc.h gen_alloc.h stralloc.h dnsfq.c dns.h \ +dnsfq.c dnsdoe.h dnsfq.c ip.h dnsfq.c ipalloc.h ip.h ip.h ipalloc.h \ +gen_alloc.h ipalloc.h dnsfq.c exit.h dnsfq.c + ./compile dnsfq.c + +dnsip: \ +load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnsip dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` + +dnsip.o: \ +compile dnsip.c substdio.h dnsip.c subfd.h substdio.h substdio.h \ +subfd.h dnsip.c stralloc.h gen_alloc.h stralloc.h dnsip.c dns.h \ +dnsip.c dnsdoe.h dnsip.c ip.h dnsip.c ipalloc.h ip.h ip.h ipalloc.h \ +gen_alloc.h ipalloc.h dnsip.c exit.h dnsip.c + ./compile dnsip.c + +dnsmxip: \ +load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o now.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnsmxip dns.o dnsdoe.o ip.o ipalloc.o now.o \ + stralloc.a alloc.a substdio.a error.a str.a fs.a `cat \ + dns.lib` `cat socket.lib` + +dnsmxip.o: \ +compile dnsmxip.c substdio.h dnsmxip.c subfd.h substdio.h substdio.h \ +subfd.h dnsmxip.c stralloc.h gen_alloc.h stralloc.h dnsmxip.c fmt.h \ +dnsmxip.c dns.h dnsmxip.c dnsdoe.h dnsmxip.c ip.h dnsmxip.c ipalloc.h \ +ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h dnsmxip.c now.h datetime.h \ +now.h dnsmxip.c exit.h dnsmxip.c + ./compile dnsmxip.c + +dnsptr: \ +load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnsptr dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` + +dnsptr.o: \ +compile dnsptr.c substdio.h dnsptr.c subfd.h substdio.h substdio.h \ +subfd.h dnsptr.c stralloc.h gen_alloc.h stralloc.h dnsptr.c str.h \ +dnsptr.c scan.h dnsptr.c dns.h dnsptr.c dnsdoe.h dnsptr.c ip.h \ +dnsptr.c exit.h dnsptr.c + ./compile dnsptr.c + +dot-qmail.0: \ +dot-qmail.5 + nroff -man dot-qmail.5 > dot-qmail.0 + +dot-qmail.5: \ +dot-qmail.9 conf-break conf-spawn + cat dot-qmail.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > dot-qmail.5 + +elq: \ +warn-auto.sh elq.sh conf-qmail conf-break conf-split + cat warn-auto.sh elq.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > elq + chmod 755 elq + +env.a: \ +makelib env.o envread.o + ./makelib env.a env.o envread.o + +env.o: \ +compile env.c str.h env.c alloc.h env.c env.h env.c + ./compile env.c + +envelopes.0: \ +envelopes.5 + nroff -man envelopes.5 > envelopes.0 + +envread.o: \ +compile envread.c env.h envread.c str.h envread.c + ./compile envread.c + +error.a: \ +makelib error.o error_str.o error_temp.o + ./makelib error.a error.o error_str.o error_temp.o + +error.o: \ +compile error.c error.c error.h error.c + ./compile error.c + +error_str.o: \ +compile error_str.c error_str.c error.h error_str.c + ./compile error_str.c + +error_temp.o: \ +compile error_temp.c error_temp.c error.h error_temp.c + ./compile error_temp.c + +fd.a: \ +makelib fd_copy.o fd_move.o + ./makelib fd.a fd_copy.o fd_move.o + +fd_copy.o: \ +compile fd_copy.c fd_copy.c fd.h fd_copy.c + ./compile fd_copy.c + +fd_move.o: \ +compile fd_move.c fd.h fd_move.c + ./compile fd_move.c + +fifo.o: \ +compile fifo.c fifo.c fifo.c hasmkffo.h fifo.c fifo.h fifo.c + ./compile fifo.c + +find-systype: \ +find-systype.sh auto-ccld.sh + cat auto-ccld.sh find-systype.sh > find-systype + chmod 755 find-systype + +fmt_str.o: \ +compile fmt_str.c fmt.h fmt_str.c + ./compile fmt_str.c + +fmt_strn.o: \ +compile fmt_strn.c fmt.h fmt_strn.c + ./compile fmt_strn.c + +fmt_uint.o: \ +compile fmt_uint.c fmt.h fmt_uint.c + ./compile fmt_uint.c + +fmt_uint0.o: \ +compile fmt_uint0.c fmt.h fmt_uint0.c + ./compile fmt_uint0.c + +fmt_ulong.o: \ +compile fmt_ulong.c fmt.h fmt_ulong.c + ./compile fmt_ulong.c + +fmtqfn.o: \ +compile fmtqfn.c fmtqfn.h fmtqfn.c fmt.h fmtqfn.c auto_split.h \ +fmtqfn.c + ./compile fmtqfn.c + +forgeries.0: \ +forgeries.7 + nroff -man forgeries.7 > forgeries.0 + +fork.h: \ +compile load tryvfork.c fork.h1 fork.h2 + ( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null \ + 2>&1 \ + && cat fork.h2 || cat fork.h1 ) > fork.h + rm -f tryvfork.o tryvfork + +forward: \ +load forward.o stralloc.a alloc.a qmail.o fd.a wait.a sig.a env.a \ +substdio.a error.a str.a auto_qmail.o + ./load forward stralloc.a alloc.a qmail.o fd.a wait.a \ + sig.a env.a substdio.a error.a str.a auto_qmail.o + +forward.0: \ +forward.1 + nroff -man forward.1 > forward.0 + +forward.o: \ +compile forward.c sig.h forward.c readwrite.h forward.c exit.h \ +forward.c env.h forward.c qmail.h substdio.h qmail.h forward.c \ +stralloc.h gen_alloc.h stralloc.h forward.c subfd.h substdio.h \ +substdio.h subfd.h forward.c substdio.h substdio.h forward.c + ./compile forward.c + +fs.a: \ +makelib fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o fmt_ulong.o \ +scan_ulong.o scan_8long.o scan_nbblong.o + ./makelib fs.a fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o \ + fmt_ulong.o scan_ulong.o scan_8long.o scan_nbblong.o + +getln.a: \ +makelib getln.o getln2.o + ./makelib getln.a getln.o getln2.o + +getln.o: \ +compile getln.c substdio.h getln.c byte.h getln.c stralloc.h \ +gen_alloc.h stralloc.h getln.c getln.h getln.c + ./compile getln.c + +getln2.o: \ +compile getln2.c substdio.h getln2.c stralloc.h gen_alloc.h \ +stralloc.h getln2.c byte.h getln2.c getln.h getln2.c + ./compile getln2.c + +getopt.a: \ +makelib subgetopt.o sgetopt.o + ./makelib getopt.a subgetopt.o sgetopt.o + +gfrom.o: \ +compile gfrom.c str.h gfrom.c gfrom.h gfrom.c + ./compile gfrom.c + +hasflock.h: \ +tryflock.c compile load + ( ( ./compile tryflock.c && ./load tryflock ) >/dev/null \ + 2>&1 \ + && echo \#define HASFLOCK 1 || exit 0 ) > hasflock.h + rm -f tryflock.o tryflock + +hasmkffo.h: \ +trymkffo.c compile load + ( ( ./compile trymkffo.c && ./load trymkffo ) >/dev/null \ + 2>&1 \ + && echo \#define HASMKFIFO 1 || exit 0 ) > hasmkffo.h + rm -f trymkffo.o trymkffo + +hasnpbg1.h: \ +trynpbg1.c compile load open.h open.a fifo.h fifo.o select.h + ( ( ./compile trynpbg1.c \ + && ./load trynpbg1 fifo.o open.a && ./trynpbg1 ) \ + >/dev/null 2>&1 \ + && echo \#define HASNAMEDPIPEBUG1 1 || exit 0 ) > \ + hasnpbg1.h + rm -f trynpbg1.o trynpbg1 + +hassalen.h: \ +trysalen.c compile + ( ./compile trysalen.c >/dev/null 2>&1 \ + && echo \#define HASSALEN 1 || exit 0 ) > hassalen.h + rm -f trysalen.o + +hassgact.h: \ +trysgact.c compile load + ( ( ./compile trysgact.c && ./load trysgact ) >/dev/null \ + 2>&1 \ + && echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h + rm -f trysgact.o trysgact + +hassgprm.h: \ +trysgprm.c compile load + ( ( ./compile trysgprm.c && ./load trysgprm ) >/dev/null \ + 2>&1 \ + && echo \#define HASSIGPROCMASK 1 || exit 0 ) > hassgprm.h + rm -f trysgprm.o trysgprm + +hasshsgr.h: \ +chkshsgr warn-shsgr tryshsgr.c compile load + ./chkshsgr || ( cat warn-shsgr; exit 1 ) + ( ( ./compile tryshsgr.c \ + && ./load tryshsgr && ./tryshsgr ) >/dev/null 2>&1 \ + && echo \#define HASSHORTSETGROUPS 1 || exit 0 ) > \ + hasshsgr.h + rm -f tryshsgr.o tryshsgr + +haswaitp.h: \ +trywaitp.c compile load + ( ( ./compile trywaitp.c && ./load trywaitp ) >/dev/null \ + 2>&1 \ + && echo \#define HASWAITPID 1 || exit 0 ) > haswaitp.h + rm -f trywaitp.o trywaitp + +headerbody.o: \ +compile headerbody.c stralloc.h gen_alloc.h stralloc.h headerbody.c \ +substdio.h headerbody.c getln.h headerbody.c hfield.h headerbody.c \ +headerbody.h headerbody.c + ./compile headerbody.c + +hfield.o: \ +compile hfield.c hfield.h hfield.c + ./compile hfield.c + +hostname: \ +load hostname.o substdio.a error.a str.a dns.lib socket.lib + ./load hostname substdio.a error.a str.a `cat dns.lib` \ + `cat socket.lib` + +hostname.o: \ +compile hostname.c substdio.h hostname.c subfd.h substdio.h \ +substdio.h subfd.h hostname.c readwrite.h hostname.c exit.h \ +hostname.c + ./compile hostname.c + +install: \ +load install.o fifo.o getln.a strerr.a substdio.a stralloc.a alloc.a \ +open.a error.a str.a fs.a + ./load install fifo.o getln.a strerr.a substdio.a \ + stralloc.a alloc.a open.a error.a str.a fs.a + +install.o: \ +compile install.c substdio.h install.c stralloc.h gen_alloc.h \ +stralloc.h install.c getln.h install.c readwrite.h install.c exit.h \ +install.c open.h install.c error.h install.c strerr.h install.c \ +byte.h install.c fifo.h install.c + ./compile install.c + +instcheck: \ +load instcheck.o getln.a strerr.a substdio.a stralloc.a alloc.a \ +error.a str.a fs.a + ./load instcheck getln.a strerr.a substdio.a stralloc.a \ + alloc.a error.a str.a fs.a + +instcheck.o: \ +compile instcheck.c instcheck.c instcheck.c substdio.h instcheck.c \ +stralloc.h gen_alloc.h stralloc.h instcheck.c getln.h instcheck.c \ +readwrite.h instcheck.c exit.h instcheck.c error.h instcheck.c \ +strerr.h instcheck.c byte.h instcheck.c + ./compile instcheck.c + +ip.o: \ +compile ip.c fmt.h ip.c scan.h ip.c ip.h ip.c + ./compile ip.c + +ipalloc.o: \ +compile ipalloc.c alloc.h ipalloc.c gen_allocdefs.h gen_allocdefs.h \ +gen_allocdefs.h ipalloc.c ip.h ipalloc.c ipalloc.h ip.h ip.h \ +ipalloc.h gen_alloc.h ipalloc.h ipalloc.c + ./compile ipalloc.c + +ipme.o: \ +compile ipme.c ipme.c ipme.c ipme.c ipme.c ipme.c ipme.c ipme.c \ +hassalen.h ipme.c byte.h ipme.c ip.h ipme.c ipalloc.h ip.h ip.h \ +ipalloc.h gen_alloc.h ipalloc.h ipme.c stralloc.h gen_alloc.h \ +stralloc.h ipme.c ipme.h ip.h ip.h ipme.h ipalloc.h ipalloc.h ipme.h \ +ipme.c ipme.c + ./compile ipme.c + +ipmeprint: \ +load ipmeprint.o ipme.o ip.o ipalloc.o stralloc.a alloc.a substdio.a \ +error.a str.a fs.a socket.lib + ./load ipmeprint ipme.o ip.o ipalloc.o stralloc.a alloc.a \ + substdio.a error.a str.a fs.a `cat socket.lib` + +ipmeprint.o: \ +compile ipmeprint.c subfd.h substdio.h subfd.h ipmeprint.c substdio.h \ +substdio.h ipmeprint.c ip.h ipmeprint.c ipme.h ip.h ip.h ipme.h \ +ipalloc.h ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h ipme.h \ +ipmeprint.c exit.h ipmeprint.c + ./compile ipmeprint.c + +it: \ +qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \ +qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \ +predate datemail mailsubj qmail-upq qmail-config qmail-showctl \ +qmail-newu qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-pop3d \ +qmail-popup qmail-qmtpd qmail-smtpd sendmail tcp-env dnscname dnsptr \ +dnsip dnsmxip dnsfq hostname ipmeprint qlist qlist2 qreceipt qsmhook \ +qbiff forward preline condredirect maildirmake maildir2mbox \ +maildirwatch qail elq pinq qmail-hier install instcheck + +load: \ +make-load warn-auto.sh systype + ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load + chmod 755 load + +lock.a: \ +makelib lock_ex.o lock_exnb.o lock_un.o + ./makelib lock.a lock_ex.o lock_exnb.o lock_un.o + +lock_ex.o: \ +compile lock_ex.c lock_ex.c lock_ex.c lock_ex.c hasflock.h lock_ex.c \ +lock.h lock_ex.c + ./compile lock_ex.c + +lock_exnb.o: \ +compile lock_exnb.c lock_exnb.c lock_exnb.c lock_exnb.c hasflock.h \ +lock_exnb.c lock.h lock_exnb.c + ./compile lock_exnb.c + +lock_un.o: \ +compile lock_un.c lock_un.c lock_un.c lock_un.c hasflock.h lock_un.c \ +lock.h lock_un.c + ./compile lock_un.c + +maildir.0: \ +maildir.5 + nroff -man maildir.5 > maildir.0 + +maildir.o: \ +compile maildir.c maildir.c maildir.c prioq.h datetime.h prioq.h \ +gen_alloc.h prioq.h maildir.c env.h maildir.c stralloc.h gen_alloc.h \ +stralloc.h maildir.c direntry.h direntry.h direntry.h maildir.c \ +datetime.h datetime.h maildir.c now.h datetime.h datetime.h now.h \ +maildir.c str.h maildir.c maildir.h strerr.h maildir.h maildir.c + ./compile maildir.c + +maildir2mbox: \ +load maildir2mbox.o maildir.o prioq.o now.o myctime.o gfrom.o lock.a \ +getln.a env.a open.a strerr.a stralloc.a alloc.a substdio.a error.a \ +str.a fs.a datetime.a + ./load maildir2mbox maildir.o prioq.o now.o myctime.o \ + gfrom.o lock.a getln.a env.a open.a strerr.a stralloc.a \ + alloc.a substdio.a error.a str.a fs.a datetime.a + +maildir2mbox.0: \ +maildir2mbox.1 + nroff -man maildir2mbox.1 > maildir2mbox.0 + +maildir2mbox.o: \ +compile maildir2mbox.c readwrite.h maildir2mbox.c prioq.h datetime.h \ +prioq.h gen_alloc.h prioq.h maildir2mbox.c env.h maildir2mbox.c \ +stralloc.h gen_alloc.h stralloc.h maildir2mbox.c subfd.h substdio.h \ +subfd.h maildir2mbox.c substdio.h substdio.h maildir2mbox.c getln.h \ +maildir2mbox.c error.h maildir2mbox.c open.h maildir2mbox.c lock.h \ +maildir2mbox.c gfrom.h maildir2mbox.c str.h maildir2mbox.c exit.h \ +maildir2mbox.c myctime.h maildir2mbox.c maildir.h strerr.h maildir.h \ +maildir2mbox.c + ./compile maildir2mbox.c + +maildirmake: \ +load maildirmake.o substdio.a error.a str.a + ./load maildirmake substdio.a error.a str.a + +maildirmake.0: \ +maildirmake.1 + nroff -man maildirmake.1 > maildirmake.0 + +maildirmake.o: \ +compile maildirmake.c subfd.h substdio.h subfd.h maildirmake.c \ +substdio.h substdio.h maildirmake.c error.h maildirmake.c exit.h \ +maildirmake.c + ./compile maildirmake.c + +maildirwatch: \ +load maildirwatch.o hfield.o headerbody.o maildir.o prioq.o now.o \ +getln.a env.a open.a strerr.a stralloc.a alloc.a substdio.a error.a \ +str.a + ./load maildirwatch hfield.o headerbody.o maildir.o \ + prioq.o now.o getln.a env.a open.a strerr.a stralloc.a \ + alloc.a substdio.a error.a str.a + +maildirwatch.0: \ +maildirwatch.1 + nroff -man maildirwatch.1 > maildirwatch.0 + +maildirwatch.o: \ +compile maildirwatch.c getln.h maildirwatch.c substdio.h \ +maildirwatch.c subfd.h substdio.h substdio.h subfd.h maildirwatch.c \ +prioq.h datetime.h prioq.h gen_alloc.h prioq.h maildirwatch.c \ +stralloc.h gen_alloc.h stralloc.h maildirwatch.c str.h maildirwatch.c \ +exit.h maildirwatch.c hfield.h maildirwatch.c readwrite.h \ +maildirwatch.c open.h maildirwatch.c headerbody.h maildirwatch.c \ +maildir.h strerr.h maildir.h maildirwatch.c + ./compile maildirwatch.c + +mailsubj: \ +warn-auto.sh mailsubj.sh conf-qmail conf-break conf-split + cat warn-auto.sh mailsubj.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > mailsubj + chmod 755 mailsubj + +mailsubj.0: \ +mailsubj.1 + nroff -man mailsubj.1 > mailsubj.0 + +make-compile: \ +make-compile.sh auto-ccld.sh + cat auto-ccld.sh make-compile.sh > make-compile + chmod 755 make-compile + +make-load: \ +make-load.sh auto-ccld.sh + cat auto-ccld.sh make-load.sh > make-load + chmod 755 make-load + +make-makelib: \ +make-makelib.sh auto-ccld.sh + cat auto-ccld.sh make-makelib.sh > make-makelib + chmod 755 make-makelib + +makelib: \ +make-makelib warn-auto.sh systype + ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \ + makelib + chmod 755 makelib + +man: \ +qmail-local.0 qmail-lspawn.0 qmail-getpw.0 qmail-remote.0 \ +qmail-rspawn.0 qmail-clean.0 qmail-send.0 qmail-start.0 splogger.0 \ +qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \ +qmail-pw2u.0 qmail-qread.0 qmail-qstat.0 qmail-tcpto.0 qmail-pop3d.0 \ +qmail-popup.0 qmail-qmtpd.0 qmail-smtpd.0 tcp-env.0 qlist.0 \ +qreceipt.0 qbiff.0 forward.0 preline.0 condredirect.0 maildirmake.0 \ +maildir2mbox.0 maildirwatch.0 qmail.0 qmail-upgrade.0 qmail-limits.0 \ +qmail-log.0 qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.0 \ +qmail-command.0 tcp-environ.0 maildir.0 mbox.0 addresses.0 \ +envelopes.0 forgeries.0 + +mbox.0: \ +mbox.5 + nroff -man mbox.5 > mbox.0 + +myctime.o: \ +compile myctime.c datetime.h myctime.c fmt.h myctime.c myctime.h \ +myctime.c + ./compile myctime.c + +ndelay.a: \ +makelib ndelay.o ndelay_off.o + ./makelib ndelay.a ndelay.o ndelay_off.o + +ndelay.o: \ +compile ndelay.c ndelay.c ndelay.c ndelay.h ndelay.c + ./compile ndelay.c + +ndelay_off.o: \ +compile ndelay_off.c ndelay_off.c ndelay_off.c ndelay.h ndelay_off.c + ./compile ndelay_off.c + +newfield.o: \ +compile newfield.c fmt.h newfield.c datetime.h newfield.c stralloc.h \ +gen_alloc.h stralloc.h newfield.c date822fmt.h newfield.c newfield.h \ +stralloc.h stralloc.h newfield.h newfield.c + ./compile newfield.c + +now.o: \ +compile now.c now.c datetime.h now.c now.h datetime.h datetime.h \ +now.h now.c + ./compile now.c + +open.a: \ +makelib open_append.o open_excl.o open_read.o open_trunc.o \ +open_write.o + ./makelib open.a open_append.o open_excl.o open_read.o \ + open_trunc.o open_write.o + +open_append.o: \ +compile open_append.c open_append.c open_append.c open.h \ +open_append.c + ./compile open_append.c + +open_excl.o: \ +compile open_excl.c open_excl.c open_excl.c open.h open_excl.c + ./compile open_excl.c + +open_read.o: \ +compile open_read.c open_read.c open_read.c open.h open_read.c + ./compile open_read.c + +open_trunc.o: \ +compile open_trunc.c open_trunc.c open_trunc.c open.h open_trunc.c + ./compile open_trunc.c + +open_write.o: \ +compile open_write.c open_write.c open_write.c open.h open_write.c + ./compile open_write.c + +pinq: \ +warn-auto.sh pinq.sh conf-qmail conf-break conf-split + cat warn-auto.sh pinq.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > pinq + chmod 755 pinq + +predate: \ +load predate.o datetime.a sig.a fd.a wait.a substdio.a error.a str.a \ +fs.a + ./load predate datetime.a sig.a fd.a wait.a substdio.a \ + error.a str.a fs.a + +predate.o: \ +compile predate.c predate.c predate.c datetime.h predate.c fork.h \ +predate.c wait.h predate.c fd.h predate.c fmt.h predate.c substdio.h \ +predate.c subfd.h substdio.h substdio.h subfd.h predate.c readwrite.h \ +predate.c exit.h predate.c + ./compile predate.c + +preline: \ +load preline.o fd.a wait.a sig.a env.a getopt.a substdio.a error.a \ +str.a + ./load preline fd.a wait.a sig.a env.a getopt.a substdio.a \ + error.a str.a + +preline.0: \ +preline.1 + nroff -man preline.1 > preline.0 + +preline.o: \ +compile preline.c fd.h preline.c sgetopt.h subgetopt.h sgetopt.h \ +preline.c readwrite.h preline.c subfd.h substdio.h subfd.h preline.c \ +substdio.h substdio.h preline.c exit.h preline.c fork.h preline.c \ +wait.h preline.c env.h preline.c sig.h preline.c error.h preline.c + ./compile preline.c + +prioq.o: \ +compile prioq.c alloc.h prioq.c gen_allocdefs.h gen_allocdefs.h \ +gen_allocdefs.h prioq.c prioq.h datetime.h prioq.h gen_alloc.h \ +prioq.h prioq.c + ./compile prioq.c + +prot.o: \ +compile prot.c hasshsgr.h prot.c prot.h prot.c + ./compile prot.c + +qail: \ +warn-auto.sh qail.sh conf-qmail conf-break conf-split + cat warn-auto.sh qail.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > qail + chmod 755 qail + +qbiff: \ +load qbiff.o headerbody.o hfield.o getln.a env.a open.a stralloc.a \ +alloc.a substdio.a error.a str.a + ./load qbiff headerbody.o hfield.o getln.a env.a open.a \ + stralloc.a alloc.a substdio.a error.a str.a + +qbiff.0: \ +qbiff.1 + nroff -man qbiff.1 > qbiff.0 + +qbiff.o: \ +compile qbiff.c qbiff.c qbiff.c qbiff.c readwrite.h qbiff.c \ +stralloc.h gen_alloc.h stralloc.h qbiff.c substdio.h qbiff.c subfd.h \ +substdio.h substdio.h subfd.h qbiff.c open.h qbiff.c byte.h qbiff.c \ +str.h qbiff.c headerbody.h qbiff.c hfield.h qbiff.c env.h qbiff.c \ +exit.h qbiff.c + ./compile qbiff.c + +qlist: \ +load qlist.o headerbody.o hfield.o token822.o qmail.o getln.a env.a \ +case.a sig.a fd.a wait.a open.a lock.a stralloc.a alloc.a substdio.a \ +error.a str.a auto_qmail.o + ./load qlist headerbody.o hfield.o token822.o qmail.o \ + getln.a env.a case.a sig.a fd.a wait.a open.a lock.a \ + stralloc.a alloc.a substdio.a error.a str.a auto_qmail.o + +qlist.0: \ +qlist.1 + nroff -man qlist.1 > qlist.0 + +qlist.o: \ +compile qlist.c sig.h qlist.c readwrite.h qlist.c substdio.h qlist.c \ +stralloc.h gen_alloc.h stralloc.h qlist.c subfd.h substdio.h \ +substdio.h subfd.h qlist.c getln.h qlist.c alloc.h qlist.c str.h \ +qlist.c env.h qlist.c hfield.h qlist.c case.h qlist.c token822.h \ +gen_alloc.h token822.h qlist.c error.h qlist.c gen_alloc.h qlist.c \ +gen_allocdefs.h gen_allocdefs.h gen_allocdefs.h qlist.c headerbody.h \ +qlist.c exit.h qlist.c open.h qlist.c lock.h qlist.c qmail.h \ +substdio.h substdio.h qmail.h qlist.c qlist.c + ./compile qlist.c + +qlist2: \ +warn-auto.sh qlist2.sh conf-qmail conf-break conf-split + cat warn-auto.sh qlist2.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > qlist2 + chmod 755 qlist2 + +qmail-clean: \ +load qmail-clean.o fmtqfn.o now.o getln.a sig.a stralloc.a alloc.a \ +substdio.a error.a str.a fs.a auto_qmail.o auto_split.o + ./load qmail-clean fmtqfn.o now.o getln.a sig.a stralloc.a \ + alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ + auto_split.o + +qmail-clean.0: \ +qmail-clean.8 + nroff -man qmail-clean.8 > qmail-clean.0 + +qmail-clean.o: \ +compile qmail-clean.c qmail-clean.c qmail-clean.c readwrite.h \ +qmail-clean.c sig.h qmail-clean.c now.h datetime.h now.h \ +qmail-clean.c str.h qmail-clean.c direntry.h direntry.h direntry.h \ +qmail-clean.c getln.h qmail-clean.c stralloc.h gen_alloc.h stralloc.h \ +qmail-clean.c substdio.h qmail-clean.c subfd.h substdio.h substdio.h \ +subfd.h qmail-clean.c byte.h qmail-clean.c scan.h qmail-clean.c fmt.h \ +qmail-clean.c error.h qmail-clean.c exit.h qmail-clean.c fmtqfn.h \ +qmail-clean.c auto_qmail.h qmail-clean.c + ./compile qmail-clean.c + +qmail-command.0: \ +qmail-command.8 + nroff -man qmail-command.8 > qmail-command.0 + +qmail-config: \ +warn-auto.sh qmail-config.sh conf-qmail conf-break conf-split + cat warn-auto.sh qmail-config.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > qmail-config + chmod 755 qmail-config + +qmail-control.0: \ +qmail-control.5 + nroff -man qmail-control.5 > qmail-control.0 + +qmail-control.5: \ +qmail-control.9 conf-break conf-spawn + cat qmail-control.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-control.5 + +qmail-getpw: \ +load qmail-getpw.o case.a substdio.a error.a str.a fs.a auto_break.o \ +auto_usera.o + ./load qmail-getpw case.a substdio.a error.a str.a fs.a \ + auto_break.o auto_usera.o + +qmail-getpw.0: \ +qmail-getpw.8 + nroff -man qmail-getpw.8 > qmail-getpw.0 + +qmail-getpw.8: \ +qmail-getpw.9 conf-break conf-spawn + cat qmail-getpw.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-getpw.8 + +qmail-getpw.o: \ +compile qmail-getpw.c qmail-getpw.c qmail-getpw.c qmail-getpw.c \ +readwrite.h qmail-getpw.c substdio.h qmail-getpw.c subfd.h substdio.h \ +substdio.h subfd.h qmail-getpw.c error.h qmail-getpw.c exit.h \ +qmail-getpw.c byte.h qmail-getpw.c str.h qmail-getpw.c case.h \ +qmail-getpw.c fmt.h qmail-getpw.c auto_usera.h qmail-getpw.c \ +auto_break.h qmail-getpw.c qlx.h qmail-getpw.c + ./compile qmail-getpw.c + +qmail-header.0: \ +qmail-header.5 + nroff -man qmail-header.5 > qmail-header.0 + +qmail-hier: \ +load qmail-hier.o substdio.a error.a str.a fs.a auto_split.o \ +auto_uids.o + ./load qmail-hier substdio.a error.a str.a fs.a \ + auto_split.o auto_uids.o + +qmail-hier.o: \ +compile qmail-hier.c subfd.h substdio.h subfd.h qmail-hier.c \ +substdio.h substdio.h qmail-hier.c auto_split.h qmail-hier.c \ +auto_uids.h qmail-hier.c fmt.h qmail-hier.c + ./compile qmail-hier.c + +qmail-inject: \ +load qmail-inject.o headerbody.o hfield.o newfield.o quote.o now.o \ +control.o date822fmt.o qmail.o fd.a wait.a open.a getln.a sig.a \ +getopt.a datetime.a token822.o env.a stralloc.a alloc.a substdio.a \ +error.a str.a fs.a auto_qmail.o + ./load qmail-inject headerbody.o hfield.o newfield.o \ + quote.o now.o control.o date822fmt.o qmail.o fd.a wait.a \ + open.a getln.a sig.a getopt.a datetime.a token822.o env.a \ + stralloc.a alloc.a substdio.a error.a str.a fs.a \ + auto_qmail.o + +qmail-inject.0: \ +qmail-inject.8 + nroff -man qmail-inject.8 > qmail-inject.0 + +qmail-inject.o: \ +compile qmail-inject.c sig.h qmail-inject.c substdio.h qmail-inject.c \ +stralloc.h gen_alloc.h stralloc.h qmail-inject.c subfd.h substdio.h \ +substdio.h subfd.h qmail-inject.c sgetopt.h subgetopt.h sgetopt.h \ +qmail-inject.c getln.h qmail-inject.c alloc.h qmail-inject.c str.h \ +qmail-inject.c fmt.h qmail-inject.c hfield.h qmail-inject.c \ +token822.h gen_alloc.h token822.h qmail-inject.c control.h \ +qmail-inject.c env.h qmail-inject.c gen_alloc.h qmail-inject.c \ +gen_allocdefs.h gen_allocdefs.h gen_allocdefs.h qmail-inject.c \ +error.h qmail-inject.c qmail.h substdio.h substdio.h qmail.h \ +qmail-inject.c now.h datetime.h now.h qmail-inject.c exit.h \ +qmail-inject.c quote.h qmail-inject.c headerbody.h qmail-inject.c \ +auto_qmail.h qmail-inject.c newfield.h stralloc.h stralloc.h \ +newfield.h qmail-inject.c + ./compile qmail-inject.c + +qmail-limits.0: \ +qmail-limits.7 + nroff -man qmail-limits.7 > qmail-limits.0 + +qmail-limits.7: \ +qmail-limits.9 conf-break conf-spawn + cat qmail-limits.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-limits.7 + +qmail-local: \ +load qmail-local.o qmail.o quote.o now.o gfrom.o myctime.o \ +slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a lock.a fd.a \ +wait.a env.a stralloc.a alloc.a substdio.a error.a str.a fs.a \ +datetime.a auto_qmail.o auto_patrn.o socket.lib + ./load qmail-local qmail.o quote.o now.o gfrom.o myctime.o \ + slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a \ + lock.a fd.a wait.a env.a stralloc.a alloc.a substdio.a \ + error.a str.a fs.a datetime.a auto_qmail.o auto_patrn.o \ + `cat socket.lib` + +qmail-local.0: \ +qmail-local.8 + nroff -man qmail-local.8 > qmail-local.0 + +qmail-local.o: \ +compile qmail-local.c qmail-local.c qmail-local.c readwrite.h \ +qmail-local.c sig.h qmail-local.c env.h qmail-local.c byte.h \ +qmail-local.c exit.h qmail-local.c fork.h qmail-local.c open.h \ +qmail-local.c wait.h qmail-local.c lock.h qmail-local.c seek.h \ +qmail-local.c substdio.h qmail-local.c getln.h qmail-local.c subfd.h \ +substdio.h substdio.h subfd.h qmail-local.c sgetopt.h subgetopt.h \ +sgetopt.h qmail-local.c alloc.h qmail-local.c error.h qmail-local.c \ +stralloc.h gen_alloc.h stralloc.h qmail-local.c fmt.h qmail-local.c \ +str.h qmail-local.c now.h datetime.h now.h qmail-local.c case.h \ +qmail-local.c quote.h qmail-local.c qmail.h substdio.h substdio.h \ +qmail.h qmail-local.c slurpclose.h qmail-local.c myctime.h \ +qmail-local.c gfrom.h qmail-local.c auto_patrn.h qmail-local.c + ./compile qmail-local.c + +qmail-log.0: \ +qmail-log.5 + nroff -man qmail-log.5 > qmail-log.0 + +qmail-lspawn: \ +load qmail-lspawn.o spawn.o prot.o slurpclose.o coe.o sig.a wait.a \ +case.a cdb.a fd.a open.a stralloc.a alloc.a substdio.a error.a str.a \ +fs.a auto_qmail.o auto_uids.o auto_spawn.o + ./load qmail-lspawn spawn.o prot.o slurpclose.o coe.o \ + sig.a wait.a case.a cdb.a fd.a open.a stralloc.a alloc.a \ + substdio.a error.a str.a fs.a auto_qmail.o auto_uids.o \ + auto_spawn.o + +qmail-lspawn.0: \ +qmail-lspawn.8 + nroff -man qmail-lspawn.8 > qmail-lspawn.0 + +qmail-lspawn.o: \ +compile qmail-lspawn.c fd.h qmail-lspawn.c wait.h qmail-lspawn.c \ +prot.h qmail-lspawn.c substdio.h qmail-lspawn.c stralloc.h \ +gen_alloc.h stralloc.h qmail-lspawn.c scan.h qmail-lspawn.c exit.h \ +qmail-lspawn.c fork.h qmail-lspawn.c error.h qmail-lspawn.c cdb.h \ +uint32.h cdb.h qmail-lspawn.c case.h qmail-lspawn.c slurpclose.h \ +qmail-lspawn.c auto_qmail.h qmail-lspawn.c auto_uids.h qmail-lspawn.c \ +qlx.h qmail-lspawn.c + ./compile qmail-lspawn.c + +qmail-newu: \ +load qmail-newu.o cdbmss.o getln.a open.a seek.a cdbmake.a case.a \ +stralloc.a alloc.a substdio.a error.a str.a auto_qmail.o + ./load qmail-newu cdbmss.o getln.a open.a seek.a cdbmake.a \ + case.a stralloc.a alloc.a substdio.a error.a str.a \ + auto_qmail.o + +qmail-newu.0: \ +qmail-newu.8 + nroff -man qmail-newu.8 > qmail-newu.0 + +qmail-newu.8: \ +qmail-newu.9 conf-break conf-spawn + cat qmail-newu.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-newu.8 + +qmail-newu.o: \ +compile qmail-newu.c stralloc.h gen_alloc.h stralloc.h qmail-newu.c \ +subfd.h substdio.h subfd.h qmail-newu.c getln.h qmail-newu.c \ +substdio.h substdio.h qmail-newu.c cdbmss.h cdbmake.h uint32.h \ +cdbmake.h cdbmss.h substdio.h substdio.h cdbmss.h qmail-newu.c exit.h \ +qmail-newu.c readwrite.h qmail-newu.c open.h qmail-newu.c error.h \ +qmail-newu.c case.h qmail-newu.c auto_qmail.h qmail-newu.c + ./compile qmail-newu.c + +qmail-pop3d: \ +load qmail-pop3d.o prioq.o now.o sig.a open.a getln.a stralloc.a \ +alloc.a substdio.a error.a str.a fs.a + ./load qmail-pop3d prioq.o now.o sig.a open.a getln.a \ + stralloc.a alloc.a substdio.a error.a str.a fs.a + +qmail-pop3d.0: \ +qmail-pop3d.8 + nroff -man qmail-pop3d.8 > qmail-pop3d.0 + +qmail-pop3d.o: \ +compile qmail-pop3d.c qmail-pop3d.c qmail-pop3d.c direntry.h \ +direntry.h direntry.h qmail-pop3d.c sig.h qmail-pop3d.c getln.h \ +qmail-pop3d.c stralloc.h gen_alloc.h stralloc.h qmail-pop3d.c \ +substdio.h qmail-pop3d.c alloc.h qmail-pop3d.c datetime.h \ +qmail-pop3d.c prot.h qmail-pop3d.c open.h qmail-pop3d.c prioq.h \ +datetime.h datetime.h prioq.h gen_alloc.h prioq.h qmail-pop3d.c \ +scan.h qmail-pop3d.c fmt.h qmail-pop3d.c error.h qmail-pop3d.c str.h \ +qmail-pop3d.c exit.h qmail-pop3d.c now.h datetime.h datetime.h now.h \ +qmail-pop3d.c readwrite.h qmail-pop3d.c + ./compile qmail-pop3d.c + +qmail-popup: \ +load qmail-popup.o now.o fd.a sig.a wait.a getln.a stralloc.a alloc.a \ +substdio.a error.a str.a fs.a + ./load qmail-popup now.o fd.a sig.a wait.a getln.a \ + stralloc.a alloc.a substdio.a error.a str.a fs.a + +qmail-popup.0: \ +qmail-popup.8 + nroff -man qmail-popup.8 > qmail-popup.0 + +qmail-popup.o: \ +compile qmail-popup.c qmail-popup.c qmail-popup.c fd.h qmail-popup.c \ +sig.h qmail-popup.c getln.h qmail-popup.c stralloc.h gen_alloc.h \ +stralloc.h qmail-popup.c substdio.h qmail-popup.c subfd.h substdio.h \ +substdio.h subfd.h qmail-popup.c alloc.h qmail-popup.c datetime.h \ +qmail-popup.c error.h qmail-popup.c wait.h qmail-popup.c str.h \ +qmail-popup.c now.h datetime.h datetime.h now.h qmail-popup.c fmt.h \ +qmail-popup.c exit.h qmail-popup.c readwrite.h qmail-popup.c + ./compile qmail-popup.c + +qmail-pw2u: \ +load qmail-pw2u.o constmap.o control.o open.a getln.a case.a getopt.a \ +stralloc.a alloc.a substdio.a error.a str.a fs.a auto_usera.o \ +auto_break.o auto_qmail.o + ./load qmail-pw2u constmap.o control.o open.a getln.a \ + case.a getopt.a stralloc.a alloc.a substdio.a error.a str.a \ + fs.a auto_usera.o auto_break.o auto_qmail.o + +qmail-pw2u.0: \ +qmail-pw2u.8 + nroff -man qmail-pw2u.8 > qmail-pw2u.0 + +qmail-pw2u.8: \ +qmail-pw2u.9 conf-break conf-spawn + cat qmail-pw2u.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-pw2u.8 + +qmail-pw2u.o: \ +compile qmail-pw2u.c qmail-pw2u.c qmail-pw2u.c substdio.h \ +qmail-pw2u.c readwrite.h qmail-pw2u.c subfd.h substdio.h substdio.h \ +subfd.h qmail-pw2u.c sgetopt.h subgetopt.h sgetopt.h qmail-pw2u.c \ +control.h qmail-pw2u.c constmap.h qmail-pw2u.c stralloc.h gen_alloc.h \ +stralloc.h qmail-pw2u.c fmt.h qmail-pw2u.c str.h qmail-pw2u.c scan.h \ +qmail-pw2u.c open.h qmail-pw2u.c error.h qmail-pw2u.c getln.h \ +qmail-pw2u.c auto_break.h qmail-pw2u.c auto_qmail.h qmail-pw2u.c \ +auto_usera.h qmail-pw2u.c + ./compile qmail-pw2u.c + +qmail-qmtpd: \ +load qmail-qmtpd.o control.o constmap.o received.o date822fmt.o now.o \ +qmail.o fd.a wait.a datetime.a open.a getln.a sig.a case.a env.a \ +stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o + ./load qmail-qmtpd control.o constmap.o received.o \ + date822fmt.o now.o qmail.o fd.a wait.a datetime.a open.a \ + getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a \ + error.a str.a fs.a auto_qmail.o + +qmail-qmtpd.0: \ +qmail-qmtpd.8 + nroff -man qmail-qmtpd.8 > qmail-qmtpd.0 + +qmail-qmtpd.o: \ +compile qmail-qmtpd.c stralloc.h gen_alloc.h stralloc.h qmail-qmtpd.c \ +substdio.h qmail-qmtpd.c subfd.h substdio.h substdio.h subfd.h \ +qmail-qmtpd.c qmail.h substdio.h substdio.h qmail.h qmail-qmtpd.c \ +now.h datetime.h now.h qmail-qmtpd.c str.h qmail-qmtpd.c fmt.h \ +qmail-qmtpd.c env.h qmail-qmtpd.c sig.h qmail-qmtpd.c auto_qmail.h \ +qmail-qmtpd.c now.h qmail-qmtpd.c datetime.h datetime.h qmail-qmtpd.c \ +date822fmt.h qmail-qmtpd.c readwrite.h qmail-qmtpd.c control.h \ +qmail-qmtpd.c constmap.h qmail-qmtpd.c received.h qmail-qmtpd.c + ./compile qmail-qmtpd.c + +qmail-qread: \ +load qmail-qread.o fmtqfn.o readsubdir.o date822fmt.o datetime.a \ +open.a getln.a stralloc.a alloc.a substdio.a error.a str.a fs.a \ +auto_qmail.o auto_split.o + ./load qmail-qread fmtqfn.o readsubdir.o date822fmt.o \ + datetime.a open.a getln.a stralloc.a alloc.a substdio.a \ + error.a str.a fs.a auto_qmail.o auto_split.o + +qmail-qread.0: \ +qmail-qread.8 + nroff -man qmail-qread.8 > qmail-qread.0 + +qmail-qread.o: \ +compile qmail-qread.c qmail-qread.c qmail-qread.c stralloc.h \ +gen_alloc.h stralloc.h qmail-qread.c substdio.h qmail-qread.c subfd.h \ +substdio.h substdio.h subfd.h qmail-qread.c fmt.h qmail-qread.c str.h \ +qmail-qread.c getln.h qmail-qread.c fmtqfn.h qmail-qread.c \ +readsubdir.h direntry.h direntry.h direntry.h readsubdir.h \ +qmail-qread.c auto_qmail.h qmail-qread.c open.h qmail-qread.c \ +datetime.h qmail-qread.c date822fmt.h qmail-qread.c readwrite.h \ +qmail-qread.c error.h qmail-qread.c exit.h qmail-qread.c + ./compile qmail-qread.c + +qmail-qstat: \ +warn-auto.sh qmail-qstat.sh conf-qmail conf-break conf-split + cat warn-auto.sh qmail-qstat.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > qmail-qstat + chmod 755 qmail-qstat + +qmail-qstat.0: \ +qmail-qstat.8 + nroff -man qmail-qstat.8 > qmail-qstat.0 + +qmail-queue: \ +load qmail-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o \ +datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \ +str.a fs.a auto_qmail.o auto_split.o auto_uids.o + ./load qmail-queue triggerpull.o fmtqfn.o now.o \ + date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \ + alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ + auto_split.o auto_uids.o + +qmail-queue.0: \ +qmail-queue.8 + nroff -man qmail-queue.8 > qmail-queue.0 + +qmail-queue.o: \ +compile qmail-queue.c qmail-queue.c qmail-queue.c readwrite.h \ +qmail-queue.c sig.h qmail-queue.c exit.h qmail-queue.c open.h \ +qmail-queue.c seek.h qmail-queue.c fmt.h qmail-queue.c alloc.h \ +qmail-queue.c substdio.h qmail-queue.c datetime.h qmail-queue.c now.h \ +datetime.h datetime.h now.h qmail-queue.c triggerpull.h qmail-queue.c \ +extra.h qmail-queue.c auto_qmail.h qmail-queue.c auto_uids.h \ +qmail-queue.c date822fmt.h qmail-queue.c fmtqfn.h qmail-queue.c + ./compile qmail-queue.c + +qmail-remote: \ +load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \ +timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \ +ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \ +substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib + ./load qmail-remote control.o constmap.o timeoutread.o \ + timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \ + ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ + lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ + str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` + +qmail-remote.0: \ +qmail-remote.8 + nroff -man qmail-remote.8 > qmail-remote.0 + +qmail-remote.o: \ +compile qmail-remote.c qmail-remote.c qmail-remote.c qmail-remote.c \ +qmail-remote.c sig.h qmail-remote.c getln.h qmail-remote.c stralloc.h \ +gen_alloc.h stralloc.h qmail-remote.c substdio.h qmail-remote.c \ +subfd.h substdio.h substdio.h subfd.h qmail-remote.c scan.h \ +qmail-remote.c case.h qmail-remote.c error.h qmail-remote.c \ +auto_qmail.h qmail-remote.c control.h qmail-remote.c dns.h \ +qmail-remote.c alloc.h qmail-remote.c quote.h qmail-remote.c ip.h \ +qmail-remote.c ipalloc.h ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h \ +qmail-remote.c ipme.h ip.h ip.h ipme.h ipalloc.h ipalloc.h ipme.h \ +qmail-remote.c gen_alloc.h qmail-remote.c gen_allocdefs.h \ +gen_allocdefs.h gen_allocdefs.h qmail-remote.c str.h qmail-remote.c \ +now.h datetime.h now.h qmail-remote.c exit.h qmail-remote.c \ +constmap.h qmail-remote.c tcpto.h qmail-remote.c timeoutconn.h \ +qmail-remote.c timeoutread.h qmail-remote.c timeoutwrite.h \ +qmail-remote.c + ./compile qmail-remote.c + +qmail-rspawn: \ +load qmail-rspawn.o spawn.o tcpto_clean.o now.o coe.o sig.a open.a \ +seek.a lock.a wait.a fd.a stralloc.a alloc.a substdio.a error.a str.a \ +auto_qmail.o auto_uids.o auto_spawn.o + ./load qmail-rspawn spawn.o tcpto_clean.o now.o coe.o \ + sig.a open.a seek.a lock.a wait.a fd.a stralloc.a alloc.a \ + substdio.a error.a str.a auto_qmail.o auto_uids.o \ + auto_spawn.o + +qmail-rspawn.0: \ +qmail-rspawn.8 + nroff -man qmail-rspawn.8 > qmail-rspawn.0 + +qmail-rspawn.o: \ +compile qmail-rspawn.c fd.h qmail-rspawn.c wait.h qmail-rspawn.c \ +substdio.h qmail-rspawn.c exit.h qmail-rspawn.c fork.h qmail-rspawn.c \ +error.h qmail-rspawn.c tcpto.h qmail-rspawn.c + ./compile qmail-rspawn.c + +qmail-send: \ +load qmail-send.o qsutil.o control.o constmap.o newfield.o prioq.o \ +trigger.o fmtqfn.o quote.o now.o readsubdir.o qmail.o date822fmt.o \ +datetime.a case.a ndelay.a getln.a wait.a seek.a fd.a sig.a open.a \ +lock.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ +auto_split.o + ./load qmail-send qsutil.o control.o constmap.o newfield.o \ + prioq.o trigger.o fmtqfn.o quote.o now.o readsubdir.o \ + qmail.o date822fmt.o datetime.a case.a ndelay.a getln.a \ + wait.a seek.a fd.a sig.a open.a lock.a stralloc.a alloc.a \ + substdio.a error.a str.a fs.a auto_qmail.o auto_split.o + +qmail-send.0: \ +qmail-send.8 + nroff -man qmail-send.8 > qmail-send.0 + +qmail-send.8: \ +qmail-send.9 conf-break conf-spawn + cat qmail-send.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-send.8 + +qmail-send.o: \ +compile qmail-send.c qmail-send.c qmail-send.c readwrite.h \ +qmail-send.c sig.h qmail-send.c direntry.h direntry.h direntry.h \ +qmail-send.c control.h qmail-send.c select.h select.h select.h \ +select.h qmail-send.c open.h qmail-send.c seek.h qmail-send.c exit.h \ +qmail-send.c lock.h qmail-send.c ndelay.h qmail-send.c now.h \ +datetime.h now.h qmail-send.c getln.h qmail-send.c substdio.h \ +qmail-send.c alloc.h qmail-send.c error.h qmail-send.c stralloc.h \ +gen_alloc.h stralloc.h qmail-send.c str.h qmail-send.c byte.h \ +qmail-send.c fmt.h qmail-send.c scan.h qmail-send.c case.h \ +qmail-send.c auto_qmail.h qmail-send.c trigger.h qmail-send.c \ +newfield.h stralloc.h stralloc.h newfield.h qmail-send.c quote.h \ +qmail-send.c qmail.h substdio.h substdio.h qmail.h qmail-send.c \ +qsutil.h qmail-send.c prioq.h datetime.h datetime.h prioq.h \ +gen_alloc.h prioq.h qmail-send.c constmap.h qmail-send.c fmtqfn.h \ +qmail-send.c readsubdir.h direntry.h readsubdir.h qmail-send.c + ./compile qmail-send.c + +qmail-showctl: \ +load qmail-showctl.o control.o open.a getln.a stralloc.a alloc.a \ +substdio.a error.a str.a fs.a auto_qmail.o + ./load qmail-showctl control.o open.a getln.a stralloc.a \ + alloc.a substdio.a error.a str.a fs.a auto_qmail.o + +qmail-showctl.0: \ +qmail-showctl.8 + nroff -man qmail-showctl.8 > qmail-showctl.0 + +qmail-showctl.o: \ +compile qmail-showctl.c substdio.h qmail-showctl.c subfd.h substdio.h \ +substdio.h subfd.h qmail-showctl.c exit.h qmail-showctl.c fmt.h \ +qmail-showctl.c str.h qmail-showctl.c control.h qmail-showctl.c \ +constmap.h qmail-showctl.c stralloc.h gen_alloc.h stralloc.h \ +qmail-showctl.c direntry.h direntry.h direntry.h qmail-showctl.c \ +auto_qmail.h qmail-showctl.c + ./compile qmail-showctl.c + +qmail-smtpd: \ +load qmail-smtpd.o ip.o ipme.o ipalloc.o control.o constmap.o \ +received.o date822fmt.o now.o qmail.o fd.a wait.a datetime.a open.a \ +getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a \ +str.a fs.a auto_qmail.o socket.lib + ./load qmail-smtpd ip.o ipme.o ipalloc.o control.o \ + constmap.o received.o date822fmt.o now.o qmail.o fd.a \ + wait.a datetime.a open.a getln.a sig.a case.a env.a \ + stralloc.a alloc.a substdio.a error.a str.a fs.a \ + auto_qmail.o `cat socket.lib` + +qmail-smtpd.0: \ +qmail-smtpd.8 + nroff -man qmail-smtpd.8 > qmail-smtpd.0 + +qmail-smtpd.o: \ +compile qmail-smtpd.c sig.h qmail-smtpd.c readwrite.h qmail-smtpd.c \ +getln.h qmail-smtpd.c stralloc.h gen_alloc.h stralloc.h qmail-smtpd.c \ +substdio.h qmail-smtpd.c alloc.h qmail-smtpd.c auto_qmail.h \ +qmail-smtpd.c control.h qmail-smtpd.c received.h qmail-smtpd.c \ +constmap.h qmail-smtpd.c error.h qmail-smtpd.c ipme.h ip.h ipme.h \ +ipalloc.h ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h ipme.h \ +qmail-smtpd.c ip.h ip.h qmail-smtpd.c qmail.h substdio.h substdio.h \ +qmail.h qmail-smtpd.c str.h qmail-smtpd.c fmt.h qmail-smtpd.c byte.h \ +qmail-smtpd.c case.h qmail-smtpd.c env.h qmail-smtpd.c now.h \ +datetime.h now.h qmail-smtpd.c exit.h qmail-smtpd.c + ./compile qmail-smtpd.c + +qmail-start: \ +load qmail-start.o prot.o fd.a auto_uids.o + ./load qmail-start prot.o fd.a auto_uids.o + +qmail-start.0: \ +qmail-start.8 + nroff -man qmail-start.8 > qmail-start.0 + +qmail-start.8: \ +qmail-start.9 conf-break conf-spawn + cat qmail-start.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-start.8 + +qmail-start.o: \ +compile qmail-start.c fd.h qmail-start.c prot.h qmail-start.c exit.h \ +qmail-start.c fork.h qmail-start.c auto_uids.h qmail-start.c + ./compile qmail-start.c + +qmail-tcpto: \ +load qmail-tcpto.o ip.o now.o open.a lock.a substdio.a error.a str.a \ +fs.a auto_qmail.o + ./load qmail-tcpto ip.o now.o open.a lock.a substdio.a \ + error.a str.a fs.a auto_qmail.o + +qmail-tcpto.0: \ +qmail-tcpto.8 + nroff -man qmail-tcpto.8 > qmail-tcpto.0 + +qmail-tcpto.o: \ +compile qmail-tcpto.c substdio.h qmail-tcpto.c subfd.h substdio.h \ +substdio.h subfd.h qmail-tcpto.c auto_qmail.h qmail-tcpto.c fmt.h \ +qmail-tcpto.c ip.h qmail-tcpto.c lock.h qmail-tcpto.c error.h \ +qmail-tcpto.c exit.h qmail-tcpto.c datetime.h qmail-tcpto.c now.h \ +datetime.h datetime.h now.h qmail-tcpto.c + ./compile qmail-tcpto.c + +qmail-upgrade.0: \ +qmail-upgrade.7 + nroff -man qmail-upgrade.7 > qmail-upgrade.0 + +qmail-upgrade.7: \ +qmail-upgrade.9 conf-break conf-spawn + cat qmail-upgrade.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-upgrade.7 + +qmail-upq: \ +warn-auto.sh qmail-upq.sh conf-qmail conf-break conf-split + cat warn-auto.sh qmail-upq.sh \ + | sed s}QMAIL}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPLIT}"`head -1 conf-split`"}g \ + > qmail-upq + chmod 755 qmail-upq + +qmail-users.0: \ +qmail-users.5 + nroff -man qmail-users.5 > qmail-users.0 + +qmail-users.5: \ +qmail-users.9 conf-break conf-spawn + cat qmail-users.9 \ + | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \ + | sed s}BREAK}"`head -1 conf-break`"}g \ + | sed s}SPAWN}"`head -1 conf-spawn`"}g \ + > qmail-users.5 + +qmail.0: \ +qmail.7 + nroff -man qmail.7 > qmail.0 + +qmail.o: \ +compile qmail.c substdio.h qmail.c readwrite.h qmail.c wait.h qmail.c \ +exit.h qmail.c fork.h qmail.c fd.h qmail.c qmail.h substdio.h \ +substdio.h qmail.h qmail.c auto_qmail.h qmail.c + ./compile qmail.c + +qreceipt: \ +load qreceipt.o headerbody.o hfield.o quote.o token822.o qmail.o \ +getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a substdio.a error.a \ +str.a auto_qmail.o + ./load qreceipt headerbody.o hfield.o quote.o token822.o \ + qmail.o getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a \ + substdio.a error.a str.a auto_qmail.o + +qreceipt.0: \ +qreceipt.1 + nroff -man qreceipt.1 > qreceipt.0 + +qreceipt.o: \ +compile qreceipt.c sig.h qreceipt.c env.h qreceipt.c substdio.h \ +qreceipt.c stralloc.h gen_alloc.h stralloc.h qreceipt.c subfd.h \ +substdio.h substdio.h subfd.h qreceipt.c getln.h qreceipt.c alloc.h \ +qreceipt.c str.h qreceipt.c hfield.h qreceipt.c token822.h \ +gen_alloc.h token822.h qreceipt.c error.h qreceipt.c gen_alloc.h \ +qreceipt.c gen_allocdefs.h gen_allocdefs.h gen_allocdefs.h qreceipt.c \ +headerbody.h qreceipt.c exit.h qreceipt.c open.h qreceipt.c quote.h \ +qreceipt.c qmail.h substdio.h substdio.h qmail.h qreceipt.c + ./compile qreceipt.c + +qsmhook: \ +load qsmhook.o sig.a case.a fd.a wait.a getopt.a env.a stralloc.a \ +alloc.a substdio.a error.a str.a + ./load qsmhook sig.a case.a fd.a wait.a getopt.a env.a \ + stralloc.a alloc.a substdio.a error.a str.a + +qsmhook.o: \ +compile qsmhook.c fd.h qsmhook.c stralloc.h gen_alloc.h stralloc.h \ +qsmhook.c readwrite.h qsmhook.c sgetopt.h subgetopt.h sgetopt.h \ +qsmhook.c wait.h qsmhook.c env.h qsmhook.c byte.h qsmhook.c str.h \ +qsmhook.c alloc.h qsmhook.c exit.h qsmhook.c fork.h qsmhook.c case.h \ +qsmhook.c subfd.h substdio.h subfd.h qsmhook.c error.h qsmhook.c \ +substdio.h substdio.h qsmhook.c sig.h qsmhook.c + ./compile qsmhook.c + +qsutil.o: \ +compile qsutil.c stralloc.h gen_alloc.h stralloc.h qsutil.c \ +readwrite.h qsutil.c substdio.h qsutil.c qsutil.h qsutil.c + ./compile qsutil.c + +quote.o: \ +compile quote.c stralloc.h gen_alloc.h stralloc.h quote.c str.h \ +quote.c quote.h quote.c + ./compile quote.c + +readsubdir.o: \ +compile readsubdir.c readsubdir.h direntry.h direntry.h direntry.h \ +readsubdir.h readsubdir.c fmt.h readsubdir.c scan.h readsubdir.c \ +str.h readsubdir.c auto_split.h readsubdir.c + ./compile readsubdir.c + +received.o: \ +compile received.c fmt.h received.c qmail.h substdio.h qmail.h \ +received.c now.h datetime.h now.h received.c datetime.h datetime.h \ +received.c date822fmt.h received.c received.h received.c + ./compile received.c + +remoteinfo.o: \ +compile remoteinfo.c remoteinfo.c remoteinfo.c remoteinfo.c \ +remoteinfo.c byte.h remoteinfo.c substdio.h remoteinfo.c ip.h \ +remoteinfo.c fmt.h remoteinfo.c timeoutconn.h remoteinfo.c \ +timeoutread.h remoteinfo.c timeoutwrite.h remoteinfo.c remoteinfo.h \ +remoteinfo.c + ./compile remoteinfo.c + +scan_8long.o: \ +compile scan_8long.c scan.h scan_8long.c + ./compile scan_8long.c + +scan_nbblong.o: \ +compile scan_nbblong.c scan.h scan_nbblong.c + ./compile scan_nbblong.c + +scan_ulong.o: \ +compile scan_ulong.c scan.h scan_ulong.c + ./compile scan_ulong.c + +seek.a: \ +makelib seek_cur.o seek_end.o seek_set.o seek_trunc.o + ./makelib seek.a seek_cur.o seek_end.o seek_set.o \ + seek_trunc.o + +seek_cur.o: \ +compile seek_cur.c seek_cur.c seek.h seek_cur.c + ./compile seek_cur.c + +seek_end.o: \ +compile seek_end.c seek_end.c seek.h seek_end.c + ./compile seek_end.c + +seek_set.o: \ +compile seek_set.c seek_set.c seek.h seek_set.c + ./compile seek_set.c + +seek_trunc.o: \ +compile seek_trunc.c seek_trunc.c seek.h seek_trunc.c + ./compile seek_trunc.c + +select.h: \ +compile trysysel.c select.h1 select.h2 + ( ./compile trysysel.c >/dev/null 2>&1 \ + && cat select.h2 || cat select.h1 ) > select.h + rm -f trysysel.o trysysel + +sendmail: \ +load sendmail.o env.a getopt.a alloc.a substdio.a error.a str.a \ +auto_qmail.o + ./load sendmail env.a getopt.a alloc.a substdio.a error.a \ + str.a auto_qmail.o + +sendmail.o: \ +compile sendmail.c sgetopt.h subgetopt.h sgetopt.h sendmail.c \ +substdio.h sendmail.c subfd.h substdio.h substdio.h subfd.h \ +sendmail.c alloc.h sendmail.c auto_qmail.h sendmail.c exit.h \ +sendmail.c env.h sendmail.c str.h sendmail.c + ./compile sendmail.c + +setup: \ +it man conf-qmail + ./qmail-hier | ./install `head -1 conf-qmail` + +sgetopt.o: \ +compile sgetopt.c substdio.h sgetopt.c subfd.h substdio.h substdio.h \ +subfd.h sgetopt.c sgetopt.h sgetopt.h subgetopt.h sgetopt.h sgetopt.c \ +subgetopt.h subgetopt.h sgetopt.c + ./compile sgetopt.c + +shar: \ +FILES BLURB BLURB2 BLURB3 BLURB4 README FAQ INSTALL INSTALL.alias \ +INSTALL.boot INSTALL.ctl INSTALL.ids INSTALL.mbox INSTALL.qsmhook \ +UPGRADE THOUGHTS TODO THANKS CHANGES RFCHCSC RFCLOOPS RFCMXPS \ +RFCNETSTR RFCNRUDT RFCQMTP RFCQSBMF RFCVERP SECURITY INTERNALS FILES \ +VERSION SYSDEPS TARGETS Makefile conf-break auto_break.h conf-spawn \ +auto_spawn.h chkspawn.c conf-split auto_split.h conf-patrn \ +auto_patrn.h conf-users conf-groups auto_uids.h auto_usera.h extra.h \ +addresses.5 condredirect.1 dot-qmail.9 envelopes.5 forgeries.7 \ +forward.1 maildir2mbox.1 maildirmake.1 maildirwatch.1 mailsubj.1 \ +mbox.5 preline.1 qbiff.1 qlist.1 qmail-clean.8 qmail-command.8 \ +qmail-control.5 qmail-getpw.9 qmail-header.5 qmail-inject.8 \ +qmail-limits.9 qmail-local.8 qmail-log.5 qmail-lspawn.8 qmail-newu.8 \ +qmail-pop3d.8 qmail-popup.8 qmail-pw2u.9 qmail-qmtpd.8 qmail-qread.8 \ +qmail-qstat.8 qmail-queue.8 qmail-remote.8 qmail-rspawn.8 \ +qmail-send.9 qmail-showctl.8 qmail-smtpd.8 qmail-start.8 \ +qmail-tcpto.8 qmail-upgrade.9 qmail-users.5 qmail.7 qreceipt.1 \ +splogger.8 tcp-env.1 qmail-clean.c qmail-config.sh qmail-getpw.c \ +qmail-hier.c qmail-inject.c qmail-local.c qmail-lspawn.c qmail-newu.c \ +qmail-pop3d.c qmail-popup.c qmail-pw2u.c qmail-qmtpd.c qmail-qread.c \ +qmail-qstat.sh qmail-queue.c qmail-remote.c qmail-rspawn.c \ +qmail-send.c qmail-showctl.c qmail-smtpd.c qmail-start.c \ +qmail-tcpto.c spawn.c dnscname.c dnsfq.c dnsip.c dnsmxip.c dnsptr.c \ +hostname.c ipmeprint.c tcp-env.c sendmail.c qlist.c qreceipt.c \ +qsmhook.c qbiff.c forward.c preline.c predate.c condredirect.c \ +maildirmake.c maildir2mbox.c maildirwatch.c splogger.c qail.sh elq.sh \ +pinq.sh qlist2.sh qmail-upq.sh datemail.sh mailsubj.sh qlx.h \ +constmap.h constmap.c dnsdoe.h dnsdoe.c fmtqfn.h fmtqfn.c gfrom.h \ +gfrom.c myctime.h myctime.c newfield.h newfield.c qsutil.h qsutil.c \ +readsubdir.h readsubdir.c received.h received.c tcpto.h tcpto.c \ +tcpto_clean.c trigger.h trigger.c triggerpull.h triggerpull.c \ +trynpbg1.c trysyslog.c conf-cc conf-ld find-systype.sh \ +make-compile.sh make-load.sh make-makelib.sh trycpp.c warn-auto.sh \ +auto-str.c auto-int.c auto-int8.c auto-gid.c auto-uid.c install.c \ +instcheck.c alloc.3 alloc.h alloc.c alloc_re.c case.3 case.h \ +case_diffb.c case_diffs.c case_lowerb.c case_lowers.c case_starts.c \ +cdb.3 cdb.h cdb_hash.c cdb_seek.c cdb_unpack.c cdbmake.h \ +cdbmake_add.c cdbmake_hash.c cdbmake_pack.c cdbmss.h cdbmss.c coe.3 \ +coe.h coe.c fd.h fd_copy.3 fd_copy.c fd_move.3 fd_move.c fifo_make.3 \ +fifo.h fifo.c trymkffo.c fork.h1 fork.h2 tryvfork.c now.3 now.h now.c \ +open.h open_append.c open_excl.c open_read.c open_trunc.c \ +open_write.c seek.h seek_cur.c seek_end.c seek_set.c seek_trunc.c \ +conf-qmail auto_qmail.h qmail.h qmail.c gen_alloc.h gen_allocdefs.h \ +stralloc.3 stralloc.h stralloc_eady.c stralloc_pend.c stralloc_copy.c \ +stralloc_opyb.c stralloc_opys.c stralloc_cat.c stralloc_catb.c \ +stralloc_cats.c stralloc_arts.c strerr.h strerr_sys.c strerr_die.c \ +substdio.h substdio.c substdi.c substdo.c substdio_copy.c subfd.h \ +subfderr.c subfdouts.c subfdout.c subfdins.c subfdin.c readwrite.h \ +exit.h timeoutconn.h timeoutconn.c timeoutread.h timeoutread.c \ +timeoutwrite.h timeoutwrite.c remoteinfo.h remoteinfo.c uint32.h1 \ +uint32.h2 tryulong32.c wait.3 wait.h wait_pid.c wait_nohang.c \ +trywaitp.c sig.h sig_alarm.c sig_block.c sig_catch.c sig_pause.c \ +sig_pipe.c sig_child.c sig_term.c sig_hup.c sig_misc.c sig_bug.c \ +trysgact.c trysgprm.c env.3 env.h env.c envread.c byte.h byte_chr.c \ +byte_copy.c byte_cr.c byte_diff.c byte_rchr.c byte_zero.c str.h \ +str_chr.c str_cpy.c str_diff.c str_diffn.c str_len.c str_rchr.c \ +str_start.c lock.h lock_ex.c lock_exnb.c lock_un.c tryflock.c getln.3 \ +getln.h getln.c getln2.3 getln2.c sgetopt.3 sgetopt.h sgetopt.c \ +subgetopt.3 subgetopt.h subgetopt.c error.3 error_str.3 error_temp.3 \ +error.h error.c error_str.c error_temp.c fmt.h fmt_str.c fmt_strn.c \ +fmt_uint.c fmt_uint0.c fmt_ulong.c scan.h scan_ulong.c scan_8long.c \ +scan_nbblong.c slurpclose.h slurpclose.c quote.h quote.c hfield.h \ +hfield.c headerbody.h headerbody.c token822.h token822.c control.h \ +control.c datetime.3 datetime.h datetime.c datetime_un.c prioq.h \ +prioq.c date822fmt.h date822fmt.c dns.h dns.c trylsock.c tryrsolv.c \ +ip.h ip.c ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h \ +ndelay.c ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c \ +prot.h prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c \ +trysalen.c maildir.5 maildir.h maildir.c tcp-environ.5 + shar -m `cat FILES` > shar + chmod 400 shar + +sig.a: \ +makelib sig_alarm.o sig_block.o sig_catch.o sig_pause.o sig_pipe.o \ +sig_child.o sig_hup.o sig_term.o sig_bug.o sig_misc.o + ./makelib sig.a sig_alarm.o sig_block.o sig_catch.o \ + sig_pause.o sig_pipe.o sig_child.o sig_hup.o sig_term.o \ + sig_bug.o sig_misc.o + +sig_alarm.o: \ +compile sig_alarm.c sig_alarm.c sig.h sig_alarm.c + ./compile sig_alarm.c + +sig_block.o: \ +compile sig_block.c sig_block.c sig.h sig_block.c hassgprm.h \ +sig_block.c + ./compile sig_block.c + +sig_bug.o: \ +compile sig_bug.c sig_bug.c sig.h sig_bug.c + ./compile sig_bug.c + +sig_catch.o: \ +compile sig_catch.c sig_catch.c sig.h sig_catch.c hassgact.h \ +sig_catch.c + ./compile sig_catch.c + +sig_child.o: \ +compile sig_child.c sig_child.c sig.h sig_child.c + ./compile sig_child.c + +sig_hup.o: \ +compile sig_hup.c sig_hup.c sig.h sig_hup.c + ./compile sig_hup.c + +sig_misc.o: \ +compile sig_misc.c sig_misc.c sig.h sig_misc.c + ./compile sig_misc.c + +sig_pause.o: \ +compile sig_pause.c sig_pause.c sig.h sig_pause.c hassgprm.h \ +sig_pause.c + ./compile sig_pause.c + +sig_pipe.o: \ +compile sig_pipe.c sig_pipe.c sig.h sig_pipe.c + ./compile sig_pipe.c + +sig_term.o: \ +compile sig_term.c sig_term.c sig.h sig_term.c + ./compile sig_term.c + +slurpclose.o: \ +compile slurpclose.c stralloc.h gen_alloc.h stralloc.h slurpclose.c \ +readwrite.h slurpclose.c slurpclose.h slurpclose.c + ./compile slurpclose.c + +socket.lib: \ +trylsock.c compile load + ( ( ./compile trylsock.c && \ + ./load trylsock -lsocket -lnsl ) >/dev/null 2>&1 \ + && echo -lsocket -lnsl || exit 0 ) > socket.lib + rm -f trylsock.o trylsock + +spawn.o: \ +compile chkspawn spawn.c spawn.c spawn.c sig.h spawn.c wait.h spawn.c \ +substdio.h spawn.c byte.h spawn.c str.h spawn.c stralloc.h \ +gen_alloc.h stralloc.h spawn.c select.h select.h select.h select.h \ +spawn.c exit.h spawn.c coe.h spawn.c open.h spawn.c error.h spawn.c \ +auto_qmail.h spawn.c auto_uids.h spawn.c auto_spawn.h spawn.c + ./chkspawn + ./compile spawn.c + +splogger: \ +load splogger.o substdio.a error.a str.a fs.a syslog.lib + ./load splogger substdio.a error.a str.a fs.a `cat \ + syslog.lib` + +splogger.0: \ +splogger.8 + nroff -man splogger.8 > splogger.0 + +splogger.o: \ +compile splogger.c splogger.c splogger.c splogger.c error.h \ +splogger.c substdio.h splogger.c subfd.h substdio.h substdio.h \ +subfd.h splogger.c exit.h splogger.c str.h splogger.c scan.h \ +splogger.c fmt.h splogger.c + ./compile splogger.c + +str.a: \ +makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \ +str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_diff.o byte_copy.o \ +byte_cr.o byte_zero.o + ./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \ + str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \ + byte_diff.o byte_copy.o byte_cr.o byte_zero.o + +str_chr.o: \ +compile str_chr.c str.h str_chr.c + ./compile str_chr.c + +str_cpy.o: \ +compile str_cpy.c str.h str_cpy.c + ./compile str_cpy.c + +str_diff.o: \ +compile str_diff.c str.h str_diff.c + ./compile str_diff.c + +str_diffn.o: \ +compile str_diffn.c str.h str_diffn.c + ./compile str_diffn.c + +str_len.o: \ +compile str_len.c str.h str_len.c + ./compile str_len.c + +str_rchr.o: \ +compile str_rchr.c str.h str_rchr.c + ./compile str_rchr.c + +str_start.o: \ +compile str_start.c str.h str_start.c + ./compile str_start.c + +stralloc.a: \ +makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \ +stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \ +stralloc_catb.o stralloc_arts.o + ./makelib stralloc.a stralloc_eady.o stralloc_pend.o \ + stralloc_copy.o stralloc_opys.o stralloc_opyb.o \ + stralloc_cat.o stralloc_cats.o stralloc_catb.o \ + stralloc_arts.o + +stralloc_arts.o: \ +compile stralloc_arts.c byte.h stralloc_arts.c str.h stralloc_arts.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_arts.c + ./compile stralloc_arts.c + +stralloc_cat.o: \ +compile stralloc_cat.c byte.h stralloc_cat.c stralloc.h gen_alloc.h \ +stralloc.h stralloc_cat.c + ./compile stralloc_cat.c + +stralloc_catb.o: \ +compile stralloc_catb.c stralloc.h gen_alloc.h stralloc.h \ +stralloc_catb.c byte.h stralloc_catb.c + ./compile stralloc_catb.c + +stralloc_cats.o: \ +compile stralloc_cats.c byte.h stralloc_cats.c str.h stralloc_cats.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_cats.c + ./compile stralloc_cats.c + +stralloc_copy.o: \ +compile stralloc_copy.c byte.h stralloc_copy.c stralloc.h gen_alloc.h \ +stralloc.h stralloc_copy.c + ./compile stralloc_copy.c + +stralloc_eady.o: \ +compile stralloc_eady.c alloc.h stralloc_eady.c stralloc.h \ +gen_alloc.h stralloc.h stralloc_eady.c gen_allocdefs.h \ +gen_allocdefs.h gen_allocdefs.h stralloc_eady.c + ./compile stralloc_eady.c + +stralloc_opyb.o: \ +compile stralloc_opyb.c stralloc.h gen_alloc.h stralloc.h \ +stralloc_opyb.c byte.h stralloc_opyb.c + ./compile stralloc_opyb.c + +stralloc_opys.o: \ +compile stralloc_opys.c byte.h stralloc_opys.c str.h stralloc_opys.c \ +stralloc.h gen_alloc.h stralloc.h stralloc_opys.c + ./compile stralloc_opys.c + +stralloc_pend.o: \ +compile stralloc_pend.c alloc.h stralloc_pend.c stralloc.h \ +gen_alloc.h stralloc.h stralloc_pend.c gen_allocdefs.h \ +gen_allocdefs.h gen_allocdefs.h stralloc_pend.c + ./compile stralloc_pend.c + +strerr.a: \ +makelib strerr_sys.o strerr_die.o + ./makelib strerr.a strerr_sys.o strerr_die.o + +strerr_die.o: \ +compile strerr_die.c substdio.h strerr_die.c subfd.h substdio.h \ +substdio.h subfd.h strerr_die.c exit.h strerr_die.c strerr.h \ +strerr_die.c + ./compile strerr_die.c + +strerr_sys.o: \ +compile strerr_sys.c error.h strerr_sys.c strerr.h strerr_sys.c + ./compile strerr_sys.c + +subfderr.o: \ +compile subfderr.c readwrite.h subfderr.c substdio.h subfderr.c \ +subfd.h substdio.h substdio.h subfd.h subfderr.c + ./compile subfderr.c + +subfdin.o: \ +compile subfdin.c readwrite.h subfdin.c substdio.h subfdin.c subfd.h \ +substdio.h substdio.h subfd.h subfdin.c + ./compile subfdin.c + +subfdins.o: \ +compile subfdins.c readwrite.h subfdins.c substdio.h subfdins.c \ +subfd.h substdio.h substdio.h subfd.h subfdins.c + ./compile subfdins.c + +subfdout.o: \ +compile subfdout.c readwrite.h subfdout.c substdio.h subfdout.c \ +subfd.h substdio.h substdio.h subfd.h subfdout.c + ./compile subfdout.c + +subfdouts.o: \ +compile subfdouts.c readwrite.h subfdouts.c substdio.h subfdouts.c \ +subfd.h substdio.h substdio.h subfd.h subfdouts.c + ./compile subfdouts.c + +subgetopt.o: \ +compile subgetopt.c subgetopt.h subgetopt.h subgetopt.c + ./compile subgetopt.c + +substdi.o: \ +compile substdi.c substdio.h substdi.c byte.h substdi.c error.h \ +substdi.c + ./compile substdi.c + +substdio.a: \ +makelib substdio.o substdi.o substdo.o subfderr.o subfdout.o \ +subfdouts.o subfdin.o subfdins.o substdio_copy.o + ./makelib substdio.a substdio.o substdi.o substdo.o \ + subfderr.o subfdout.o subfdouts.o subfdin.o subfdins.o \ + substdio_copy.o + +substdio.o: \ +compile substdio.c substdio.h substdio.c + ./compile substdio.c + +substdio_copy.o: \ +compile substdio_copy.c substdio.h substdio_copy.c + ./compile substdio_copy.c + +substdo.o: \ +compile substdo.c substdio.h substdo.c str.h substdo.c byte.h \ +substdo.c error.h substdo.c + ./compile substdo.c + +syslog.lib: \ +trysyslog.c compile load + ( ( ./compile trysyslog.c && \ + ./load trysyslog -lgen ) >/dev/null 2>&1 \ + && echo -lgen || exit 0 ) > syslog.lib + rm -f trysyslog.o trysyslog + +systype: \ +find-systype trycpp.c + ./find-systype > systype + +tcp-env: \ +load tcp-env.o dns.o remoteinfo.o timeoutread.o timeoutwrite.o \ +timeoutconn.o ip.o ipalloc.o case.a ndelay.a sig.a env.a getopt.a \ +stralloc.a alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib + ./load tcp-env dns.o remoteinfo.o timeoutread.o \ + timeoutwrite.o timeoutconn.o ip.o ipalloc.o case.a ndelay.a \ + sig.a env.a getopt.a stralloc.a alloc.a substdio.a error.a \ + str.a fs.a `cat dns.lib` `cat socket.lib` + +tcp-env.0: \ +tcp-env.1 + nroff -man tcp-env.1 > tcp-env.0 + +tcp-env.o: \ +compile tcp-env.c tcp-env.c tcp-env.c tcp-env.c tcp-env.c sig.h \ +tcp-env.c stralloc.h gen_alloc.h stralloc.h tcp-env.c str.h tcp-env.c \ +env.h tcp-env.c fmt.h tcp-env.c scan.h tcp-env.c subgetopt.h \ +tcp-env.c ip.h tcp-env.c dns.h tcp-env.c byte.h tcp-env.c \ +remoteinfo.h tcp-env.c exit.h tcp-env.c case.h tcp-env.c + ./compile tcp-env.c + +tcp-environ.0: \ +tcp-environ.5 + nroff -man tcp-environ.5 > tcp-environ.0 + +tcpto.o: \ +compile tcpto.c tcpto.h tcpto.c open.h tcpto.c lock.h tcpto.c seek.h \ +tcpto.c now.h datetime.h now.h tcpto.c ip.h tcpto.c byte.h tcpto.c \ +datetime.h datetime.h tcpto.c readwrite.h tcpto.c + ./compile tcpto.c + +tcpto_clean.o: \ +compile tcpto_clean.c tcpto.h tcpto_clean.c open.h tcpto_clean.c \ +substdio.h tcpto_clean.c readwrite.h tcpto_clean.c + ./compile tcpto_clean.c + +timeoutconn.o: \ +compile timeoutconn.c timeoutconn.c timeoutconn.c timeoutconn.c \ +timeoutconn.c ndelay.h timeoutconn.c select.h select.h select.h \ +select.h timeoutconn.c error.h timeoutconn.c readwrite.h \ +timeoutconn.c ip.h timeoutconn.c byte.h timeoutconn.c timeoutconn.h \ +timeoutconn.c + ./compile timeoutconn.c + +timeoutread.o: \ +compile timeoutread.c timeoutread.h timeoutread.c select.h select.h \ +select.h select.h timeoutread.c error.h timeoutread.c readwrite.h \ +timeoutread.c + ./compile timeoutread.c + +timeoutwrite.o: \ +compile timeoutwrite.c timeoutwrite.h timeoutwrite.c select.h \ +select.h select.h select.h timeoutwrite.c error.h timeoutwrite.c \ +readwrite.h timeoutwrite.c + ./compile timeoutwrite.c + +token822.o: \ +compile token822.c stralloc.h gen_alloc.h stralloc.h token822.c \ +alloc.h token822.c str.h token822.c token822.h gen_alloc.h token822.h \ +token822.c gen_allocdefs.h gen_allocdefs.h gen_allocdefs.h token822.c + ./compile token822.c + +trigger.o: \ +compile trigger.c select.h select.h select.h select.h trigger.c \ +open.h trigger.c trigger.h trigger.c hasnpbg1.h trigger.c + ./compile trigger.c + +triggerpull.o: \ +compile triggerpull.c ndelay.h triggerpull.c open.h triggerpull.c \ +triggerpull.h triggerpull.c + ./compile triggerpull.c + +uint32.h: \ +tryulong32.c compile load uint32.h1 uint32.h2 + ( ( ./compile tryulong32.c && ./load tryulong32 && \ + ./tryulong32 ) >/dev/null 2>&1 \ + && cat uint32.h2 || cat uint32.h1 ) > uint32.h + rm -f tryulong32.o tryulong32 + +wait.a: \ +makelib wait_pid.o wait_nohang.o + ./makelib wait.a wait_pid.o wait_nohang.o + +wait_nohang.o: \ +compile wait_nohang.c wait_nohang.c wait_nohang.c haswaitp.h \ +wait_nohang.c + ./compile wait_nohang.c + +wait_pid.o: \ +compile wait_pid.c wait_pid.c wait_pid.c error.h wait_pid.c + ./compile wait_pid.c diff --git a/README b/README @@ -0,0 +1,199 @@ +qmail 1.01 +19970413 +Copyright 1997 +D. J. Bernstein, qmail@pobox.com + +qmail is a secure, reliable, efficient, simple message transfer agent. +It is meant as a replacement for the entire sendmail-binmail system on +typical Internet-connected UNIX hosts. See BLURB, BLURB2, BLURB3, and +BLURB4 for more detailed advertisements. + +INSTALL says how to set up and test qmail. If you're upgrading from +1.00, read UPGRADE instead. + +See http://pobox.com/~djb/qmail.html for other qmail-related software +and a pointer to the qmail mailing list. + +Other documentation here: RFC* explain solutions to several Internet +mail problems; all of these except RFCMXPS are implemented in qmail. +CHANGES and THANKS show how qmail has changed since it was first +released. SECURITY, INTERNALS, THOUGHTS, and TODO record many of the +qmail design decisions. + +The rest of this file is a list of systypes where various versions of +qmail have been reported to work. 0.90 was the first gamma version. 0.96 +was the final gamma version. 1.00 had exactly the same code as 0.96. To +see your systype, make systype; cat systype. + +1.00: a.ux-3.0-svr2-:-:-:mc68030-:- (tnx RF) +0.96: aix-3-2-:-:-:000011216700-:- (tnx JLB) +0.91: aix-3-2-:-:-:000109257500-:- +0.96: aix-4-1-:-:-:000088581000-:- (tnx HJB) +0.95: aix-4-1-:-:-:00061176a600-:- (tnx JS) +1.00: aix-4-1-:-:-:00910033a000-:- (tnx K2J) +0.91: aix-4-2-:-:-:006030934c00-:- +1.00: bsd.os-2.0.1-:i386-:-:i486-:- (tnx KR) +0.93: bsd.os-2.0.1-:i386-:-:pentium-:- +0.96: bsd.os-2.1-:i386-:-:-:- (tnx DAR) +1.00: bsd.os-2.1-:i386-:-:i486-:- (tnx RJC) +0.96: bsd.os-2.1-:i386-:-:pentium-:- (tnx DAR) +0.96: dgux-5.4r2.01-generic-:-:-:aviion-:- (tnx HWM) +0.93: dgux-5.4r3.10-generic-:-:-:aviion-:- (tnx HWM) +0.91: freebsd-2.0.5-release-:i386-:-:-:- (tnx TG) +0.92: freebsd-2.1-stable-:i386-:-:pentium.815\100-:- +0.90: freebsd-2.1.0-release-:i386-:-:cy486dlc-:- (tnx G2A) +1.00: freebsd-2.1.0-release-:i386-:-:i486-dx2-:- (tnx JLB) +1.00: freebsd-2.1.0-release-:i386-:-:i486-dx-:- (tnx chrisj=???) +0.96: freebsd-2.1.0-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx MBS) +0.95: freebsd-2.1.5-release-:i386-:-:-:- (tnx NAA) +0.96: freebsd-2.1.5-release-:i386-:-:i486-dx-:- (tnx FN) +0.95: freebsd-2.1.5-release-:i386-:-:pentium.510\60.or.567\66-:- (tnx M2L) +0.95: freebsd-2.1.5-release-:i386-:-:pentium.735\90-:- (tnx AG) +0.92: freebsd-2.1.5-stable-:i386-:-:pentium.735\90.or.815\100-:- (tnx FE) +1.00: freebsd-2.1.6-release-:i386-:-:-:- (tnx TM) +0.96: freebsd-2.1.6-release-:i386-:-:Pentium-Pro.150-:- (tnx CH) +0.96: freebsd-2.1.6-release-:i386-:-:i486-dx-:- (tnx HCJ) +0.95: freebsd-2.1.6-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx M2L) +0.96: freebsd-2.1.6.1-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx MF) +1.00: freebsd-2.1.7-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx JBB) +0.95: freebsd-2.2-beta_a-:i386-:-:i486-dx2-:- (tnx DA) +0.91: freebsd-2.2-current-:i386-:-:i486-dx-:- (tnx DC) +1.00: freebsd-2.2-release-:i386-:-:-:- (tnx MT) +1.00: freebsd-2.2.1-release-:i386-:-:-:- (tnx TM) +1.00: freebsd-2.2.1-release-:i386-:-:i486-dx2-:- (tnx BR) +1.00: freebsd-2.2.1-release-:i386-:-:pentium-:- (tnx IW) +0.92: freebsd-3.0-current-:i386-:-:pentium-:- (tnx J2M) +1.00: hp-ux-b.09.00-a-:-:-:9000.360-:- (tnx VV) +0.91: hp-ux-b.10.01-a-:-:-:9000.712-:- (tnx S2R) +0.94: hp-ux-b.10.01-a-:-:-:9000.715-:- (tnx BG) +0.91: hp-ux-b.10.01-a-:-:-:9000.801-:- (tnx S2T) +0.93: irix-5.3-02091401-:-:-:ip22-:- (tnx PW) +0.91: irix-5.3-11091811-:sgi-:-:ip19-:- (tnx BS) +0.96: irix-5.3-11091812-:-:-:ip22-:- (tnx JL) +1.00: irix-6.2-03131015-:-:-:ip22-:- (tnx SAS) +0.92: linux-1.2.13-:i386-:-:i386-:- (tnx RN) +1.00: linux-1.2.13-:i386-:-:i486-:- (tnx RF) +0.96: linux-1.2.13-:i386-:-:pentium-:- (tnx MEE) +0.91: linux-1.3.90-:alpha-:-:alpha-:- (tnx ES) +0.93: linux-1.99.6-:i386-:-:pentium-:- (tnx TG) +0.94: linux-2.0.0-:i386-:-:i486-:- (tnx PCO) +1.00: linux-2.0.0-:i386-:-:pentium-:- (tnx JJR) +0.91: linux-2.0.1-:alpha-:-:alpha-:- (tnx BET) +0.90: linux-2.0.1-:i386-:-:i486-:- (tnx DF) +0.93: linux-2.0.1-:i386-:-:pentium-:- (tnx FW) +0.95: linux-2.0.6-:i386-:-:pentium-:- +1.00: linux-2.0.6-:i386-:-:ppro-:- (tnx MR) +0.96: linux-2.0.7-:i386-:-:i486-:- (tnx TLM) +0.90: linux-2.0.7-:i386-:-:pentium-:- (tnx K2J) +0.94: linux-2.0.8-:i386-:-:i486-:- (tnx EP) +0.90: linux-2.0.9-:i386-:-:pentium-:- (tnx JM) +0.90: linux-2.0.10-:i386-:-:i486-:- (tnx JL) +0.90: linux-2.0.10-:i386-:-:pentium-:- (tnx S2R) +0.90: linux-2.0.11-:i386-:-:i486-:- (tnx ET) +0.92: linux-2.0.12-:i386-:-:i486-:- (tnx TRR) +0.90: linux-2.0.12-:i386-:-:ppro-:- (tnx SS) +0.96: linux-2.0.13-:i386-:-:pentium-:- (tnx BW) +0.90: linux-2.0.14-:i386-:-:pentium-:- (tnx PS) +0.91: linux-2.0.15-:i386-:-:pentium-:- (tnx CL) +0.90: linux-2.0.16-:i386-:-:i486-:- (tnx AP) +0.91: linux-2.0.17-:i386-:-:i486-:- (tnx JL) +0.91: linux-2.0.17-:i386-:-:pentium-:- (tnx SS) +0.95: linux-2.0.18-:i386-:-:i386-:- (tnx RN) +1.00: linux-2.0.18-:i386-:-:i486-:- (tnx JMS) +1.00: linux-2.0.18-:i386-:-:pentium-:- (tnx D2S) +0.92: linux-2.0.19-:alpha-:-:alpha-:- (tnx BET) +0.92: linux-2.0.20-:i386-:-:pentium-:- (tnx RJH) +0.92: linux-2.0.21-:i386-:-:i486-:- (tnx DCC) +0.91: linux-2.0.21-:i386-:-:pentium-:- (tnx root@contact=???) +0.92: linux-2.0.22-:i386-:-:i486-:- (tnx root@attila=???) +1.00: linux-2.0.22-:i386-:-:pentium-:- (tnx MDI) +1.00: linux-2.0.23-:i386-:-:i486-:- (tnx B2L) +0.93: linux-2.0.23-:i386-:-:pentium-:- (tnx IW) +0.93: linux-2.0.24-:i386-:-:i486-:- (tnx root@cerberus=???) +1.00: linux-2.0.24-:i386-:-:pentium-:- (tnx VV) +0.96: linux-2.0.25-:i386-:-:i486-:- (tnx BDB) +1.00: linux-2.0.25-:i386-:-:pentium-:- (tnx AP) +0.93: linux-2.0.25-:i386-:-:ppro-:- (tnx CS) +0.93: linux-2.0.26-:i386-:-:i486-:- (tnx blynch=???) +0.96: linux-2.0.26-:i386-:-:pentium-:- (tnx ESM) +0.93: linux-2.0.26-:i386-:-:ppro-:- (tnx modus@enews=???) +1.00: linux-2.0.27-:-:-:sparc-:- (tnx SVD) +1.00: linux-2.0.27-:i386-:-:i486-:- (tnx FPL) +1.00: linux-2.0.27-:i386-:-:pentium-:- (tnx root@bullwinkle=???) +1.00: linux-2.0.27-:i386-:-:ppro-:- (tnx DE) +1.00: linux-2.0.28-:i386-:-:i486-:- (tnx H2S) +1.00: linux-2.0.28-:i386-:-:pentium-:- (tnx root@duggy=???) +1.00: linux-2.0.28-:i386-:-:ppro-:- (tnx KJS) +1.00: linux-2.0.29-:i386-:-:i486-:- (tnx PK) +1.00: linux-2.0.29-:i386-:-:pentium-:- (tnx CL) +1.00: linux-2.0.29-:i386-:-:ppro-:- (tnx MMM) +0.92: linux-2.1.1-:i386-:-:i486-:- (tnx nick@sga2=???) +0.92: linux-2.1.7-:i386-:-:ppro-:- (tnx JL) +0.92: linux-2.1.9-:i386-:-:pentium-:- (tnx AC) +0.92: linux-2.1.10-:i386-:-:ppro-:- (tnx S3T) +0.96: linux-2.1.13-:i386-:-:i486-:- (tnx ML) +0.93: linux-2.1.13-:i386-:-:ppro-:- (tnx JL) +0.96: linux-2.1.14-:i386-:-:pentium-:- (tnx SCW) +0.96: linux-2.1.23-:i386-:-:pentium-:- (tnx JF) +0.96: linux-2.1.25-:i386-:-:i486-:- (tnx JBF) +0.96: linux-2.1.25-:i386-:-:pentium-:- (tnx UO) +1.00: linux-2.1.26-:i386-:-:i486-:- (tnx DK) +1.00: linux-2.1.27-:i386-:-:pentium-:- (tnx JF) +1.00: linux-2.1.28-:i386-:-:pentium-:- (tnx RGS) +1.00: linux-2.1.29-:i386-:-:i486-:- (tnx SJW) +0.93: netbsd-1.2-:amiga-:-:amiga.4000.(m68040.cpu/mmu/fpu)-:- (tnx OS) +0.96: netbsd-1.2-:i386-:-:pentium.(genuineintel.586-class.cpu)-:- (tnx GH) +0.91: netbsd-1.2-:mac68k-:-:apple.macintosh.se/30..(68030)-:- (tnx hauke=???) +0.92: netbsd-1.2b-:i386-:-:-:- (tnx MG) +0.93: netbsd-1.2b-:i386-:-:pentium.(genuineintel.586-class.cpu)-:- (tnx MG) +0.96: netbsd-1.2c-:pmax-:-:-:- (tnx JLW) +0.92: nextstep-3.3-:hppa-:-:7100lc-:- +0.92: nextstep-3.3-:i386-:-:pentium-:- +0.91: openbsd-1.2-:openbsd.m68k-:-:mac68k-:- (tnx AKB) +0.95: openbsd-2.0-:openbsd.i386-:-:i386-:- (tnx JPH) +0.96: openbsd-2.0-:openbsd.m68k-:-:mac68k-:- (tnx AKB) +1.00: openbsd-2.0-hoth#0-:openbsd.i386-:-:i386-:- (tnx MBS) +1.00: openbsd-2.0-mr_potatoe_head#2-:openbsd.i386-:-:i386-:- (JJMK) +0.96: openbsd-2.0-puma#1-:openbsd.m68k-:-:mac68k-:- (tnx AB) +0.92: osf1-v3.0-347-:-:-:alpha-:- (tnx B2H) +0.92: osf1-v4.0-386-:-:-:alpha-:- (tnx WW) +0.96: sco_sv-3.2-2-:-:-:i386-:- (tnx DEH) +0.96: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4c-:sun4c- (tnx MBS) +0.91: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4m-:sun4m- (tnx IS) +0.92: sunos-4.1.3_u1-2-:sparc-:sun4-:sun4c-:sun4c- (tnx ANR) +0.93: sunos-4.1.3_u1-4-:sparc-:sun4-:sun4m-:sun4m- (tnx J2B) +1.00: sunos-4.1.3_u1-4-:unknown-:sun4-:sun4m-:sun4m- (tnx J2B) +0.91: sunos-4.1.3_u1-9-:sparc-:sun4-:sun4m-:sun4m- (tnx TA) +0.91: sunos-4.1.4-2-:sparc-:sun4-:sun4c-:sun4c- (tnx ST) +0.95: sunos-4.1.4-2-:sparc-:sun4-:sun4m-:sun4m- (tnx TG) +0.95: sunos-4.1c-4.1.3-:sparc-:sun4-:sun4-:s4000- (tnx DBK) +0.91: sunos-5.4-generic-:sparc-:sun4-:sun4m-:sun4m- +0.96: sunos-5.4-generic_101945-10-:sparc-:sun4-:sun4m-:sun4m- (tnx W2K) +0.93: sunos-5.4-generic_101945-23-:-:sun4-:sun4m-:sun4m- (tnx JP) +0.92: sunos-5.4-generic_101945-23-:sparc-:-:sun4c-:- (tnx BH) +1.00: sunos-5.4-generic_101945-34-:sparc-:sun4-:sun4m-:sun4m- (tnx ACB) +0.92: sunos-5.4-generic_101945-36-:-:sun4-:sun4c-:sun4c- (tnx JP) +0.95: sunos-5.4-generic_101945-43-:-:sun4-:sun4m-:sun4m- (tnx JP) +0.90: sunos-5.4-generic_101946-07-:-:i86pc-:i86pc-:i86pc- (tnx CR) +0.96: sunos-5.4-generic_101946-35-:i386-:i86pc-:i86pc-:i86pc- (tnx CK) +0.96: sunos-5.5-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx M2G) +0.93: sunos-5.5-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx CG) +1.00: sunos-5.5-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx SG) +1.00: sunos-5.5-generic_103093-02-:sparc-:sun4-:sun4m-:sun4m- (tnx RF) +0.91: sunos-5.5-generic_103093-03-:sparc-:sun4-:sun4d-:sun4d- (tnx M3S) +0.96: sunos-5.5-generic_103093-03-:sparc-:sun4-:sun4m-:sun4m- (tnx RDM) +0.91: sunos-5.5-generic_103093-03-:sparc-:sun4-:sun4u-:sun4u- (tnx olav=???) +0.92: sunos-5.5-generic_103093-05-:sparc-:sun4-:sun4m-:sun4m- (tnx KE) +0.93: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4d-:sun4d- (tnx KT) +1.00: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4m-:sun4m- (tnx TEE) +0.94: sunos-5.5-generic_103094-01-:i386-:i86pc-:i86pc-:i86pc- (tnx MD) +0.91: sunos-5.5-generic_103094-03-:i386-:i86pc-:i86pc-:i86pc- (tnx ding=???) +1.00: sunos-5.5.1-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx DML) +1.00: sunos-5.5.1-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx JMT) +1.00: sunos-5.5.1-generic-:sparc-:sun4-:sun4u-:sun4u- (tnx TH) +0.96: sunos-5.5.1-generic_103640-02-:sparc-:sun4-:sun4m-:sun4m- (tnx SGC) +0.95: sunos-5.5.1-generic_103640-03-:sparc-:sun4-:sun4m-:sun4m- (tnx MRG) +1.00: sunos-5.5.1-generic_103640-03-:sparc-:sun4-:sun4u-:sun4u- (tnx EG) +1.00: sunos-5.5.1-generic_103640-05-:sparc-:sun4-:sun4m-:sun4m- (tnx L2L) +0.96: sunos-5.5.1-generic_patch-:i386-:i86pc-:i86pc-:i86pc- (tnx DK) +0.96: ultrix-4.3-1-:pmax-:-:risc-:- (tnx YF) diff --git a/RFCHCSC b/RFCHCSC @@ -0,0 +1,37 @@ +The Hash Convention For Mail System Status Codes (HCMSSC) +D. J. Bernstein, djb@pobox.com +19970201 + + +1. Introduction + + RFC 1893 defines codes for mail delivery failures. For example, + code 5.1.1 means that the specified mailbox does not exist. + + The qmail package sprays these codes all over the place, by adding a + code to the text of every error message, preceded by a hash mark and + surrounded by parentheses. It avoids using hash marks elsewhere. + + +2. Examples + + Here is a typical HCMSSC SMTP error message: + + 421 load average too high, please come back later (#4.3.2) + + Here is part of a typical HCMSSC bounce message: + + <mail-loop@silverton.berkeley.edu>: + This is looping; it already has my Delivered-To line. (#5.7.1) + + But qmail doesn't use HCMSSC when it repeats another MTA's error + message: + + <foo@heaven.af.mil>: + 127.3.4.5 does not like recipient. + Remote host said: 550 <foo>... User unknown (#5.1.1) + + +3. Security considerations + + Don't take drastic action upon seeing "(#"; it might not be HCMSSC. diff --git a/RFCLOOPS b/RFCLOOPS @@ -0,0 +1,338 @@ +Tools in the war on mail loops +D. J. Bernstein, djb@pobox.com +19970201 + + +1. Introduction + + An automailer means any program that receives a mail message and + automatically sends one or more mail messages. This term is meant to + include not only a mail-based server, such as a mailing list exploder + or a vacation program, but also an SMTP server, which receives a + message from the network and relays it to a local or remote user. + + In a network full of automailers, any mistake can cause a mail loop. + Since some automailers generate several outputs in response to a + single input, a loop can produce an exponential explosion of mail. + + All the automailers in the qmail package follow a general philosophy + designed to prevent mail loops and limit the damage from any loops + that do occur. These automailers have been repeatedly observed to + fail safe: they stop loops in the face of typical failures by other + hosts. This document explains the philosophy and describes the + automailers. + + To some extent the philosophy here simply repeats and amplifies + standard practice as codified in RFC 974 and RFC 1123. Unfortunately, + the standards do not adequately control bounce loops, since they do + not recognize that postmasters want to see double bounces; they do + not adequately control relaying loops; and they do not prevent + cross-host forwarding loops. + + Terminology: The mail message received by an automailer is called + input. The mail messages sent by an automailer are called outputs. + For simplicity, this document focuses on the case that the input has + just one envelope recipient. + + REMINDER: This document describes the automailers in the qmail + package. Other packages include automailers that do not fit the + descriptions given here. + + Beware that the war on mail loops can never be won: any method of + preventing mail loops can be subverted by other hosts. I welcome + further development of techniques that work well in practice. + + +2. Basics + + The output from an automailer is always further down the following + list than the input. + + 0 hops, <sender> is neither <> nor <#@[]> normal messages + 1 hop, <sender> is neither <> nor <#@[]> + 2 hops, <sender> is neither <> nor <#@[]> + etc. + 0 hops, <sender> is <> bounces + 1 hop, <sender> is <> + 2 hops, <sender> is <> + etc. + 0 hops, <sender> is <#@[]> double bounces + 1 hop, <sender> is <#@[]> + 2 hops, <sender> is <#@[]> + etc. + + Here sender means the envelope sender address. Hops means the number + of Received and Delivered-To fields in the header. See sections 3.3 + and 3.4 for an explanation of <> and <#@[]>. + + Consequently, no automailer ever generates an entirely new normal + message in response to a normal message. If the output is a normal + message, it always has more hops than the input. + + When input and output are both normal messages, both bounces, or both + double bounces, the output header is essentially the same as the + input header. However, when an automailer moves from a normal message + to a bounce, or from a bounce to a double bounce, it generates an + entirely new header. + + An automailer may refuse to operate if the input has too many hops. + The definition of too many hops depends on the automailer. This + practice is called hop counting. Note that some existing messages + legitimately take as many as 20 hops. One automailer uses a limit of + 100 hops; this will be adequate for all messages in the foreseeable + future. + + Hop counting is a weapon of last resort. It will, if correctly + implemented, prevent all infinite loops; however, even a finite loop + can do practically infinite damage, as illustrated in section 4.3. + + +3. Pre-delivery automailers + + Conceptually: The input is a message that has not yet reached its + envelope recipient address. It is fed to a relay, which attempts to + deliver the message directly to, or at least closer to, that address; + if the relay fails permanently, the message is fed to a bouncer or a + double-bouncer. Relays, bouncers, and double-bouncers are examples of + pre-delivery automailers. + + A pre-delivery automailer produces at most one output. + + The basic weapon against pre-delivery mail loops is gravity. A normal + message always moves closer to its envelope recipient, according to a + notion of distance defined in section 3.1. If it bounces before + reaching the recipient, it turns into a bounce message, which always + moves closer to the original envelope sender. If that in turn + bounces, it turns into a double bounce, which always moves closer to + a local postmaster. (Triple bounces do not exist.) + + +3.1. Distance + + The distance from a DNS domain D to a recipient U@R is defined as + follows, when R has an MX list: the minimum preference of D in the + MX list, or 100000 if D does not appear in the list. + + When R has no MX records, the distance from R to U@R is defined as 0, + and the distance from any other domain to U@R is defined as 100000. + + Exception: If R is an alias, i.e., if R has a CNAME record, the + distance from any domain to U@R is defined as 500000. + + The distance from a host H to U@R is defined as the minimum distance + to U@R from any domain that touches H. (``D touches H'' means ``D has + an A record listing one of H's IP addresses.'') + + Exception: If H does not accept mail from the network, its distance + to any recipient is defined as 999999. + + +3.2. Relays + + A relay is a pre-delivery automailer that sends the output towards + the envelope recipient. What this means for intra-host relays is not + discussed here. What this means for cross-host relays is the + following: if the relay is at host H, and it sends its output to host + T, then the distance from T to the output envelope recipient is + always smaller than the distance from H to the input envelope + recipient. + + The following facts guarantee that certain cross-host relay behavior + is safe. For proofs of these facts, see Appendix A. + + Fact 1: If R is an alias for X, X is not an alias, D touches T, + and T accepts mail from the network, then the distance from T to + U@X is smaller than the distance from H to U@R. + + Fact 2: If R is not an alias, R has no MX records, H is not + touched by R, T is touched by R, and T accepts mail from the + network, then T is closer to U@R than H is. + + Fact 3: If R is not an alias, R has an MX record with domain X and + preference p, H is not touched by any of the domains in the MX + list for R with preference <= p, T is touched by X, and T accepts + mail from the network, then T is closer to U@R than H is. + + Also, a host that does not accept mail from the network can relay + messages to a nearby hub. + + A relay adds a new Received header field to the top of the output. + Other than this, the output header, body, and envelope are exactly + the same as the input header, body, and envelope. Exception: If the + input envelope recipient is U@R, R is an alias for X, and X is not + an alias, the output envelope recipient is U@X. + + +3.3. Bouncers + + A bouncer is a pre-delivery automailer that lets the envelope sender + know what happened to a message. Most bouncers send failure notices. + Some bouncers, such as vacation servers and echo servers, send + success notices. + + In a bouncer's output, the envelope sender is <>, and the envelope + recipient is the input envelope sender. A bouncer refuses to operate + if the input envelope sender is <> or <#@[]>. + + Some mailers on the Internet do not understand the <> convention. In + fact, some mailers will rewrite <> as <@host>. So any message with an + envelope recipient of <> or <@host> is discarded upon local delivery. + + Unlike a relay, a bouncer produces output with a new header, not + simply a copy of the input header. For example: + + (envelope) from <> to <djb@silverton.berkeley.edu> + Date: 2 Jan 1996 03:38:25 GMT + From: DELIVERY NOTICE SYSTEM <MAILER-DAEMON@heaven.af.mil> + To: djb@silverton.berkeley.edu + Subject: failure notice + + However, the body of the bounce indicates the relevant input envelope + recipient, as well as the Message-ID of the input, if the input had a + Message-ID. The body of a failure notice includes a copy of the + entire input message. + + +3.4. Double-bouncers + + A double-bouncer is a pre-delivery automailer that informs a local + postmaster of permanent failures to deliver bounce messages. Such + failures are generally caused by poorly configured hosts that produce + normal messages with faulty envelope sender addresses. + + A double-bouncer refuses to operate unless the input envelope sender + is <>. The output envelope sender from a double-bouncer is <#@[]>; + note that <#@[]> cannot be used as an SMTP envelope sender under + RFC 821. The output envelope recipient is predetermined. + + Note that double bounces are not suggested by RFC 1123. However, + faulty envelope sender addresses are usually configuration errors + that can and should be fixed. Some postmasters, faced with mail + software that throws away double bounces, resort to keeping copies of + all bounces; but single bounces are rarely the postmaster's problem. + + +4. Post-delivery automailers + + Conceptually: The input is a message that has reached its envelope + recipient address. It is fed to a post-delivery automailer at that + address. + + The basic weapon against post-delivery loops is a new header field, + Delivered-To, tracing all the forwarders and mailing lists that a + message has been through. This field has the side benefit of making + it much easier for a user (or for a postmaster seeing a bounce) to + figure out the path that the message took. Delivered-To is similar to + RFC 1327's DL-Expansion-History, but (1) it omits the time stamp, + removing any need for parsing, and (2) it has a much better name. + + +4.1. Exploders and repliers + + There are two basic types of post-delivery automailers: exploders, + where the output envelope recipients are predetermined; and repliers, + where there is just one output, with envelope recipient determined + from the input. + + Repliers normally determine the output envelope recipient as either + the input Reply-To header field, if it exists; or else the input + From header field, if it exists; or else the envelope sender. A + replier never produces an output to <> or <#@[]>. + + Exploders are classified into mailing lists, where the output + envelope senders are predetermined, and forwarders, where every + output has envelope sender equal to the original envelope sender. + + Exception: if the input envelope sender is <> or <#@[]>, then the + output envelope senders are equal to the input envelope sender, even + for a mailing list. + + Note that, if the envelope sender of a mailing list with M bad + addresses is another exploder with E bad addresses, the local + postmaster will receive EM double bounces for each message to the + mailing list. + + +4.2. Delivered-To + + Every post-delivery automailer adds a new Delivered-To header field + to the top of each output. + + The contents of the Delivered-To field are typically the address of + the automailer, i.e., the input envelope recipient, conventionally + without any quoting. The contents of the Delivered-To field are in + any case entirely predetermined. The automailer checks if exactly the + same Delivered-To field already appears in the header; if so, it + refuses to operate. + + A post-delivery automailer preserves existing Delivered-To and + Received fields. In fact, a post-delivery automailer generally + preserves all header fields. The exceptions are limited to known + fields that are not used for loop detection and that must be removed + for correct operation. For example, a replier generally changes the + body of a message and thus should not preserve the SVR4 + Content-Length field. + + +4.3. An example + + Aliases and mailing lists are highly dangerous, because they can + generate several outputs for each input. + + Here is an extreme example. A user has three accounts, and wants any + message to any of the accounts to be delivered to all three. So he + forwards luser@host1 to luser@host2 and luser@host3, forwards + luser@host2 to luser@host1 and luser@host3, and forwards luser@host3 + to luser@host1 and luser@host2. + + Without Delivered-To, someone who sends a message to luser@host1 will + receive a practically infinite series of bounces. For example, with a + hop count limit of 50, the sender will receive 1125899906842624 + bounces. + + If all the hosts, or two out of the three, support Delivered-To, the + message will bounce just a few times. If just one of the hosts + supports Delivered-To, it will be the unfortunate victim of a loop + between the other two hosts---although the total number of bounces + will drop from practically infinite down to a few hundred, with + typical hop count limits. + + +Appendix A. Proofs of correctness for MX handling + + Section 3.2 states three facts about the notion of distance defined + in section 3.1. Here are mathematical proofs of those facts. + + Symbols: D, E, R, and X are domains; H and T are hosts; p and q are + nonnegative integers. {} is the empty set. + + Hypotheses: M(R), the ``MX list for R,'' is a set of pairs (p,D) + where p <= 65535. There is a set A of domains, called ``aliases.'' + There is a relation D->H, called ``D touches H.'' There is a set N of + hosts, called ``hosts that accept mail from the network.'' + + Definitions: m(D,R) = min { p: p = 100000 or (p,D) in M(R) } when + M(R) is nonempty. When M(R) is empty, m(D,R) is 0 if D = R, 100000 + otherwise. f(D,R) is defined as 500000 if R is in A, m(D,R) + otherwise; this is the ``distance from D to U@R,'' for any U. g(H,R) + is defined as min { f(D,R): D->H } if H is in N, 999999 otherwise; + this is the ``distance from H to U@R,'' for any U. + + Fact 1 (generalized): If R is in A, X is not in A, D->T, and T is in + N, then g(T,X) < g(H,R). Proof: R is in A, so f(E,R) = 500000 for any + E; thus g(H,R) >= 500000. X is not in A, so f(D,X) = m(D,X) <= + 100000; hence g(T,X) <= f(D,X) <= 100000 < g(H,R). + + Fact 2: If R is not in A, M(R) = {}, R->T, T is in N, and not R->H, + then g(T,R) < g(H,R). Proof: f(R,R) = m(R,R) = 0 since R is not in A + and M(R) = {}. T is in N so g(T,R) <= f(R,R) = 0 so g(T,R) = 0. + Suppose that g(H,R) <= g(T,R). Then g(H,R) = 0, so f(D,R) = 0 for + some D with D->H, so m(D,R) = 0. But then D = R by definition of m, + so R->H. Contradiction. Thus g(T,R) < g(H,R). + + Fact 3: If R is not in A, (p,X) is in M(R), X->T, T is in N, and + (q,D) is not in M(R) whenever D->H and q <= p, then g(T,R) < g(H,R). + Proof: First m(X,R) <= p. R is not in A, so f(X,R) = m(X,R). T is in + N, so g(T,R) <= f(X,R). Thus g(T,R) <= p. Suppose that g(H,R) <= p. + Then f(D,R) <= p for some D with D->H, so m(D,R) <= p. But then + (m(D,R),D) is in M(R). Contradiction. Thus g(T,R) <= p < g(H,R). diff --git a/RFCMXPS b/RFCMXPS @@ -0,0 +1,122 @@ +The Mail Exchanger Protocol Switch (MXPS) +D. J. Bernstein, djb@pobox.com +19970201 + + +1. Introduction + + Mail messages today are transferred through the Simple Mail Transfer + Protocol (SMTP). One can imagine other protocols that achieve the + same results as SMTP but that, for example, use the network more + efficiently. + + The Mail Exchanger Protocol Switch (MXPS) lets other protocols + compete with SMTP. A receiver can announce its support for another + protocol while operating properly with MXPS-ignorant senders. A + sender can check for support, with no overhead, while operating + properly with MXPS-ignorant receivers. + + All receivers must support SMTP, i.e., must be able to receive + messages via SMTP. Similarly, all senders must be able to send + messages via SMTP. + + +2. The protocol switch + + MXPS abuses the preference field of MX records. A protocol is + assigned to each possible preference. + + SMTP is assigned to preferences 0 through 10000. + + The initial MXPS experiment will involve preferences between 12800 + and 13055 inclusive. These preferences are sliced into 16 portions: + + 12800, 12816, 12832, 12848, 12864, ..., 13040: slice #0 (SMTP) + 12801, 12817, 12833, 12849, 12865, ..., 13041: slice #1 (QMTP) + 12802, 12818, 12834, 12850, 12866, ..., 13042: slice #2 + ... + 12815, 12831, 12847, 12863, 12879, ..., 13055: slice #15 + + Preferences in slice #0 are assigned SMTP. Preferences in slice #1 + are assigned the Quick Mail Transfer Protocol (QMTP). Preferences in + the remaining slices may be assigned protocols in the future. + + A receiver must support the protocol assigned to its preference. More + precisely, if an MX record points to domain D, and the MX preference + is assigned protocol P, then every host listed as an A record for D + must support protocol P. + + When a sender, following the procedure outlined in RFC 974 (and + modified by RFC 1123), attempts to deliver a mail message as + specified by that MX record, it may use protocol P instead of SMTP. + If it does not support protocol P, it may treat the attempt as a + temporary failure and go on to the next MX record. However, the + sender must not skip every MX record. + + MX records must never use unassigned preferences. A sender may treat + an unassigned preference as referring to SMTP. + + Example: + + A.EXAMPLE.ORG IN MX 12801 A.EXAMPLE.ORG + B.EXAMPLE.ORG IN MX 12801 A.EXAMPLE.ORG + IN MX 12816 C.EXAMPLE.ORG + + A sender with a message for A.EXAMPLE.ORG will try A.EXAMPLE.ORG by + QMTP. If it does not support QMTP, it will try SMTP instead. Note + that A.EXAMPLE.ORG must support both QMTP and SMTP. + + A sender with a message for B.EXAMPLE.ORG will try A.EXAMPLE.ORG by + QMTP, then C.EXAMPLE.ORG by SMTP. If it does not support QMTP, it may + try SMTP instead of QMTP, or it may skip A.EXAMPLE.ORG. + + Some of the above requirements might be violated if current + MXPS-ignorant domains use any preferences above 10000. Mail could be + unnecessarily rejected if any existing MXPS-ignorant domains have a + best-preference MX above 10000. I do not know any examples of such + domains. + + +3. Protocol requirements + + MXPS operates purely at the link level. It does not change the + fundamental nature of Internet mail. + + The function of a mail transfer protocol is to transmit a message, as + described below, together with an envelope sender address and one or + more envelope recipient addresses. + + A recipient address is a sequence of characters---i.e., nonnegative + integers---including an ASCII @ (64). It is parsed as box@dom, where + dom does not contain an @. The interpretation of box is up to the + hosts listed as MX records for dom. A sender address may contain an + @, in which case it is also of the form box@dom; or it may be a + special address, such as the empty string. + + A mail message is structured as a sequence of lines. A line is a + sequence of characters. Every mail transfer protocol must be able to + transmit all sufficiently short boring mail messages. A boring mail + message is one where (1) no line has more than 80 characters and (2) + each character is either 9 or between 32 and 127 inclusive. Note that + RFC 1341 defines a mechanism for encoding a message with characters + between 0 and 255 inclusive as a boring mail message of similar + length. + + The receiver must indicate, for each recipient address, either + acceptance, permanent rejection, or temporary rejection of the + message. Acceptance means that the receiver has taken responsibility, + in the sense of RFC 1123, section 5.3.3, for delivering the message + to that recipient. Rejection means that the receiver will not deliver + the message to that recipient. + + Mail transfer protocols may vary in many details, such as line + encodings, the means of expressing acceptance or rejection, the + maximum number of allowable recipients per envelope, the encoding of + envelope addresses, the nature of optional protocol extensions, etc. + + +4. Security considerations + + MXPS does not change the following facts: An attacker who can subvert + the Domain Name System can steal or forge mail. An attacker who can + subvert TCP/IP can also steal or forge mail. diff --git a/RFCNETSTR b/RFCNETSTR @@ -0,0 +1,88 @@ +Netstrings +D. J. Bernstein, djb@pobox.com +19970201 + + +1. Introduction + + A netstring is a self-delimiting encoding of a string. Netstrings are + very easy to generate and to parse. Any string may be encoded as a + netstring; there are no restrictions on length or on allowed bytes. + Another virtue of a netstring is that it declares the string size up + front. Thus an application can check in advance whether it has enough + space to store the entire string. + + Netstrings may be used as a basic building block for reliable network + protocols. Most high-level protocols, in effect, transmit a sequence + of strings; those strings may be encoded as netstrings and then + concatenated into a sequence of characters, which in turn may be + transmitted over a reliable stream protocol such as TCP. + + Note that netstrings can be used recursively. The result of encoding + a sequence of strings is a single string. A series of those encoded + strings may in turn be encoded into a single string. And so on. + + In this document, a string of 8-bit bytes may be written in two + different forms: as a series of hexadecimal numbers between angle + brackets, or as a sequence of ASCII characters between double quotes. + For example, <68 65 6c 6c 6f 20 77 6f 72 6c 64 21> is a string of + length 12; it is the same as the string "hello world!". + + Although this document restricts attention to strings of 8-bit bytes, + netstrings could be used with any 6-bit-or-larger character set. + + +2. Definition + + Any string of 8-bit bytes may be encoded as [len]":"[string]",". + Here [string] is the string and [len] is a nonempty sequence of ASCII + digits giving the length of [string] in decimal. The ASCII digits are + <30> for 0, <31> for 1, and so on up through <39> for 9. Extra zeros + at the front of [len] are prohibited: [len] begins with <30> exactly + when [string] is empty. + + For example, the string "hello world!" is encoded as <31 32 3a 68 + 65 6c 6c 6f 20 77 6f 72 6c 64 21 2c>, i.e., "12:hello world!,". The + empty string is encoded as "0:,". + + [len]":"[string]"," is called a netstring. [string] is called the + interpretation of the netstring. + + +3. Sample code + + The following C code starts with a buffer buf of length len and + prints it as a netstring. + + if (printf("%lu:",len) < 0) barf(); + if (fwrite(buf,1,len,stdout) < len) barf(); + if (putchar(',') < 0) barf(); + + The following C code reads a netstring and decodes it into a + dynamically allocated buffer buf of length len. + + if (scanf("%9lu",&len) < 1) barf(); /* >999999999 bytes is bad */ + if (getchar() != ':') barf(); + buf = malloc(len + 1); /* malloc(0) is not portable */ + if (!buf) barf(); + if (fread(buf,1,len,stdin) < len) barf(); + if (getchar() != ',') barf(); + + Both of these code fragments assume that the local character set is + ASCII, and that the relevant stdio streams are in binary mode. + + +4. Security considerations + + The famous Finger security hole may be blamed on Finger's use of the + CRLF encoding. In that encoding, each string is simply terminated by + CRLF. This encoding has several problems. Most importantly, it does + not declare the string size in advance. This means that a correct + CRLF parser must be prepared to ask for more and more memory as it is + reading the string. In the case of Finger, a lazy implementor found + this to be too much trouble; instead he simply declared a fixed-size + buffer and used C's gets() function. The rest is history. + + In contrast, as the above sample code shows, it is very easy to + handle netstrings without risking buffer overflow. Thus widespread + use of netstrings may improve network security. diff --git a/RFCNRUDT b/RFCNRUDT @@ -0,0 +1,89 @@ +Notice-Requested-Upon-Delivery-To (NRUDT) +D. J. Bernstein, djb@pobox.com +19970201 + + +1. Introduction + + The UNIX sendmail program has for many years supported a + Return-Receipt-To (RRT) header field that requests a notice of + successful final delivery. + + Notice-Requested-Upon-Delivery-To (NRUDT) has the same basic + function. The big difference is that RRT lists the sender's address, + while NRUDT lists the recipient's address. + + This change is critical. RRT works poorly for messages to multiple + recipients, because it requests a notice from every recipient. RRT in + a message to a large mailing list produces a giant, usually + unintentional, flood of mail. This problem is so severe that RRT has + been disabled in recent versions of sendmail. + + NRUDT is designed to be adopted immediately, with minimal disruption, + as a solution to the problems of RRT. Note that NRUDT is merely a + request for notification; unlike the link-level Delivery Status + Notification SMTP extension, NRUDT does not provide a guarantee of + notification. + + NRUDT is supported by the qreceipt program in the qmail package. + + +2. Syntax + + NRUDT is a field in the header of an RFC 822 mail message. It has the + following syntax: + + "Notice-Requested-Upon-Delivery-To" ":" 1#address + + See RFC 822 for more information about header fields and addresses. + + NRUDT requests that, upon final delivery of the message to any of the + specified addresses, the sender be notified. Note that more than one + address can appear in a single NRUDT header field. Multiple NRUDT + header fields should not appear in a single message. + + +3. Response + + Upon successful final delivery of a message to any address listed in + an NRUDT header field, the host performing delivery may, if desired, + generate a success notice. + + The success notice is similar to a failure notice as described in RFC + 1123. Its envelope sender is <>. Its envelope recipient is the + envelope sender of the original message; however, if the envelope + sender of the original message is <>, a success notice is not sent. + + The body of the success notice does not contain a copy of the + original message, but it does indicate the Message-ID of the original + message, as well as the relevant recipient address. + + A success notice may indicate delivery to several addresses. For + example, given the following message: + + (envelope) from djb@silverton.berkeley.edu + (envelope) to god@heaven.af.mil, angels@heaven.af.mil + Date: 1 Jan 1996 21:43:34 GMT + From: "D. J. Bernstein" <djb@silverton.berkeley.edu> + Message-Id: <19960101214334.8529.qmail@silverton.berkeley.edu> + Notice-Requested-Upon-Delivery-To: God <god@heaven.af.mil>, + angels@heaven.af.mil (You Know Who You Are) + ... + + a host may respond as follows: + + (envelope) from <> to djb@silverton.berkeley.edu + Date: 1 Jan 1996 21:43:37 GMT + From: DELIVERY NOTICE SYSTEM <MAILER-DAEMON@heaven.af.mil> + To: djb@silverton.berkeley.edu + Subject: success notice + + I delivered <19960101214334.8529.qmail@silverton.berkeley.edu> + to the following local mailboxes: + + god@heaven.af.mil + angels@heaven.af.mil + + Thanks for asking. + + However, a success notice is never merged with a failure notice. diff --git a/RFCQMTP b/RFCQMTP @@ -0,0 +1,229 @@ +Quick Mail Transfer Protocol (QMTP) +D. J. Bernstein, djb@pobox.com +19970201 + + +1. Introduction + + The Quick Mail Transfer Protocol (QMTP) is a replacement for the + Simple Mail Transfer Protocol (SMTP). QMTP eliminates any need for + end-of-line scanning between hosts with the same end-of-line + convention. It features automatic pipelining and chunking, 8-bit + transmission, prior declaration of the message size, and efficient + batching. It is designed to be very easy to implement. + + QMTP is supported by the qmail-qmtpd and maildir2qmtp programs in the + qmail package. + + In this document, a string of 8-bit bytes may be written in two + different forms: as a series of hexadecimal numbers between angle + brackets, or as a sequence of ASCII characters between double quotes. + For example, <68 65 6c 6c 6f 20 77 6f 72 6c 64 21> is a string of + length 12; it is the same as the string "hello world!". Note that + these notations are part of this document, not part of the protocol. + + +2. Protocol + + A QMTP client connects to a QMTP server, as discussed in section 7, + over a reliable stream protocol allowing transmission of 8-bit bytes. + + Protocol outline: the client sends one or more packages; after each + package, the server sends back some responses. + + The client begins by sending a package. A package contains a mail + message, an envelope sender address, and one or more envelope + recipient addresses. See section 4 for the format of a package. + + When the server sees the end of the package, it sends back a series + of responses, one response for each envelope recipient address, in + the same order as given by the client. The server is not permitted to + change the order under any circumstances, even if two addresses are + the same. See section 5 for the format of a response. + + The server is not permitted to send any portion of its responses to a + package until the client has sent the final byte of the package. The + client is permitted to close the connection before sending the final + byte of the package; in this case, the server must throw away the + package without attempting to deliver the message. However, the + server must not throw away previously accepted messages. + + The client does NOT need to wait for a server response before sending + another package. The server must NOT throw away incoming data when it + sends a response. It is the client's responsibility to avoid + deadlock: if it sends a package before receiving all expected server + responses, it must continuously watch for those responses. The server + is permitted to delay its responses if further data has already shown + up from the client; while it is delaying responses, it must not pause + to wait for further data for the client. + + The server is permitted to close the connection at any time, although + high-quality servers will try to avoid doing so. Any response not + received by the client indicates a temporary failure. + + A QMTP session should take at most 1 hour. Both sides are expected + to close the connection after this time. + + +3. Messages + + In this document, an ``8-bit mail message'' means a sequence of + lines. Each line is a string of zero or more 8-bit bytes. + + A message is called ``safe'' if none of its bytes are <0a>. + + Implementation note: Here is the intended interpretation of text + files as messages under some current operating systems. Under DOS, a + message is stored on disk as + + first line, <0d 0a>, second line, <0d 0a> ... <0d 0a>, last line. + + Under UNIX, a message is stored on disk as + + first line, <0a>, second line, <0a> ... <0a>, last line. + + Notice that both of these encodings are reversible for safe messages. + + In practice, it is very common for the last line to be empty. Many + existing utilities refer to the last line as a ``partial line'' and + ignore it whether or not it is empty. + + +4. Packages + + A package is the concatenation of three strings: + + first, an encoded 8-bit mail message; + second, an encoded envelope sender address; + third, an encoded series of encoded envelope recipient addresses. + + Each envelope address is a string of 8-bit bytes. The interpretation + of addresses depends on the environment in which QMTP is used and is + outside the scope of this document. Each address is encoded as a + netstring, as discussed in section 6. The series of encoded recipient + addresses is in turn encoded as a netstring. + + A message is encoded as a string of 8-bit bytes in one of two ways: + + Encoding #1 is <0d>, the first line, <0d 0a>, the second line, + <0d 0a>, the third line, ..., <0d 0a>, the last line. + + Encoding #2 is <0a>, the first line, <0a>, the second line, <0a>, + the third line, ..., <0a>, the last line. + + This string of 8-bit bytes is in turn encoded as a netstring, as + discussed in section 6. + + Every server must be prepared to handle encoding #1 and encoding #2. + A server must not reject a message merely because of its encoding. + + Implementation note: The intent of encoding #1 and encoding #2 is to + allow very straightforward handling of text files under DOS and UNIX + respectively. The programmer can print <0d> or <0a> and then simply + copy the file. + + +5. Responses + + Each response is a nonempty string of 8-bit bytes, encoded as a + netstring. The first byte of the string is one of the following: + + "K" The message has been accepted for delivery to this envelope + recipient. This is morally equivalent to the 250 response to + DATA in SMTP; it is subject to the reliability requirements + of RFC 1123, section 5.3.3. + + "Z" Temporary failure. The client should try again later. + + "D" Permanent failure. + + The remaining bytes are a description of what happened. It is + expected that the description, when interpreted as UTF-2 characters, + (1) will be human-readable, (2) will not repeat the envelope + recipient address, and (3) will not include formatting characters + other than <20>. However, these expectations are not requirements, + and the client should be ready for arbitrary bytes from the server. + + Descriptions beginning with <20> are reserved for future extensions. + In descriptions not beginning with <20>, the character "#" must not + appear except in HCMSSC codes. + + A server must NOT accept a safe message unless it can store the + message without corruption. More precisely: if the encoded message + sent by the client matches the encoding of some safe message M, then + acceptance means that the server is accepting responsibility to + deliver M to the envelope recipient. (There is at most one + possibility for M, since encodings are reversible on safe messages.) + Deletion of nulls is NOT permissible; a server that deletes nulls + must reject any message containing nulls. Folding of long lines and + high-bit stripping are also NOT permissible. + + Servers are permitted to change unsafe messages. + + +6. Netstrings + + Any string of 8-bit bytes may be encoded as [len]":"[string]",". + Here [string] is the string and [len] is a nonempty sequence of ASCII + digits giving the length of [string] in decimal. The ASCII digits are + <30> for 0, <31> for 1, and so on up through <39> for 9. Extra zeros + at the front of [len] are prohibited: [len] begins with <30> exactly + when [string] is empty. + + For example, the string "hello world!" is encoded as <31 32 3a 68 + 65 6c 6c 6f 20 77 6f 72 6c 64 21 2c>, i.e., "12:hello world!,". The + empty string is encoded as "0:,". + + [len]":"[string]"," is called a netstring. [string] is called the + interpretation of the netstring. + + +7. Encapsulation + + QMTP may be used on top of TCP. A QMTP-over-TCP server listens for + TCP connections on port 209. + + +8. Examples + + A client opens a connection and sends the concatenation of the + following strings: + + "246:" <0a> + "Received: (qmail-queue invoked by uid 0);" + " 29 Jul 1996 09:36:40 -0000" <0a> + "Date: 29 Jul 1996 11:35:35 -0000" <0a> + "Message-ID: <19960729113535.375.qmail@heaven.af.mil>" <0a> + "From: God@heaven.af.mil" <0a> + "To: djb@silverton.berkeley.edu (D. J. Bernstein)" <0a> + <0a> + "This is a test." <0a> "," + "24:" "God-DSN-37@heaven.af.mil" "," + "30:" "26:djb@silverton.berkeley.edu," "," + + "356:" <0d> + "From: MAILER-DAEMON@heaven.af.mil" <0d 0a> + "To:" <0d 0a> + " Hate." <22> "The Quoting" <22> + "@SILVERTON.berkeley.edu," <0d 0a> + " " <22> "\\Backslashes!" <22> + "@silverton.BERKELEY.edu" <0d 0a> + <0d 0a> + "The recipient addresses here could" + " have been encoded in SMTP as" <0d 0a> + "" <0d 0a> + " RCPT TO:<Hate.The\ Quoting@silverton.berkeley.EDU>" <0d 0a> + " RCPT TO:<\\Backslashes!@silverton.berkeley.edu>" <0d 0a> + <0d 0a> + "This ends with a partial last line, right here" "," + "0:" "," + "83:" "39:Hate.The Quoting@silverton.berkeley.edu," + "36:\Backslashes!@silverton.berkeley.EDU," "," + + The server sends the following response, indicating acceptance: + + "21:Kok 838640135 qp 1390," + "21:Kok 838640135 qp 1391," + "21:Kok 838640135 qp 1391," + + The client closes the connection. diff --git a/RFCQSBMF b/RFCQSBMF @@ -0,0 +1,155 @@ +The qmail-send Bounce Message Format (QSBMF) +D. J. Bernstein, djb@pobox.com +19970201 + + +1. Introduction + + When a message transport agent (MTA) finds itself permanently unable + to deliver a mail message, it generates a new message, generally + known as a bounce message, back to the envelope sender. + + Bounce messages produced by the qmail-send program display the list + of failed recipient addresses, an explanation for each address, and a + copy of the original message, in a format that is easy for both + humans and programs to read. For example: + + Date: 17 Mar 1996 03:54:40 -0000 + From: MAILER-DAEMON@silverton.berkeley.edu + To: djb@silverton.berkeley.edu + Subject: failure notice + + Hi. This is the qmail-send program at silverton.berkeley.edu. + I'm afraid I wasn't able to deliver your message to the + following addresses. This is a permanent error; I've given up. + Sorry it didn't work out. + + <god@heaven.af.mil>: + Sorry, I couldn't find any host by that name. + + --- Below this line is a copy of the message. + + Return-Path: <djb@silverton.berkeley.edu> + Received: (qmail 317 invoked by uid 7); 17 Mar 1996 03:54:38 -0000 + Date: 17 Mar 1996 03:54:38 -0000 + Message-ID: <19960317035438.316.qmail@silverton.berkeley.edu> + From: djb@silverton.berkeley.edu (D. J. Bernstein) + To: god@heaven.af.mil + Subject: are you there? + + Just checking. + + This document defines qmail-send's format for bounce messages. + + In this document, a string of 8-bit bytes may be written in two + different forms: as a series of hexadecimal numbers between angle + brackets, or as a sequence of ASCII characters between double quotes. + For example, <68 65 6c 6c 6f 20 77 6f 72 6c 64 21> is a string of + length 12; it is the same as the string "hello world!". + + +2. Format + + A bounce message may be recognized as QSBMF as follows: its body + begins with the characters "Hi. This is the" exactly as shown. + + The body of the message has four pieces: an introductory paragraph, + zero or more recipient paragraphs, a break paragraph, and the + original message. + + Each paragraph is a series of non-blank lines followed by a single + blank line. The break paragraph begins with the character "-". All + other paragraphs begin with characters other than "-". The break + paragraph is human-readable but provides no interesting information. + + The introductory paragraph is human-readable. It gives the name and + human-comprehensible location of the MTA, but parsers should not + attempt to use this information. + + The only type of recipient paragraph described here is a failure + paragraph, which begins with the character "<". Paragraphs beginning + with other characters are reserved for future extensions. + + The first line of a failure paragraph ends with the characters ">:". + Everything between the leading "<" and the trailing ">:" is an + (unquoted) Internet mail address. + + A failure paragraph asserts that the MTA was permanently unable to + deliver the message to the mail address shown on the first line; the + MTA will not attempt further deliveries to that address. The + remaining lines of the paragraph give a human-readable description of + the reason for failure. Descriptions beginning with <20>, and + descriptions containing "#", are reserved for future extensions. + + The envelope sender might not have sent his message to the address + shown. There are two reasons for this. First, the MTA may freely + replace unprintable characters with "_". Second, the original + recipient address may have been an alias for the address shown. + + The original message is an exact copy of the message received by the + MTA, including both header and body, preceded by a Return-Path field + showing the envelope sender. + + +3. Comparison with 1892/1894 + + RFC 1892 and RFC 1894 together describe a format for delivery status + notifications. I have decided not to use that format, because I + believe that its complexity will prevent wide implementation and + increase the burden on people who manage mailing lists. + + QSBMF is dedicated to failure reports, whereas RFC 1894 allows + success reports and deferral reports. Although it would be possible + to add deferral paragraphs and success paragraphs to QSBMF, it would + be even easier to design separate formats for such notices. I have + trouble reading mixed failure/deferral reports. + + QSBMF always returns the entire original message. RFC 1892 allows + the MTA to return nothing or to return just the headers; it states + ``Return of content may be wasteful of network bandwidth.'' However, + failure notices are very rare, so the overall loss of bandwidth in + this case is insignificant. A much more important issue is storage + space: someone who manages a big mailing list does not want to have + to store several copies of each message in the form of bounces. The + best solution is to have each bounce automatically fed through a + program that stores only the critical information. I expect such + programs to spring up quickly for QSBMF. + + RFC 1894 provides language-independent error messages, as described + by RFC 1893. One can achieve the same results more easily by adding + structure to the human-readable failure descriptions, for example + with HCMSSC. + + RFC 1894 is able to communicate an ``envelope ID'' and the original + envelope recipient address specified by the sender. Unfortunately, + this information will almost never be available, since it requires + support by every intermediate MTA. All of the applications of this + information can be handled reliably, right now, with VERPs; this + requires support from the sender's MTA but not from other hosts. + + RFC 1894 includes several pieces of information that might be of + human interest but can be seen just as easily from Received lines: + the name of the MTA where delivery failed, the name of the previous + MTA, timestamps, etc. + + All of these RFC 1894 features have a cost: complexity. A program + cannot parse an 1894 report without parsing RFC 822 header fields + and understanding quite a bit of MIME. This will limit the + availability of parsing software. In the meantime, such reports are + annoying to mailing list maintainers, since they are full of + uninteresting information and are difficult to parse visually. + + +4. Security considerations + + Bounce messages may be forged. Never remove someone from a mailing + list without sending him a message stating that you are doing so, + even if the reason for removal is a series of apparent bounce + messages from his address. + + If you send a message along a secret path, you should change the + envelope sender address of the message to yourself, so that a bounce + will not reveal anything to the original sender. In other words: for + secret forwarding, use a mailing list, not a forwarder. + + See RFC 1894 for further discussion of these points. diff --git a/RFCVERP b/RFCVERP @@ -0,0 +1,88 @@ +Variable Envelope Return Paths +D. J. Bernstein, djb@pobox.com +19970201 + + +1. Introduction + + The fundamental problem in managing a large mailing list is matching + bounce messages to subscription addresses. + + Often a bounce message refers to a failing address that does not + appear on the mailing list. One of the mailing list subscribers is + forwarding messages to that address. Which subscriber? As the list + grows, this question becomes more and more difficult to answer. + + Sometimes a bounce message doesn't identify the address that failed. + On occasion it doesn't even include a copy of the original message. + See RFC 1211 for an extensive collection of horror stories. + + In theory, one could solve this problem with the DSN option and DSN + format described in RFC 1891, RFC 1892, and RFC 1894. Unfortunately, + the DSN option is useless unless it is supported by every + intermediate MTA. The complexity of RFC 1891 means that it will be + many years, perhaps infinitely many, before DSNs are universally + supported. Furthermore, the complexity of RFC 1894 means that parsing + the subscriber address is difficult even on the occasions that the + address is available. + + Variable envelope return paths (VERPs) completely eliminate this + problem _right now_. They automatically and reliably identify the + subscription address relevant to each bounce message. They provide + the address in a form that is trivial for automated bounce handlers + to parse. They require support from the local mailer, but they do not + require support from any other hosts. + + +2. Variable envelope return paths + + Here is how VERPs work: each recipient of the message sees a + different envelope sender address. When a message to the + djb-sos@silverton.berkeley.edu mailing list is sent to + God@heaven.af.mil, for example, it has the following envelope sender: + + djb-sos-owner-God=heaven.af.mil@silverton.berkeley.edu + + If the message bounces, the bounce message will be sent back to + djb-sos-owner-God=heaven.af.mil@silverton.berkeley.edu. + + If God is forwarding His mail, the bounce message will still go to + djb-sos-owner-God=heaven.af.mil@silverton.berkeley.edu. No matter how + uninformative the bounce message is, it will display God's + subscription address in its envelope. + + Another benefit of VERPs is that God Himself can see what address He + used to subscribe. + + Making VERPs work requires two pieces of local software support. + First: it must be easy to modify the outgoing sender address + separately for each envelope recipient. For example, with one mailer, + qmail, a user can simply touch ~/.qmail-list-owner and + ~/.qmail-list-owner-default to apply VERPs to user-list. + + Second, and more important: it must be easy to identify a collection + of addresses, such as djb-sos-owner-*, and send all mail for those + addresses to one place, while preserving the * information. Under + qmail, all user-list-owner-* mail will be sent to the user once he + touches ~/.qmail-list-owner-default. Sending the mail through an + automated bounce-handling program is just as easy. + + With older mailers, applying VERPs would require setting up a new + user-list-owner-recipient alias for each new recipient. This + inconvenience has prevented VERPs from being widely exploited, even + though the idea is not new. + + +3. Per-message VERPs + + VERPs are not restricted to distinguishing mailing list subscribers; + they can also be used to distinguish messages. + + For example, a user can send one message with an envelope sender + address of user-dsn-1, the next message with user-dsn-2, and so on. + As long as the local mailer gives all user-dsn-* back to that user, + he can reliably match up incoming bounces with outgoing messages. + + Per-message VERPs can be combined with per-recipient VERPs. Every + application of RFC 1891's ORCPT and ENVID can be handled with + VERPs---easily, reliably, and right now. diff --git a/SECURITY b/SECURITY @@ -0,0 +1,131 @@ +Background: Every few months CERT announces Yet Another Security Hole In +Sendmail---something that lets local or even remote users take complete +control of the machine. I'm sure there are many more holes waiting to be +discovered; sendmail's design means that any minor bug in 46000 lines of +code is a major security risk. Other popular mailers, such as Smail, and +even mailing-list managers, such as Majordomo, seem nearly as bad. + +I started working on qmail because I was sick of this cycle of doom. +Here are some of the things I did to make sure that qmail will never let +an intruder into your machine. + + +1. Programs and files are not addresses. Don't treat them as addresses. + +sendmail treats programs and files as addresses. Obviously random people +can't be allowed to execute arbitrary programs or write to arbitrary +files, so sendmail goes through horrendous contortions trying to keep +track of whether a local user was ``responsible'' for an address. This +has proven to be an unmitigated disaster. + +In qmail, programs and files are not addresses. The local delivery +agent, qmail-local, can run programs or write to files as directed by +~user/.qmail, but it's always running as that user. (The notion of +``user'' is configurable, but root is never a user. To prevent silly +mistakes, qmail-local makes sure that neither ~user nor ~user/.qmail is +group-writable or world-writable.) + +Security impact: .qmail, like .cshrc and .exrc and various other files, +means that anyone who can write arbitrary files as a user can execute +arbitrary programs as that user. That's it. + + +2. Do as little as possible in setuid programs. + +A setuid program must operate in a very dangerous environment: a user is +under complete control of its fds, args, environ, cwd, tty, rlimits, +timers, signals, and more. Even worse, the list of controlled items +varies from one vendor's UNIX to the next, so it is very difficult to +write portable code that cleans up everything. + +Of the twelve most recent sendmail security holes, six worked only +because the entire sendmail system is setuid. + +Only one qmail program is setuid: qmail-queue. Its only purpose is to +add a new mail message to the outgoing queue. + + +3. Do as little as possible as root. + +The entire sendmail system runs as root, so there's no way that its +mistakes can be caught by the operating system's built-in protections. +In contrast, only two qmail programs, qmail-start and qmail-lspawn, +run as root. + + +4. Move separate functions into mutually untrusting programs. + +Five of the qmail programs---qmail-smtpd, qmail-send, qmail-rspawn, +qmail-remote, and tcp-env---are not security-critical. Even if all of +these programs are completely compromised, so that an intruder has +control over the qmaild, qmails, and qmailr accounts and the mail queue, +he still can't take over your system. None of the other programs trust +the results from these five. + +In fact, these programs don't even trust each other. They are in three +groups: tcp-env and qmail-smtpd, which run as qmaild; qmail-rspawn and +qmail-remote, which run as qmailr; and qmail-send, the queue manager, +which runs as qmails. Each group is immune from attacks by the others. + +(From root's point of view, as long as root doesn't send any mail, only +qmail-start and qmail-lspawn are security-critical. They don't write any +files or start any other programs as root.) + + +5. Don't parse. + +I have discovered that there are two types of command interfaces in the +world of computing: good interfaces and user interfaces. + +The essence of user interfaces is _parsing_---converting an unstructured +sequence of commands, in a format usually determined more by psychology +than by solid engineering, into structured data. + +When another programmer wants to talk to a user interface, he has to +_quote_: convert his structured data into an unstructured sequence of +commands that the parser will, he hopes, convert back into the original +structured data. + +This situation is a recipe for disaster. The parser often has bugs: it +fails to handle some inputs according to the documented interface. The +quoter often has bugs: it produces outputs that do not have the right +meaning. Only on rare joyous occasions does it happen that the parser +and the quoter both misinterpret the interface in the same way. + +When the original data is controlled by a malicious user, many of these +bugs translate into security holes. Some examples: the Linux login +-froot security hole; the classic find | xargs rm security hole; the +recent Majordomo security hole. Even a simple parser like getopt is +complicated enough for people to screw up the quoting. + +In qmail, all the internal file structures are incredibly simple: text0 +lines beginning with single-character commands. (text0 format means that +lines are separated by a 0 byte instead of line feed.) The program-level +interfaces don't take options. + +All the complexity of parsing RFC 822 address lists and rewriting +headers is in the qmail-inject program, which runs without privileges +and is essentially part of the UA. + +The only nasty case is .qmail, qmail's answer to .forward. I tried to +make this as simple as possible, but unfortunately it still has to be +edited by users. As a result, the qlist mailing-list-management program +has to be careful to exclude subscriber addresses that contain newlines. + + +6. Keep it simple, stupid. + +See BLURB for some of the reasons that qmail is so much smaller than +sendmail. There's nothing inherently complicated about writing a mailer. +(Except RFC 822 support; but that's only in qmail-inject.) Security +holes can't show up in features that don't exist. + + +7. Write bug-free code. + +I've mostly given up on the standard C library. Many of its facilities, +particularly stdio, seem designed to encourage bugs. A big chunk of +qmail is stolen from a basic C library that I've been developing for +several years for a variety of applications. The stralloc concept and +getline2() make it very easy to avoid buffer overruns, memory leaks, +and artificial line length limits. diff --git a/SYSDEPS b/SYSDEPS @@ -0,0 +1,17 @@ +VERSION +systype +hasshsgr.h +hasnpbg1.h +select.h +hasflock.h +hassalen.h +fork.h +hassgact.h +direntry.h +hassgprm.h +haswaitp.h +hasmkffo.h +uint32.h +dns.lib +socket.lib +syslog.lib diff --git a/TARGETS b/TARGETS @@ -0,0 +1,353 @@ +auto-ccld.sh +make-load +find-systype +systype +load +make-compile +compile +fork.h +qmail-local.o +qmail.o +auto-str.o +make-makelib +makelib +substdio.o +substdi.o +substdo.o +subfderr.o +subfdout.o +subfdouts.o +subfdin.o +subfdins.o +substdio_copy.o +substdio.a +error.o +error_str.o +error_temp.o +error.a +str_len.o +str_diff.o +str_diffn.o +str_cpy.o +str_chr.o +str_rchr.o +str_start.o +byte_chr.o +byte_rchr.o +byte_diff.o +byte_copy.o +byte_cr.o +byte_zero.o +str.a +auto-str +auto_qmail.c +auto_qmail.o +auto-int8.o +fmt_str.o +fmt_strn.o +fmt_uint.o +fmt_uint0.o +fmt_ulong.o +scan_ulong.o +scan_8long.o +scan_nbblong.o +fs.a +auto-int8 +auto_patrn.c +auto_patrn.o +quote.o +now.o +gfrom.o +myctime.o +slurpclose.o +case_diffb.o +case_diffs.o +case_lowerb.o +case_lowers.o +case_starts.o +case.a +getln.o +getln2.o +getln.a +subgetopt.o +sgetopt.o +getopt.a +sig_alarm.o +hassgprm.h +sig_block.o +hassgact.h +sig_catch.o +sig_pause.o +sig_pipe.o +sig_child.o +sig_hup.o +sig_term.o +sig_bug.o +sig_misc.o +sig.a +open_append.o +open_excl.o +open_read.o +open_trunc.o +open_write.o +open.a +seek_cur.o +seek_end.o +seek_set.o +seek_trunc.o +seek.a +hasflock.h +lock_ex.o +lock_exnb.o +lock_un.o +lock.a +fd_copy.o +fd_move.o +fd.a +wait_pid.o +haswaitp.h +wait_nohang.o +wait.a +env.o +envread.o +env.a +stralloc_eady.o +stralloc_pend.o +stralloc_copy.o +stralloc_opys.o +stralloc_opyb.o +stralloc_cat.o +stralloc_cats.o +stralloc_catb.o +stralloc_arts.o +stralloc.a +alloc.o +alloc_re.o +alloc.a +datetime.o +datetime_un.o +datetime.a +qmail-local +uint32.h +qmail-lspawn.o +auto-uid.o +auto-uid +auto-gid.o +auto-gid +auto_uids.c +auto_uids.o +auto-int.o +auto-int +auto_spawn.c +auto_spawn.o +select.h +chkspawn.o +chkspawn +spawn.o +chkshsgr.o +chkshsgr +hasshsgr.h +prot.o +coe.o +cdb_hash.o +cdb_unpack.o +cdb_seek.o +cdb.a +qmail-lspawn +qmail-getpw.o +auto_break.c +auto_break.o +auto_usera.c +auto_usera.o +qmail-getpw +qmail-remote.o +control.o +constmap.o +timeoutread.o +timeoutwrite.o +timeoutconn.o +tcpto.o +dns.o +ip.o +ipalloc.o +hassalen.h +ipme.o +ndelay.o +ndelay_off.o +ndelay.a +socket.lib +dns.lib +qmail-remote +qmail-rspawn.o +tcpto_clean.o +qmail-rspawn +direntry.h +qmail-clean.o +auto_split.c +auto_split.o +fmtqfn.o +qmail-clean +qmail-send.o +qsutil.o +newfield.o +prioq.o +hasmkffo.h +fifo.o +hasnpbg1.h +trigger.o +readsubdir.o +date822fmt.o +qmail-send +qmail-start.o +qmail-start +splogger.o +syslog.lib +splogger +qmail-queue.o +triggerpull.o +qmail-queue +qmail-inject.o +headerbody.o +hfield.o +token822.o +qmail-inject +predate.o +predate +datemail +mailsubj +qmail-upq +qmail-config +qmail-showctl.o +qmail-showctl +qmail-newu.o +cdbmss.o +cdbmake_pack.o +cdbmake_hash.o +cdbmake_add.o +cdbmake.a +qmail-newu +qmail-pw2u.o +qmail-pw2u +qmail-qread.o +qmail-qread +qmail-qstat +qmail-tcpto.o +qmail-tcpto +qmail-pop3d.o +qmail-pop3d +qmail-popup.o +qmail-popup +qmail-qmtpd.o +received.o +qmail-qmtpd +qmail-smtpd.o +qmail-smtpd +sendmail.o +sendmail +tcp-env.o +remoteinfo.o +tcp-env +dnscname.o +dnsdoe.o +dnscname +dnsptr.o +dnsptr +dnsip.o +dnsip +dnsmxip.o +dnsmxip +dnsfq.o +dnsfq +hostname.o +hostname +ipmeprint.o +ipmeprint +qlist.o +qlist +qlist2 +qreceipt.o +qreceipt +qsmhook.o +qsmhook +qbiff.o +qbiff +forward.o +forward +preline.o +preline +condredirect.o +condredirect +maildirmake.o +maildirmake +maildir2mbox.o +maildir.o +strerr_sys.o +strerr_die.o +strerr.a +maildir2mbox +maildirwatch.o +maildirwatch +qail +elq +pinq +qmail-hier.o +qmail-hier +install.o +install +instcheck.o +instcheck +it +qmail-local.0 +qmail-lspawn.0 +qmail-getpw.8 +qmail-getpw.0 +qmail-remote.0 +qmail-rspawn.0 +qmail-clean.0 +qmail-send.8 +qmail-send.0 +qmail-start.0 +splogger.0 +qmail-queue.0 +qmail-inject.0 +mailsubj.0 +qmail-showctl.0 +qmail-newu.0 +qmail-pw2u.8 +qmail-pw2u.0 +qmail-qread.0 +qmail-qstat.0 +qmail-tcpto.0 +qmail-pop3d.0 +qmail-popup.0 +qmail-qmtpd.0 +qmail-smtpd.0 +tcp-env.0 +qlist.0 +qreceipt.0 +qbiff.0 +forward.0 +preline.0 +condredirect.0 +maildirmake.0 +maildir2mbox.0 +maildirwatch.0 +qmail.0 +qmail-upgrade.7 +qmail-upgrade.0 +qmail-limits.7 +qmail-limits.0 +qmail-log.0 +qmail-control.0 +qmail-header.0 +qmail-users.0 +dot-qmail.5 +dot-qmail.0 +qmail-command.0 +tcp-environ.0 +maildir.0 +mbox.0 +addresses.0 +envelopes.0 +forgeries.0 +man diff --git a/THANKS b/THANKS @@ -0,0 +1,217 @@ +Thanks to lots of people for success and failure reports, code, ideas, +and documentation. See CHANGES for details of specific contributions. +Sorry if I left anyone out. + +SA = Satoshi Adachi +G1A = Graham Adams +NA = Norm Aleks +NAA = Nicholas A. Amato +G2A = Greg Andrews +TA = Tetsuo Aoki +DA = Dave Arcuri +JJB = J. J. Bailey +J2B = Jos Backus +SSB = Stik Bakken +J1B = John Banghart +GB = Glenn Barry +JLB = Julie L. Baumler +SLB = Steven L. Baur +ALB = Allan L. Bazinet +JDHB = Johannes D. H. Beekhuizen +BDB = Boris D. Beletsky +HJB = Herbert J. Bernstein +REB = Ronald E. Bickers +JPB = Joe Block +BB = Bruce Bodger +SB = Stephane Bortzmeyer +PB = Peter Bowyer +ACB = Andy C. Brandt +AB = Alan Briggs +AKB = Allen K. Briggs +JBB = Jason B. Brown +JAB = Jeremy A. Bussard +RJC = Robert J. Carter +EC = Evan Champion +JC = Jim Clausing +HCJ = Helio Coelho Jr. +BC = Bob Collie +SGC = Stephen G. Comings +MC = Michael Cooley +DCC = Daniel C. Cotey +AC = Arne Coucheron +M2C = Mark Crimmins +DC = Dan Cross +MD = Mark Delany +SVD = Stef Van Dessel +RD = Rahul Dhesi +MJD = Mark-Jason Dominus +JD = Joe Doupnik +FE = Frank Ederveen +DE = Daniel Egnor +MWE = Mark W. Eichin +MEE = Mads E. Eilertsen +KE = Kenny Elliott +TEE = Thomas E. Erskine +ME = Marc Ewing +JF = Janos Farkas +DF = Dale Farnsworth +YF = Yaroslav Faybishenko +CF = C. Ferree +JBF = John B. Fleming +C2F = Chuck Foster +RF = Rainer Fraedrich +MF = Massimo Fusaro +CG = Chris Garrigues +BG = Bert Gijsbers +M2G = Michael R. Gile +EG = Eivind Gjelseth +HG = Howard Goldstein +TG = Tim Goodwin +HDG = Hans de Graaff +MG = Michael Graff +PJG = Paul Graham +MRG = Matthew R. Green +SG = Steven Grimm +AG = Armin Gruner +CSH = Clayton S. Haapala +JLH = Jason L. Haar +MLH = May Liss Haarstad +CH = Chael Hall +JPH = Justin P. Hannah +RJH = Randy Harmon +PH = Paul Harrington +DEH = Daniel E. Harris +RFH = Robert F. Harrison +D1H = Dieter Heidner +GH = Gene Hightower +MH = Markus Hofmann +D2H = Dan Hollis +NH = Nick Holloway +TH = Ton Hospel +BH = Brad Howes +TJH = Timothy J. Hunt +B2H = Buck Huppmann +MDI = Miguel de Icaza +BJ = Brian Jackson +AJ = Alan Jaffray +CEJ = Colin Eric Johnson +K2J = Kevin Johnson +K1J = Kyle Jones +SJ = Sudish Joseph +W2K = Wolfram Kahl +JJMK = Jonathan J. M. Katz +CK = Christoph Kaesling +PK = Petri Kaukasoina +D2K = Dax Kelson +TK = Terry Kennedy +DBK = Douglas B. Kerry +WK = Werner Koch +DK = Dave Kopper +J1K = Jost Krieger +J2K = Johannes Kroeger +EK = Eric Krohn +B2L = Brent Laminack +AL = Andreas Lamprecht +L2L = Louis Larry +M3L = Michael Lazarou +CL = Carsten Leonhardt +JRL = John R. Levine +DML = David M. Lew +LL = lilo +FPL = Frederik P. Lindberg +JL = Jim Littlefield +BL = Brian Litzinger +RL = Robert Luce +ML = Martin Lucina +M2L = M. Lyons +TM = Toshinori Maeno +ESM = Edward S. Marshall +J2M = Joel Maslak +TLM = Timothy L. Mayo +DM = David Mazieres +RM = Rich McClellan +SM = Shawn McHorse +JM = Jim Meehan +HWM = Henry W. Miller +RDM = Raul Miller +MMM = Momchil M. Momchev +JGM = John G. Myers +FN = Faried Nawaz +RN = Russell Nelson +TN = Thomas Neumann +UO = Uwe Ohse +PCO = Peter C. Olsen +HHO = Harald Hanche-Olsen +BEO = Bruce E. O'Neel +JP = John Palkovic +AP = Andrew Pam +SP = Stephen Parker +TVP = Tom van Peer +BP = Bruce Perens +CMP = Chase M. Phillips +DP = Dave Platt +EP = Emanuele Pucciarelli +JPR = Jean-Pierre Radley +S1R = Satish Ramachandran +MR = Mosfeq Rashid +TRR = Tracy R. Reed +BR = Brian Reichert +S2R = Sean Reifschneider +DAR = Daniel A. Reish +CR = Christian Riede +KR = Kenji Rikitake +OR = Ollivier Robert +ANR = Adriano Nagelschmidt Rodrigues +JJR = Jaron J. Rubenstein +RS = Robert Sanders +KJS = Kevin J. Sawyer +MBS = Mike Scher +SAS = Steven A. Schrader +CLS = Christopher L. Seawood +OS = Oliver Seiler +D2S = Dan Senie +SS = Simon Shapiro +RGS = Richard G. Sharman +DS = Dave Sill +H2S = Harley Silver +M3S = Morten Skjelland +JS = Jesper Skriver +ES = Eric Smith +IS = Icarus Sparry +CS = Cloyce Spradling +BS = Bjoern Stabell +HS = Harlan Stenn +JMS = Jason M. Stokes +DWS = David Wayne Summers +M2S = Mikael Suokas +PS = Paul Svensson +ET = Eivind Tagseth +PT = Paul Taylor +S2T = Steve Taylor +BT = Brad Templeton +DST = Daniel S. Thibadeau +MT = Mark Thompson +S3T = Steffen Thorsen +KT = Karsten Thygesen +BET = Bennett E. Todd +JMT = John M. Twilley +ST = Steve Tylock +TU = Tetsu Ushijima +VV = Vince Vielhaber +TV = Tommi Virtanen +FW = Frank Wagner +BW = Bill Weinman +IW = Ian Westcott +SJW = Stephen J. White +JW = John Whittaker +LW = Lionel Widdifield +MW = Mate Wierdl +BTW = Brian T. Wightman +PW = Peter Wilkinson +HW = Hal Wine +GAW = Greg A. Woods +SCW = Steven C. Work +JLW = Jason L. Wright +WW = Wei Wu +IKW = Ian Keith Wynne +BZ = Blaz Zupan diff --git a/THOUGHTS b/THOUGHTS @@ -0,0 +1,437 @@ +Please note that this file is not called ``Internet Mail For Dummies.'' +It _records_ my thoughts on various issues. It does not _explain_ them. +Paragraphs are not organized except by section. The required background +varies wildly from one paragraph to the next. + +In this file, ``sendmail'' means Allman's creation; ``sendmail-clone'' +means the program in this package. + + +1. Security + +There are lots of interesting remote denial-of-service attacks on any +mail system. A long-term solution is to insist on prepayment for +unauthorized resource use. The tricky technical problem is to make the +prepayment enforcement mechanism cheaper than the expected cost of the +attacks. (For local denial-of-service attacks it's enough to be able to +figure out which user is responsible.) + +qmail-send's log was originally designed for profiling. It subsequently +sprouted some tracing features. However, there's no way to verify +securely that a particular message came from a particular local user; +how do you know the recipient is telling you the truth about the +contents of the message? With QUEUE_EXTRA it'd be possible to record a +one-way hash of each outgoing message, but a user who wants to send +``bad'' mail can avoid qmail entirely. + +I originally decided on security grounds not to put qmail advertisements +into SMTP responses: advertisements often act as version identifiers. +But this problem went away when I found a stable qmail URL. + +As qmail grows in popularity, the mere knowledge that rcpthosts is so +easily available will deter people from setting up unauthorized MXs. +(I've never seen an unauthorized MX, but I can imagine that it would be +rather annoying.) Note that, unlike the bat book checkcompat() kludge, +rcpthosts doesn't interfere with mailing lists. + +qmail-start doesn't bother with tty dissociation. On some old machines +this means that random people can send tty signals to the qmail daemons. +That's a security flaw in the job control subsystem, not in qmail. + +The resolver library isn't too bloated (before 4.9.4, at least), but it +uses stdio, which _is_ bloated. Reading /etc/resolv.conf costs lots of +memory in each qmail-remote process. So it's tempting to incorporate a +smaller resolver library into qmail. (Bonus: I'd avoid system-specific +problems with old resolvers.) The problem is that I'd then be writing a +fundamentally insecure library. I'd no longer be able to blame the BIND +authors and vendors for the fact that attackers can easily use DNS to +steal mail. Possible solution: replace dns.c with something that passes +requests (reliably!) to a local daemon; call the original resolver +library from that daemon. + +NFS is the primary enemy of security partitioning under UNIX. Here's the +story. Sun knew from the start that NFS was completely insecure. It +tried to hide that fact by disallowing root access over NFS. Intruders +nevertheless broke into system after system, first obtaining bin access +and then obtaining root access. Various people thus decided to compound +Sun's error and build a wall between root and all other users: if all +system files are owned by root, and if there are no security holes other +than NFS, someone who breaks in via NFS won't be able to wipe out the +operating system---he'll merely be able to wipe out all user files. This +clueless policy means that, for example, all the qmail users have to be +replaced by root. See what I mean by ``enemy''? ... Basic NFS comments: +Aside from the cryptographic problem of having hosts communicate +securely, it's obvious that there's an administrative problem of mapping +client uids to server uids. If a host is secure and under your control, +you shouldn't have to map anything. If a host is under someone else's +control, you'll want to map his uids to one local account; it's his +client's job to decide which of his users get to talk NFS in the first +place. Sun's original map---root to nobody, everyone else left alone--- +is, as far as I can tell, always wrong. + + +2. Injecting mail locally (qmail-inject, sendmail-clone) + +RFC 822 section 3.4.9 prohibits certain visual effects in headers. +qmail-inject doesn't waste the time to enforce this absurd restriction. +If you will suffer from someone sending you ``flash mail,'' go find a +better mail reader. + +qmail-inject's ``Cc: recipient list not shown: ;'' successfully stops +sendmail from adding Apparently-To. Unfortunately, old versions of +sendmail will append a host name. This wasn't fixed until sendmail 8.7. +How many years has it been since RFC 822 came out? + +sendmail discards duplicate addresses. This has probably resulted in +more lost and stolen mail over the years than the entire Chicago branch +of the United States Postal Service. The qmail system delivers messages +exactly as it's told to do. Along the same lines: qmail-inject is both +unable and unwilling to support anything like sendmail's (default) +nometoo option. Of course, a list manager could support nometoo. + +There should be a mechanism in qmail-inject that does for envelope +recipients what Return-Path does for the envelope sender. Then +qmail-inject -n could print the recipients. + +Should qmail-inject bounce messages with no recipients? Should there be +an option for this? If it stays as is (accept the message), qmail-inject +could at least avoid invoking qmail-queue. + +It is possible to extract non-unique Message-IDs out of qmail-inject. +Here's how: stop qmail-inject before it gets to the third line of +main(), then wait until the pids wrap around, then restart qmail-inject +and blast the message through, then start another qmail-inject with the +same pid in the same second. I'm not sure how to fix this. (Of course, +the user could just type in his own non-unique Message-IDs.) + +The bat book says: ``Rules that hide hosts in a domain should be applied +only to sender addresses.'' Recipient masquerading works fine with +qmail. None of sendmail's pitfalls apply, basically because qmail has a +straight paper path. + +I expect to receive some pressure to make up for the failings of MUA +writers who don't understand the concept of reliability. (``Like, duh, +you mean I was supposed to check the sendmail exit code?'') + + +3. Receiving mail from the network (tcp-env, qmail-smtpd) + +RFC 1123 requires VRFY support, but says that it's okay if an +implementation can be configured to not allow VRFY. qmail-smtpd doesn't +allow VRFY. If you desperately want your SMTP server (i.e., inetd) to +provide useful information for VRFY, just compile and install sendmail. +Were the RFC 1123 writers aware of the as-if principle of interface +specification? ... They say that VRFY and EXPN are important for +tracking down cross-host mailing list loops. Catch up to the 1990s, +guys: with Delivered-To, mailing list loops do absolutely no damage, +_and_ one of the list administrators gets a bounce that shows exactly +how the loop occurred. Solve the problem, not the symptom. ... There's a +vastly superior alternative to EXPN. Hint: finger postmaster@ai.mit.edu. + +Should dns.c make special allowances for 127.0.0.1/localhost? + +badmailfrom (like 8BITMIME) is a waste of code space. + + +4. Adding messages to the queue (qmail-queue) + +Should qmail-queue try to make sure enough disk space is free in +advance? When qmail-queue is invoked by qmail-local or (with ESMTP) +qmail-smtpd or qmail-qmtpd, it could be told a size in advance. I wish +UNIX had an atomic allocate-disk-space routine... + +The qmail.h interface (reflecting the qmail-queue interface, which in +turn reflects the current queue file structure) is constitutionally +incapable of handling an address that contains a 0 byte. I can't imagine +that this will be a problem. + +Should qmail-queue not bother queueing a message with no recipients? + + +5. Handling queued mail (qmail-send, qmail-clean) + +The queue directory must be local. Mounting it over NFS is extremely +dangerous---not that this stops people from running sendmail that way! +Perhaps it is worth putting together a diskless-host qmail package with +just qmail-inject and an SMTP client in place of qmail-queue. Sending +mail to the server via SMTP is of course vastly better than trying to do +anything over NFS. If the NFS server is up but the mail server is down, +users will just have to wait. + +Queue reliability demands that single-byte writes be atomic. This is +true for a fixed-block filesystem such as UFS, and for a logging +filesystem such as LFS. + +qmail-send uses 8 bytes of memory per queued message. Double that for +reallocation. (Fix: use a small forest of heaps; i.e., keep several +prioqs.) Double again for buddy malloc()s. (Fix: be clever about the +heap sizes.) 32 bytes is worrisome, but not devastating. Even on my +disk-heavy memory-light machine, I'd run out of inodes long before +running out of memory. + +Some mail systems organize the queue by host. This is pointless as a +means of splitting up the queue directory. The real issue is what to do +when you suddenly find out that a host is up. For local SLIP/PPP links +you know in advance which hosts need this treatment, so you can handle +them with virtualdomains and serialmail. + +For the old queue structure I implemented recipient list compression: +if mail goes out to a giant mailing list, and most of the recipients are +delivered, make a new, compressed, todo list. But this really isn't +worth the effort: it saves only a tiny bit of CPU time. + +qmail-send doesn't have any notions of precedence, priority, fairness, +importance, etc. It handles the queue in first-seen-first-served order. +One could put a lot of work into doing something different, but that +work would be a waste: given the triggering mechanism and qmail's +deferral strategy, it is exceedingly rare for the queue to contain more +than one deliverable message at any given moment. + +Exception: Even with all the concurrency tricks, qmail-send can end up +spending a few minutes on a mailing list with thousands of remote +entries. A user might send a new message to a remote address in the +meantime. Perhaps qmail-send should limit its time per message to, +say, thirty recipients. This will require some way to mark recipients +who were already done on this pass. Possible approach: Maintain two todo +lists (for both L and R). Always work on the earlier todo list. Move +deferrals to the other todo list. + +qmail-send will never start a pass for a job that it already has. This +means that, if one delivery takes longer than the retry interval, the +next pass will be delayed. I implemented the opposite strategy for the +old queue structure. Some hassles: mark() had to understand how job +input was buffered; every new delivery had to check whether the same +mpos in the same message was already being done. + +Some things that qmail-send does synchronously: queueing a bounce +message; doing a cleanup via qmail-clean; classifying and rewriting all +the addresses in a new message. As usual, making these asynchronous +would require some housekeeping, but could speed things up a bit. +(Making bounces asynchronous, without POSIX waitpid(), means that +wait_pid() has to keep a buffer of previous wait()s. Ugh.) + +fsync() is a bottleneck. To make this asynchronous would require gobs of +dedicated output processes whose only purpose in life is to watch data +get written to the disk. Inconceivable! (``You keep using that word. I +do not think that word means what you think it means.'') + +On the other hand, I could survive without fsync()ing the local and +remote and info files as long as I don't unlink todo. This would require +redefining the queue states. I need to see how much speed can be gained. + +Currently qmail-send sends at most one bounce message for each incoming +message. This means that the sender doesn't get flooded with copies of +his own message. On the other hand, a single slow address can hold up +bounces for a bunch of fast addresses. It would be easy to call +injectbounce() more often. What is the best strategy? This feels like +the TCP-buffering issue... don't want to pepper the other guy with +little packets, but do want to get the data across. + +qmail-stop implementation: setuid to UID_SEND; kill -TERM -1. Given how +simple this is, I'm not inclined to set up some tricky locking solution +where qmail-send records its pid etc. But I just know that, if I provide +this qmail-stop program, someone will screw himself by making another +uid the same as UID_SEND, or making UID_SEND be root, or whatever. +Aargh. Maybe use another named pipe... New solution: Run qmail-start +under an external service controller---it runs in the foreground now. + +Bounce messages could include more statistical information in the first +paragraph: when I received the message, how many recipients I was +supposed to handle, how many I successfully dealt with, how many I +already told you about, how many are still in the queue. Have to +emphasize that the number of recipients _here_ is perhaps less than the +number of recipients on the original message. + +The readdir() interface hides I/O errors. Lower-level interfaces would +lead me into a thicket of portability problems. I'm really not sure what +to do about this. Of course, a hard I/O error means that mail is toast, +but a soft I/O error shouldn't cause any trouble. + +job_open() or pass_dochan() could be paranoid about the same id,channel +already being open; but, since messdone() is so paranoid, the worst +possible effect of a bug along these lines would be double delivery. + +Mathematical amusement: The optimal retry schedule is essentially, +though not exactly, independent of the actual distribution of message +delay times. What really matters is how much cost you assign to retries +and to particular increases in latency. qmail's current quadratic retry +schedule says that an hour-long delay in a day-old message is worth the +same as a ten-minute delay in an hour-old message; this doesn't seem so +unreasonable. + +Insider information: AOL retries their messages every five minutes for +three days straight. Hmmm. + + +6. Sending mail through the network (qmail-rspawn, qmail-remote) + +Are there any hosts, anywhere, whose mailers are bogged down by huge +messages to multiple recipients at a single host? For typical hosts, +multiple RCPTs per SMTP aren't an ``efficiency feature''; they're a +_slowness_ feature. Separate SMTP transactions have much lower latency. + +The multiple-RCPT bandwidth gain _might_ be noticeable for a machine +that sends most messages to a smarthost. It would be easy to have +qmail-rspawn supply qmail-remote with all the addresses at once, as long +as qmail-send says when it's about to block... Putting recipients into +the right order is clearly the UA's job. One multiple-RCPT pitfall is +that a remote host might not be able to deal with (say) 10 recipients, +even though RFC 821 says everyone has to be able to handle 100; +qmail-rspawn would have to notice this and back off. (Not that other +mailers do. Sometimes I'm amazed Internet mail works at all.) + +In the opposite direction: It's tempting to remove the @host part of the +qmail-remote recip argument. Or at least avoid double-dns_cname. + +There are lots of reasons that qmail-rspawn should take a more active +role in qmail-remote's activities. It should call separate programs to +do (1) MX lookups, (2) SMTP connections, (3) QMTP connections. + +I bounce ambiguous MXs. (An ``ambiguous MX'' is a best-preference MX +record sending me mail for a host that I don't recognize as local.) +Automatically treating ambiguous MXs as local is incompatible with my +design decision to keep local delivery working when the network goes +down. It puts more faith in DNS than DNS deserves. Much better: Have +your MX records generated automatically from control/locals. + +If I successfully connect to an MX host but it temporarily refuses to +accept the message, I give up and put the message back into the queue. +But several documents seem to suggest that I should try further MX +records. What are they thinking? My approach deals properly with downed +hosts, hosts that are unreachable through a firewall, and load +balancing; what else do people use multiple MX records for? + +Currently qmail-remote sends data in 1024-byte buffers. Perhaps it +should try to take account of the MTU. + +Perhaps qmail-remote should allocate a fixed amount of DNS/connect() +time across any number of MXs; this idea is due to Mark Delany. + +RFC 821 doesn't say what it means by ``text.'' qmail-remote assumes that +the server's reply text doesn't contain bare LFs. + + +7. Delivering mail locally (qmail-lspawn, qmail-local) + +qmail-local doesn't support comsat. comsat is a pointless abomination. +Use qbiff if you want that kind of notification. + +The getpwnam() interface hides I/O errors. Solution: qmail-pw2u. + + +8. sendmail V8's new features + +sendmail-8.8.0/doc/op/op.me includes a list of big improvements of +sendmail 8.8.0 over sendmail 5.67. Here's how qmail stacks up against +each of those improvements. (Of course, qmail has its own improvements, +but that's not the point of this list.) + +Connection caching, MX piggybacking: Nope. (Profile. Don't speculate.) + +Response to RCPT command is fast: Yup. + +IP addresses show up in Received lines: Yup. + +Self domain literal is properly handled: Yup. + +Different timeouts for QUIT, RCPT, etc.: No, just a single timeout. + +Proper <> handling, route-address pruning: Yes, but not configurable. + +ESMTP support: Yup. (Server-side, including PIPELINING.) + +8-bit clean: Yup. (Including server-side 8BITMIME support; same as +sendmail with the 8 option.) + +Configurable user database: Yup. + +BIND support: Yup. + +Keyed files: Yes, in qmsmac. + +931/1413/Ident/TAP: Yup. + +Correct 822 address list parsing: Yup. (Note that sendmail still has +some major problems with quoting.) + +List-owner handling: Yup. + +Dynamic header allocation: Yup. + +Minimum number of disk blocks: Yes, via tunefs -m. + +Checkpointing: Yes, but not configurable---qmail always checkpoints. + +Error message configuration: Nope. + +GECOS matching: Not directly, but easy to hook in. + +Hop limit configuration: No. (qmail's limit is 100 hops. qmail offers +automatic loop protection much more advanced than hop counting.) + +MIME error messages: No. (qmail uses QSBMF error messages, which are +much easier to parse.) + +Forward file path: Yes, via /etc/passwd. + +Incoming SMTP configuration: Yes, via inetd or tcpserver. + +Privacy options: Yes, but they're not options. + +Best-MX mangling: Nope. See section 6 for further discussion. + +7-bit mangling: Nope. qmail always uses 8 bits. + +Support for up to 20 MX records: Yes, and more. qmail has no limits +other than memory. + +Correct quoting of name-and-address headers: Yup. + +VRFY and EXPN now different: Nope. qmail always hides this information. + +Multi-word classes, deferred macro expansion, separate envelope/header +$g processing, separate per-mailer envelope and header processing, new +command line flags, new configuration lines, new mailer flags, new +macros: These are sendmail-specific; they wouldn't even make sense for +qmail. For example, _of course_ qmail handles envelopes and headers +separately; they're almost entirely different objects! + + +9. Miscellany + +sendmail-clone and qsmhook are too bletcherous to be documented. (The +official replacement for qsmhook is preline, together with the +qmail-command environment variables.) + +I've considered making install atomic, but this is very difficult to do +right, and pointless if it isn't done right. + +RN suggests automatically putting together a reasonable set of lines for +/etc/passwd. I perceive this as getting into the adduser business, which +is worrisome: I'll be lynched the first time I screw up somebody's +passwd file. This should be left to OS-specific installation scripts. + +The BSD 4.2 inetd didn't allow a username. I think I can safely forget +about this. (DS notes that the username works under Ultrix even though +it's undocumented.) + +I should clean up the bput/put choices. + +Some of the stralloc_0()s indicate that certain lower-level routines +should grok stralloc. + +RN suggests having qlist smash the case of the incoming host name. + +K1J suggests that mailing list subscription managers should have +a three-way handshake, to prevent person A from subscribing person B to +a mailing list. qlist doesn't do this, but ezmlm does. + +qmail assumes that all times are positive; that pid_t, time_t and ino_t +fit into unsigned long; that gid_t fits into int; that the character set +is ASCII; and that all pointers are interchangeable. Do I care? + +The bat book justifies sendmail's insane line-splitting mechanism by +pointing out that it might be useful for ``a 40-character braille +print-driving program.'' C'mon, guys, is that your best excuse? + +qmail's mascot is a dolphin. diff --git a/TODO b/TODO @@ -0,0 +1,9 @@ +do some serious coverage testing, preferably under Purify, without alloc slop +replace INTERNALS and THOUGHTS with a real paper describing qmail +reorganize qmail-inject to do most rw on characters, not tokens +allow concurrency over 255 +handle IPv6 +turn qmail-upq into a more serious queue-moving utility +expand strerr coverage +rewrite everything from scratch +maybe allow root to clear tcpto on the fly diff --git a/UPGRADE b/UPGRADE @@ -0,0 +1,145 @@ +SAVE COPIES OF YOUR OUTGOING MAIL! Like any other piece of software (and +information generally), the qmail system comes with NO WARRANTY. It's +much more secure and reliable than sendmail, but that's not saying much. + + +Here's how to upgrade from qmail 1.00 to qmail 1.01. This procedure will +overwrite the old qmail binaries. Furthermore, it may begin delivering +messages from the queue before you have had a chance to test it. + + +WARNING: The qmail-start command line has changed. + + +Before starting, compare conf* to your old conf*, and make any necessary +changes. Do not copy your old conf*; the baseline has changed. + + +How to install: + + 1. Compile the programs: + # make + 2. Create the formatted man pages, *.0: + # make man + 3. Inform your users that mail will not be accepted for a few minutes. + 4. Disable deliveries by killing your old qmail-send. Wait for it to + print ``exiting'' in the log. + 5. Disable SMTP service by commenting out the smtp line in inetd.conf; + kill -HUP your inetd. (If you are using tcpserver, simply kill -STOP + your tcpserver.) Wait for current qmail-smtpd processes to die. (If + you are running a QMTP server, disable that too.) + 6. Install the new binaries and man pages: + # rm /var/qmail/bin/* /var/qmail/man/*/* + # make setup + 7. Run instcheck to make sure it doesn't print any warnings: + # make check + 8. Reenable deliveries: + # env - PATH="/var/qmail/bin:$PATH" \ + qmail-start ./Mailbox splogger qmail & + Make sure to include the ./ in ./Mailbox. + 9. Insert ./Mailbox into the qmail-start line in your boot scripts. +10. Reenable SMTP service by restoring the smtp line in inetd.conf; kill + -HUP your inetd. (If you are using tcpserver, simply kill -CONT your + tcpserver. If you are running a QMTP server, reenable that too.) + + +How to test (steps 11-17 can be done before step 10): + +11. Look for a + qmail: running + line in syslog. (The big number is a splogger timestamp.) +12. Local-local test: Send yourself an empty message. (Replace ``me'' + with your username. Make sure to include the ``to:'' colon.) + % echo to: me | /var/qmail/bin/qmail-inject + The message will show up immediately in ~/Mailbox, and syslog will + show something like this: + qmail: new msg 53 + qmail: info msg 53: bytes 246 from <me@domain> qp 20345 uid 666 + qmail: starting delivery 1: msg 53 to local me@domain + qmail: delivery 1: success: did_1+0+0/ + qmail: end msg 53 + (53 is an inode number; 20345 is a process ID; your numbers will + probably be different.) +13. Local-error test: Send a message to a nonexistent local address. + % echo to: nonexistent | /var/qmail/bin/qmail-inject + qmail: new msg 53 + qmail: info msg 53: bytes 246 from <me@domain> qp 20351 uid 666 + qmail: starting delivery 2: msg 53 to local nonexistent@domain + qmail: delivery 2: failure: No_such_address.__#5.1.1_/ + qmail: bounce msg 53 qp 20357 + qmail: end msg 53 + qmail: new msg 54 + qmail: info msg 54: bytes 743 from <> qp 20357 uid 666 + qmail: starting delivery 3: msg 54 to local me@domain + qmail: delivery 3: success: did_1+0+0/ + qmail: end msg 54 + You will now have a bounce message in ~/Mailbox. +14. Local-remote test: Send an empty message to your account on another + machine. + % echo to: me@wherever | /var/qmail/bin/qmail-inject + qmail: new msg 53 + qmail: info msg 53: bytes 246 from <me@domain> qp 20372 uid 666 + qmail: starting delivery 4: msg 53 to remote me@wherever + qmail: delivery 4: success: 1.2.3.4_accepted_message./... + qmail: end msg 53 + There will be a pause between ``starting delivery'' and ``success''; + SMTP is slow. Check that the message is in your mailbox on the other + machine. +15. Local-postmaster test: Send mail to postmaster, any capitalization. + % echo to: POSTmaster | /var/qmail/bin/qmail-inject + Look for the message in ~alias/Mailbox. +16. Double-bounce test: Send a message with a completely bad envelope. + % /var/qmail/bin/qmail-inject -f nonexistent + To: unknownuser + Subject: testing + + This is a test. This is only a test. + % + (Use end-of-file, not dot, to end the message.) Look for the double + bounce in ~alias/Mailbox. +17. Group membership test: + % cat > ~me/.qmail-groups + |groups >> MYGROUPS; exit 0 + % /var/qmail/bin/qmail-inject me-groups < /dev/null + % cat ~me/MYGROUPS + MYGROUPS will show your normal gid and nothing else. (Under Solaris, + make sure to use /usr/ucb/groups; /usr/bin/groups is broken.) +18. SMTP server test: Forge some mail locally via SMTP. + % telnet 127.0.0.1 25 + Trying 127.0.0.1... + Connected to 127.0.0.1. + Escape character is '^]'. + 220 domain ESMTP + helo dude + 250-domain + 250-PIPELINING + 250 8BITMIME + mail <me@domain> + 250 ok + rcpt <me@domain> + 250 ok + data + 354 go ahead + Subject: testing + + This is a test. + . + 250 ok 812345679 qp 12345 + quit + 221 domain + Connection closed by foreign host. + % + Look for the message in your mailbox. +19. Remote-local test: Send yourself some mail from another machine. +20. Remote-error test: I think you can figure this one out. +21. UA test: Try sending mail, first to a local account, then to a + remote account, with your normal user agent. +22. Remote-postmaster test: Send mail from another machine to + PoStMaStEr@domain. Look for the message in ~alias/Mailbox. + + +That's it! To report success: + % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \ + | mail djb-qst@koobera.math.uic.edu +Replace First M. Last with your name. If you have questions about qmail, +contact qmail@pobox.com. diff --git a/VERSION b/VERSION @@ -0,0 +1 @@ +qmail 1.01 diff --git a/addresses.5 b/addresses.5 @@ -0,0 +1,260 @@ +.TH addresses 5 +.SH "NAME" +addresses \- formats for Internet mail addresses +.SH "INTRODUCTION" +A +.B mail address +is a string of characters containing @. + +Every mail address has a +.B local part +and a +.B domain part\fR. +The domain part is everything after the final @. +The local part is everything before. + +For example, the mail addresses + +.EX + God@heaven.af.mil + @heaven.af.mil + @at@@heaven.af.mil +.EE + +all have domain part +.BR heaven.af.mil . +The local parts are +.BR God , +empty, +and +.BR @at@ . + +Some domains have owners. +It is up to the owner of +.B heaven.af.mil +to say how mail messages will be delivered to addresses with domain part +.BR heaven.af.mil . + +The domain part of an address is interpreted without regard to case, so + +.EX + God@heaven.af.mil +.br + God@HEAVEN.AF.MIL +.br + God@Heaven.AF.Mil +.EE + +all refer to the same domain. + +There is one exceptional address that does not contain an @: +namely, the empty string. +The empty string cannot be used as a recipient address. +It can be used as a sender address so that +the real sender doesn't receive bounces. +.SH "QMAIL EXTENSIONS" +The +.B qmail +system allows several further types of addresses in mail envelopes. + +First, an envelope recipient address without an @ is interpreted as being at +.IR envnoathost . +For example, if +.I envnoathost +is +.BR heaven.af.mil , +the address +.B God +will be rewritten as +.BR God@heaven.af.mil . + +Second, the address +.B #@[] +is used as an envelope sender address for double bounces. + +Third, envelope sender addresses of the form +.I pre\fB@\fIhost\fB-@[] +are used to support variable envelope return paths (VERPs). +.B qmail-send +will rewrite +.I pre\fB@\fIhost\fB-@[] +as +.I prerecip\fB=\fIdomain\fB@\fIhost +for deliveries to +.IR recip\fB@\fIdomain . +Bounces directly from +.B qmail-send +will come back to +.IR pre\fB@\fIhost . +.SH "CHOOSING MAIL ADDRESSES" +Here are some suggestions on choosing mail addresses for the Internet. + +Do not use non-ASCII characters. +Under RFC 822 and RFC 821, +these characters cannot be used in mail headers or in SMTP commands. +In practice, they are regularly corrupted. + +Do not use ASCII control characters. +NUL is regularly corrupted. +CR and LF cannot be used in some combinations +and are corrupted in all. +None of these characters are usable on business cards. + +Avoid spaces and the characters + +.EX + \\"<>()[],;: +.EE + +These all require quoting in mail headers and in SMTP. +Many existing mail programs do not handle quoting properly. + +Do not use @ in a local part. +@ requires quoting in mail headers and in SMTP. +Many programs incorrectly look for the first @, +rather than the last @, +to find the domain part of an address. + +In a local part, +do not use two consecutive dots, a dot at the beginning, or a dot at the end. +Any of these would require quoting in mail headers. + +Do not use an empty local part; it cannot appear in SMTP commands. + +Avoid local parts longer than 64 characters. + +Be wary of uppercase letters in local parts. +Some mail programs (and users!) will incorrectly convert +.B God@heaven.af.mil +to +.BR god@heaven.af.mil . + +Be wary of the following characters: + +.EX + $&!#~`'^*|{} +.EE + +Some users will not know +how to feed these characters safely to their mail programs. + +In domain names, stick to letters, digits, dash, and dot. +One popular DNS resolver has, +under the banner of security, +recently begun destroying domain names +that contain certain other characters, +including underscore. +Exception: A dotted-decimal IP address in brackets, +such as +.BR [127.0.0.1] , +identifies a domain owned by whoever owns the host at that IP address, +and can be used safely. + +In a domain name, +do not use two consecutive dots, +a dot at the beginning, +or a dot at the end. +This means that, +when a domain name is broken down into components separated by dots, +there are no empty components. + +Always use at least one dot in a domain name. +If you own the +.B mil +domain, +don't bother using the address +.BR root@mil ; +most users will be unable to send messages to that address. +Same for the root domain. + +Avoid domain names longer than 64 characters. +.SH "ENCODED ADDRESSES IN SMTP COMMANDS" +RFC 821 defines an encoding of mail addresses in SMTP. +For example, the addresses + +.EX + God@heaven.af.mil +.br + a"quote@heaven.af.mil +.br + The Almighty.One@heaven.af.mil +.EE + +could be encoded in RCPT commands as + +.EX + RCPT TO:<God@heaven.af.mil> +.br + RCPT TO:<a\\"quote@heaven.af.mil> +.br + RCPT TO:<The\\ Almighty.One@heaven.af.mil> +.EE + +There are several restrictions in RFC 821 +on the mail addresses that can be used over SMTP. +Non-ASCII characters are prohibited. +The local part must not be empty. +The domain part must be a sequence of elements separated by dots, +where each element is either a component, +a sequence of digits preceded by #, +or a dotted-decimal IP address surrounded by brackets. +The only allowable characters in components are +letters, digits, and dashes. +Every component must (believe it or not) +have at least three characters; +the first character must be a letter; +the last character must not be a hyphen. +.SH "ENCODED ADDRESSES IN MAIL HEADERS" +RFC 822 defines an encoding of mail addresses +in certain header fields in a mail message. +For example, the addresses + +.EX + God@heaven.af.mil +.br + a"quote@heaven.af.mil +.br + The Almighty.One@heaven.af.mil +.EE + +could be encoded in a +.B To +field as + +.EX + To: God@heaven.af.mil, +.br + <@brl.mil:"a\\"quote"@heaven.af.mil>, +.br + "The Almighty".One@heaven.af.mil +.EE + +or perhaps + +.EX + To: < "God"@heaven .af.mil>, +.br + "a\\"quote" (Who?) @ heaven . af. mil +.br + , God<"The Almighty.One"@heaven.af.mil> +.EE + +There are several restrictions on the mail addresses that can +be used in these header fields. +Non-ASCII characters are prohibited. +The domain part must be a sequence of elements separated by dots, +where each element either (1) begins with [ and ends with ] +or (2) is a nonempty string of printable ASCII characters +not including any of + +.EX + \\".<>()[],;: +.EE + +and not including space. +.SH "SEE ALSO" +envelopes(5), +qmail-header(5), +qmail-inject(8), +qmail-remote(8), +qmail-smtpd(8) diff --git a/alloc.3 b/alloc.3 @@ -0,0 +1,62 @@ +.TH alloc 3 +.SH NAME +alloc \- allocate memory +.SH SYNTAX +.B #include <alloc.h> + +char *\fBalloc\fP(\fInew\fR); + +void \fBalloc_free\fP(\fIx\fR); + +void \fBalloc_re\fP(&\fIx\fR,\fIold\fR,\fInew\fR); + +char *\fIx\fR; +.br +unsigned int \fIold\fR; +.br +unsigned int \fInew\fR; +.SH DESCRIPTION +.B alloc +allocates enough space from the heap for +.I new +bytes of data, +adequately aligned for any data type. +.I new +may be 0. +.B alloc +returns a pointer to the space. +If space is not available, +.B alloc +returns 0, +setting +.B errno +appropriately. + +.B alloc_free +returns space to the heap. + +.B alloc_re +expands the space allocated to +.I x +from +.I old +bytes to +.I new +bytes. +It allocates new space, +copies +.I old +bytes from the old space to the new space, +returns the old space to the heap, +and changes +.I x +to point to the new space. +It then returns 1. +If space is not available, +.B alloc_re +returns 0, +leaving the old space alone. +.SH "SEE ALSO" +sbrk(2), +malloc(3), +error(3) diff --git a/alloc.c b/alloc.c @@ -0,0 +1,32 @@ +#include "alloc.h" +#include "error.h" +extern char *malloc(); +extern void free(); + +#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */ +#define SPACE 4096 /* must be multiple of ALIGNMENT */ + +typedef union { char irrelevant[ALIGNMENT]; double d; } aligned; +static aligned realspace[SPACE / ALIGNMENT]; +#define space ((char *) realspace) +static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */ + +/*@null@*//*@out@*/char *alloc(n) +unsigned int n; +{ + char *x; + n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */ + if (n <= avail) { avail -= n; return space + avail; } + x = malloc(n); + if (!x) errno = error_nomem; + return x; +} + +void alloc_free(x) +char *x; +{ + if (x >= space) + if (x < space + SPACE) + return; /* XXX: assuming that pointers are flat */ + free(x); +} diff --git a/alloc.h b/alloc.h @@ -0,0 +1,8 @@ +#ifndef ALLOC_H +#define ALLOC_H + +extern /*@null@*//*@out@*/char *alloc(); +extern void alloc_free(); +extern int alloc_re(); + +#endif diff --git a/alloc_re.c b/alloc_re.c @@ -0,0 +1,17 @@ +#include "alloc.h" +#include "byte.h" + +int alloc_re(x,m,n) +char **x; +unsigned int m; +unsigned int n; +{ + char *y; + + y = alloc(n); + if (!y) return 0; + byte_copy(y,m,*x); + alloc_free(*x); + *x = y; + return 1; +} diff --git a/auto-gid.c b/auto-gid.c @@ -0,0 +1,51 @@ +#include <sys/types.h> +#include <grp.h> +#include "subfd.h" +#include "substdio.h" +#include "readwrite.h" +#include "exit.h" +#include "scan.h" +#include "fmt.h" + +char buf1[256]; +substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); + +void outs(s) +char *s; +{ + if (substdio_puts(&ss1,s) == -1) _exit(111); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *name; + char *value; + struct group *gr; + char strnum[FMT_ULONG]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + gr = getgrnam(value); + if (!gr) { + substdio_puts(subfderr,"fatal: unable to find group "); + substdio_puts(subfderr,value); + substdio_puts(subfderr,"\n"); + substdio_flush(subfderr); + _exit(111); + } + + strnum[fmt_ulong(strnum,(unsigned long) gr->gr_gid)] = 0; + + outs("int "); + outs(name); + outs(" = "); + outs(strnum); + outs(";\n"); + if (substdio_flush(&ss1) == -1) _exit(111); + _exit(0); +} diff --git a/auto-int.c b/auto-int.c @@ -0,0 +1,40 @@ +#include "substdio.h" +#include "readwrite.h" +#include "exit.h" +#include "scan.h" +#include "fmt.h" + +char buf1[256]; +substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); + +void puts(s) +char *s; +{ + if (substdio_puts(&ss1,s) == -1) _exit(111); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *name; + char *value; + unsigned long num; + char strnum[FMT_ULONG]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + scan_ulong(value,&num); + strnum[fmt_ulong(strnum,num)] = 0; + + puts("int "); + puts(name); + puts(" = "); + puts(strnum); + puts(";\n"); + if (substdio_flush(&ss1) == -1) _exit(111); + _exit(0); +} diff --git a/auto-int8.c b/auto-int8.c @@ -0,0 +1,40 @@ +#include "substdio.h" +#include "readwrite.h" +#include "exit.h" +#include "scan.h" +#include "fmt.h" + +char buf1[256]; +substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); + +void puts(s) +char *s; +{ + if (substdio_puts(&ss1,s) == -1) _exit(111); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *name; + char *value; + unsigned long num; + char strnum[FMT_ULONG]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + scan_8long(value,&num); + strnum[fmt_ulong(strnum,num)] = 0; + + puts("int "); + puts(name); + puts(" = "); + puts(strnum); + puts(";\n"); + if (substdio_flush(&ss1) == -1) _exit(111); + _exit(0); +} diff --git a/auto-str.c b/auto-str.c @@ -0,0 +1,44 @@ +#include "substdio.h" +#include "readwrite.h" +#include "exit.h" + +char buf1[256]; +substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); + +void puts(s) +char *s; +{ + if (substdio_puts(&ss1,s) == -1) _exit(111); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *name; + char *value; + unsigned char ch; + char octal[4]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + puts("char "); + puts(name); + puts("[] = \"\\\n"); + + while (ch = *value++) { + puts("\\"); + octal[3] = 0; + octal[2] = '0' + (ch & 7); ch >>= 3; + octal[1] = '0' + (ch & 7); ch >>= 3; + octal[0] = '0' + (ch & 7); + puts(octal); + } + + puts("\\\n\";\n"); + if (substdio_flush(&ss1) == -1) _exit(111); + _exit(0); +} diff --git a/auto-uid.c b/auto-uid.c @@ -0,0 +1,51 @@ +#include <sys/types.h> +#include <pwd.h> +#include "subfd.h" +#include "substdio.h" +#include "readwrite.h" +#include "exit.h" +#include "scan.h" +#include "fmt.h" + +char buf1[256]; +substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1)); + +void outs(s) /* was named puts, but Solaris pwd.h includes stdio.h. dorks. */ +char *s; +{ + if (substdio_puts(&ss1,s) == -1) _exit(111); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *name; + char *value; + struct passwd *pw; + char strnum[FMT_ULONG]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + pw = getpwnam(value); + if (!pw) { + substdio_puts(subfderr,"fatal: unable to find user "); + substdio_puts(subfderr,value); + substdio_puts(subfderr,"\n"); + substdio_flush(subfderr); + _exit(111); + } + + strnum[fmt_ulong(strnum,(unsigned long) pw->pw_uid)] = 0; + + outs("int "); + outs(name); + outs(" = "); + outs(strnum); + outs(";\n"); + if (substdio_flush(&ss1) == -1) _exit(111); + _exit(0); +} diff --git a/auto_break.h b/auto_break.h @@ -0,0 +1,6 @@ +#ifndef AUTO_BREAK_H +#define AUTO_BREAK_H + +extern char auto_break[]; + +#endif diff --git a/auto_patrn.h b/auto_patrn.h @@ -0,0 +1,6 @@ +#ifndef AUTO_PATRN_H +#define AUTO_PATRN_H + +extern int auto_patrn; + +#endif diff --git a/auto_qmail.h b/auto_qmail.h @@ -0,0 +1,6 @@ +#ifndef AUTO_QMAIL_H +#define AUTO_QMAIL_H + +extern char auto_qmail[]; + +#endif diff --git a/auto_spawn.h b/auto_spawn.h @@ -0,0 +1,6 @@ +#ifndef AUTO_SPAWN_H +#define AUTO_SPAWN_H + +extern int auto_spawn; + +#endif diff --git a/auto_split.h b/auto_split.h @@ -0,0 +1,6 @@ +#ifndef AUTO_SPLIT_H +#define AUTO_SPLIT_H + +extern int auto_split; + +#endif diff --git a/auto_uids.h b/auto_uids.h @@ -0,0 +1,16 @@ +#ifndef AUTO_UIDS_H +#define AUTO_UIDS_H + +extern int auto_uida; +extern int auto_uidd; +extern int auto_uidl; +extern int auto_uido; +extern int auto_uidp; +extern int auto_uidq; +extern int auto_uidr; +extern int auto_uids; + +extern int auto_gidn; +extern int auto_gidq; + +#endif diff --git a/auto_usera.h b/auto_usera.h @@ -0,0 +1,6 @@ +#ifndef AUTO_USERA_H +#define AUTO_USERA_H + +extern char auto_usera[]; + +#endif diff --git a/byte.h b/byte.h @@ -0,0 +1,13 @@ +#ifndef BYTE_H +#define BYTE_H + +extern unsigned int byte_chr(); +extern unsigned int byte_rchr(); +extern void byte_copy(); +extern void byte_copyr(); +extern int byte_diff(); +extern void byte_zero(); + +#define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) + +#endif diff --git a/byte_chr.c b/byte_chr.c @@ -0,0 +1,20 @@ +#include "byte.h" + +unsigned int byte_chr(s,n,c) +char *s; +register unsigned int n; +int c; +{ + register char ch; + register char *t; + + ch = c; + t = s; + for (;;) { + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + } + return t - s; +} diff --git a/byte_copy.c b/byte_copy.c @@ -0,0 +1,14 @@ +#include "byte.h" + +void byte_copy(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + for (;;) { + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + } +} diff --git a/byte_cr.c b/byte_cr.c @@ -0,0 +1,16 @@ +#include "byte.h" + +void byte_copyr(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + to += n; + from += n; + for (;;) { + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + } +} diff --git a/byte_diff.c b/byte_diff.c @@ -0,0 +1,16 @@ +#include "byte.h" + +int byte_diff(s,n,t) +register char *s; +register unsigned int n; +register char *t; +{ + for (;;) { + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + } + return ((int)(unsigned int)(unsigned char) *s) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/byte_rchr.c b/byte_rchr.c @@ -0,0 +1,23 @@ +#include "byte.h" + +unsigned int byte_rchr(s,n,c) +char *s; +register unsigned int n; +int c; +{ + register char ch; + register char *t; + register char *u; + + ch = c; + t = s; + u = 0; + for (;;) { + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + if (!n) break; if (*t == ch) u = t; ++t; --n; + } + if (!u) u = t; + return u - s; +} diff --git a/byte_zero.c b/byte_zero.c @@ -0,0 +1,13 @@ +#include "byte.h" + +void byte_zero(s,n) +char *s; +register unsigned int n; +{ + for (;;) { + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + } +} diff --git a/case.3 b/case.3 @@ -0,0 +1,100 @@ +.TH case 3 +.SH NAME +case \- convert ASCII uppercase bytes to lowercase +.SH SYNTAX +.B #include <case.h> + +void \fBcase_lowers\fP(\fIs\fR); +.br +void \fBcase_lowerb\fP(\fIs\fR,\fIlen\fR); + +int \fBcase_diffs\fP(\fIs\fR,\fIt\fR); +.br +int \fBcase_equals\fP(\fIs\fR,\fIt\fR); +.br +int \fBcase_starts\fP(\fIs\fR,\fIt\fR); + +int \fBcase_diffb\fP(\fIs\fR,\fIlen\fR,\fIt\fR); +.br +int \fBcase_startb\fP(\fIs\fR,\fIlen\fR,\fIt\fR); + +char *\fIs\fR; +.br +char *\fIt\fR; +.br +unsigned int \fIlen\fR; +.SH DESCRIPTION +.B case_lowers +converts each uppercase byte in the string +.I s +to lowercase. +.I s +must be 0-terminated. + +.B case_lowerb +converts each uppercase byte in the buffer +.IR s , +of length +.IR len , +to lowercase. + +.B case_diffs +lexicographically compares lowercase versions of the strings +.I s +and +.IR t . +It returns something positive, negative, or zero +when the first is larger than, smaller than, or equal to the second. +.I s +and +.I t +must be 0-terminated. + +.B case_equals +means +.BR !case_diffs . + +.B case_starts +returns 1 if a lowercase version of +.I s +starts with a lowercase version of +.IR t . +.I s +and +.I t +must be 0-terminated. + +.B case_diffb +lexicographically compares lowercase versions of the buffers +.I s +and +.IR t , +each of length +.IR len . +It returns something positive, negative, or zero +when the first is larger than, smaller than, or equal to the second. + +.B case_startb +returns 1 if a lowercase version of the buffer +.IR s , +of length +.IR len , +starts with a lowercase version of the string +.IR t . +.I t +must be 0-terminated. + +The +.B case +routines +are ASCII-specific. +They are suitable for programs that handle +case-independent networking protocols. + +All comparisons are performed on unsigned bytes. +.SH "SEE ALSO" +byte_diff(3), +byte_equal(3), +str_diff(3), +str_equal(3), +str_start(3) diff --git a/case.h b/case.h @@ -0,0 +1,13 @@ +#ifndef CASE_H +#define CASE_H + +extern void case_lowers(); +extern void case_lowerb(); +extern int case_diffs(); +extern int case_diffb(); +extern int case_starts(); +extern int case_startb(); + +#define case_equals(s,t) (!case_diffs((s),(t))) + +#endif diff --git a/case_diffb.c b/case_diffb.c @@ -0,0 +1,21 @@ +#include "case.h" + +int case_diffb(s,len,t) +register char *s; +unsigned int len; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + while (len > 0) { + --len; + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (x != y) + return ((int)(unsigned int) x) - ((int)(unsigned int) y); + } + return 0; +} diff --git a/case_diffs.c b/case_diffs.c @@ -0,0 +1,19 @@ +#include "case.h" + +int case_diffs(s,t) +register char *s; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + for (;;) { + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (x != y) break; + if (!x) break; + } + return ((int)(unsigned int) x) - ((int)(unsigned int) y); +} diff --git a/case_lowerb.c b/case_lowerb.c @@ -0,0 +1,14 @@ +#include "case.h" + +void case_lowerb(s,len) +char *s; +unsigned int len; +{ + unsigned char x; + while (len > 0) { + --len; + x = *s - 'A'; + if (x <= 'Z' - 'A') *s = x + 'a'; + ++s; + } +} diff --git a/case_lowers.c b/case_lowers.c @@ -0,0 +1,12 @@ +#include "case.h" + +void case_lowers(s) +char *s; +{ + unsigned char x; + while (x = *s) { + x -= 'A'; + if (x <= 'Z' - 'A') *s = x + 'a'; + ++s; + } +} diff --git a/case_starts.c b/case_starts.c @@ -0,0 +1,18 @@ +#include "case.h" + +int case_starts(s,t) +register char *s; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + for (;;) { + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (!y) return 1; + if (x != y) return 0; + } +} diff --git a/cdb.3 b/cdb.3 @@ -0,0 +1,62 @@ +.TH cdb 3 +.SH NAME +cdb \- read from a constant database +.SH SYNTAX +.B #include <cdb.h> + +int \fBcdb_seek(\fP\fIfd,key,len,dlen\fR\fB)\fP; + +int \fIfd\fR; +.br +char *\fIkey\fR; +.br +unsigned int \fIlen\fR; +.br +uint32 *\fIdlen\fR; +.SH DESCRIPTION +.B cdb_seek +looks up +.I key +in a constant database. +It returns 1 if +.I key +is present, +0 if +.I key +is not present, +or \-1 if there was a read error. +.I key +is an array of +.I len +characters. + +.B cdb_seek +needs an open file descriptor, +.IR fd , +pointing to the database. +If +.B cdb_seek +returns 1, +it points +.I fd +at the beginning of the data portion of the first record +indexed by +.IR key , +and it stores the data length in +.IR dlen. +.B cdb_seek +does not provide a way to read subsequent records with the same key. + +It's fine to do several +.B cdb_seek +lookups with the same open file descriptor. +Beware, however, that two simultaneous +.B cdb_seek +lookups can fail horribly; +separate processes should not share the same database descriptor. +Furthermore, any updates after the database was opened +will be invisible. +It's rarely a good idea for a long-running program +to hold a database open. +.SH "SEE ALSO" +cdbget(1) diff --git a/cdb.h b/cdb.h @@ -0,0 +1,12 @@ +#ifndef CDB_H +#define CDB_H + +#include "uint32.h" + +extern uint32 cdb_hash(); +extern uint32 cdb_unpack(); + +extern int cdb_bread(); +extern int cdb_seek(); + +#endif diff --git a/cdb_hash.c b/cdb_hash.c @@ -0,0 +1,16 @@ +#include "cdb.h" + +uint32 cdb_hash(buf,len) +unsigned char *buf; +unsigned int len; +{ + uint32 h; + + h = 5381; + while (len) { + --len; + h += (h << 5); + h ^= (uint32) *buf++; + } + return h; +} diff --git a/cdb_seek.c b/cdb_seek.c @@ -0,0 +1,95 @@ +#include <sys/types.h> +#include <errno.h> +extern int errno; +#include "cdb.h" + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +int cdb_bread(fd,buf,len) +int fd; +char *buf; +int len; +{ + int r; + while (len > 0) { + do + r = read(fd,buf,len); + while ((r == -1) && (errno == EINTR)); + if (r == -1) return -1; + if (r == 0) { errno = EIO; return -1; } + buf += r; + len -= r; + } + return 0; +} + +static int match(fd,key,len) +int fd; +char *key; +unsigned int len; +{ + char buf[32]; + int n; + int i; + + while (len > 0) { + n = sizeof(buf); + if (n > len) n = len; + if (cdb_bread(fd,buf,n) == -1) return -1; + for (i = 0;i < n;++i) if (buf[i] != key[i]) return 0; + key += n; + len -= n; + } + return 1; +} + +int cdb_seek(fd,key,len,dlen) +int fd; +char *key; +unsigned int len; +uint32 *dlen; +{ + char packbuf[8]; + uint32 pos; + uint32 h; + uint32 lenhash; + uint32 h2; + uint32 loop; + uint32 poskd; + + h = cdb_hash(key,len); + + pos = 8 * (h & 255); + if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1; + + if (cdb_bread(fd,packbuf,8) == -1) return -1; + + pos = cdb_unpack(packbuf); + lenhash = cdb_unpack(packbuf + 4); + + if (!lenhash) return 0; + h2 = (h >> 8) % lenhash; + + for (loop = 0;loop < lenhash;++loop) { + if (lseek(fd,(off_t) (pos + 8 * h2),SEEK_SET) == -1) return -1; + if (cdb_bread(fd,packbuf,8) == -1) return -1; + poskd = cdb_unpack(packbuf + 4); + if (!poskd) return 0; + if (cdb_unpack(packbuf) == h) { + if (lseek(fd,(off_t) poskd,SEEK_SET) == -1) return -1; + if (cdb_bread(fd,packbuf,8) == -1) return -1; + if (cdb_unpack(packbuf) == len) + switch(match(fd,key,len)) { + case -1: + return -1; + case 1: + *dlen = cdb_unpack(packbuf + 4); + return 1; + } + } + if (++h2 == lenhash) h2 = 0; + } + return 0; +} diff --git a/cdb_unpack.c b/cdb_unpack.c @@ -0,0 +1,12 @@ +#include "cdb.h" + +uint32 cdb_unpack(buf) +unsigned char *buf; +{ + uint32 num; + num = buf[3]; num <<= 8; + num += buf[2]; num <<= 8; + num += buf[1]; num <<= 8; + num += buf[0]; + return num; +} diff --git a/cdbmake.h b/cdbmake.h @@ -0,0 +1,35 @@ +#ifndef CDBMAKE_H +#define CDBMAKE_H + +#include "uint32.h" + +#define CDBMAKE_HPLIST 1000 + +struct cdbmake_hp { uint32 h; uint32 p; } ; + +struct cdbmake_hplist { + struct cdbmake_hp hp[CDBMAKE_HPLIST]; + struct cdbmake_hplist *next; + int num; +} ; + +struct cdbmake { + char final[2048]; + uint32 count[256]; + uint32 start[256]; + struct cdbmake_hplist *head; + struct cdbmake_hp *split; /* includes space for hash */ + struct cdbmake_hp *hash; + uint32 numentries; +} ; + +extern void cdbmake_pack(); +#define CDBMAKE_HASHSTART ((uint32) 5381) +extern uint32 cdbmake_hashadd(); + +extern void cdbmake_init(); +extern int cdbmake_add(); +extern int cdbmake_split(); +extern uint32 cdbmake_throw(); + +#endif diff --git a/cdbmake_add.c b/cdbmake_add.c @@ -0,0 +1,117 @@ +#include "cdbmake.h" + +void cdbmake_init(cdbm) +struct cdbmake *cdbm; +{ + cdbm->head = 0; + cdbm->split = 0; + cdbm->hash = 0; + cdbm->numentries = 0; +} + +int cdbmake_add(cdbm,h,p,alloc) +struct cdbmake *cdbm; +uint32 h; +uint32 p; +char *(*alloc)(); +{ + struct cdbmake_hplist *head; + + head = cdbm->head; + if (!head || (head->num >= CDBMAKE_HPLIST)) { + head = (struct cdbmake_hplist *) alloc(sizeof(struct cdbmake_hplist)); + if (!head) return 0; + head->num = 0; + head->next = cdbm->head; + cdbm->head = head; + } + head->hp[head->num].h = h; + head->hp[head->num].p = p; + ++head->num; + ++cdbm->numentries; + return 1; +} + +int cdbmake_split(cdbm,alloc) +struct cdbmake *cdbm; +char *(*alloc)(); +{ + int i; + uint32 u; + uint32 memsize; + struct cdbmake_hplist *x; + + for (i = 0;i < 256;++i) + cdbm->count[i] = 0; + + for (x = cdbm->head;x;x = x->next) { + i = x->num; + while (i--) + ++cdbm->count[255 & x->hp[i].h]; + } + + memsize = 1; + for (i = 0;i < 256;++i) { + u = cdbm->count[i] * 2; + if (u > memsize) + memsize = u; + } + + memsize += cdbm->numentries; /* no overflow possible up to now */ + u = (uint32) 0 - (uint32) 1; + u /= sizeof(struct cdbmake_hp); + if (memsize > u) return 0; + + cdbm->split = (struct cdbmake_hp *) alloc(memsize * sizeof(struct cdbmake_hp)); + if (!cdbm->split) return 0; + + cdbm->hash = cdbm->split + cdbm->numentries; + + u = 0; + for (i = 0;i < 256;++i) { + u += cdbm->count[i]; /* bounded by numentries, so no overflow */ + cdbm->start[i] = u; + } + + for (x = cdbm->head;x;x = x->next) { + i = x->num; + while (i--) + cdbm->split[--cdbm->start[255 & x->hp[i].h]] = x->hp[i]; + } + + return 1; +} + +uint32 cdbmake_throw(cdbm,pos,b) +struct cdbmake *cdbm; +uint32 pos; +int b; +{ + uint32 len; + uint32 j; + uint32 count; + struct cdbmake_hp *hp; + uint32 where; + + count = cdbm->count[b]; + + len = count + count; /* no overflow possible */ + cdbmake_pack(cdbm->final + 8 * b,pos); + cdbmake_pack(cdbm->final + 8 * b + 4,len); + + if (len) { + for (j = 0;j < len;++j) + cdbm->hash[j].h = cdbm->hash[j].p = 0; + + hp = cdbm->split + cdbm->start[b]; + for (j = 0;j < count;++j) { + where = (hp->h >> 8) % len; + while (cdbm->hash[where].p) + if (++where == len) + where = 0; + cdbm->hash[where] = *hp++; + } + } + + return len; +} diff --git a/cdbmake_hash.c b/cdbmake_hash.c @@ -0,0 +1,10 @@ +#include "cdbmake.h" + +uint32 cdbmake_hashadd(h,c) +uint32 h; +unsigned int c; +{ + h += (h << 5); + h ^= (uint32) (unsigned char) c; + return h; +} diff --git a/cdbmake_pack.c b/cdbmake_pack.c @@ -0,0 +1,11 @@ +#include "cdbmake.h" + +void cdbmake_pack(buf,num) +unsigned char *buf; +uint32 num; +{ + *buf++ = num; num >>= 8; + *buf++ = num; num >>= 8; + *buf++ = num; num >>= 8; + *buf = num; +} diff --git a/cdbmss.c b/cdbmss.c @@ -0,0 +1,65 @@ +#include "readwrite.h" +#include "seek.h" +#include "alloc.h" +#include "cdbmss.h" + +int cdbmss_start(c,fd) +struct cdbmss *c; +int fd; +{ + cdbmake_init(&c->cdbm); + c->fd = fd; + c->pos = sizeof(c->cdbm.final); + substdio_fdbuf(&c->ss,write,fd,c->ssbuf,sizeof(c->ssbuf)); + return seek_set(fd,(seek_pos) c->pos); +} + +int cdbmss_add(c,key,keylen,data,datalen) +struct cdbmss *c; +unsigned char *key; +unsigned int keylen; +unsigned char *data; +unsigned int datalen; +{ + uint32 h; + int i; + + cdbmake_pack(c->packbuf,(uint32) keylen); + cdbmake_pack(c->packbuf + 4,(uint32) datalen); + if (substdio_put(&c->ss,c->packbuf,8) == -1) return -1; + if (substdio_put(&c->ss,key,keylen) == -1) return -1; + if (substdio_put(&c->ss,data,datalen) == -1) return -1; + + h = CDBMAKE_HASHSTART; + for (i = 0;i < keylen;++i) + h = cdbmake_hashadd(h,(unsigned int) key[i]); + + if (!cdbmake_add(&c->cdbm,h,c->pos,alloc)) return -1; + + c->pos += 8 + keylen + datalen; /* XXX: overflow? */ + return 0; +} + +int cdbmss_finish(c) +struct cdbmss *c; +{ + int i; + uint32 len; + uint32 u; + + if (!cdbmake_split(&c->cdbm,alloc)) return -1; + + for (i = 0;i < 256;++i) { + len = cdbmake_throw(&c->cdbm,c->pos,i); + for (u = 0;u < len;++u) { + cdbmake_pack(c->packbuf,c->cdbm.hash[u].h); + cdbmake_pack(c->packbuf + 4,c->cdbm.hash[u].p); + if (substdio_put(&c->ss,c->packbuf,8) == -1) return -1; + c->pos += 8; /* XXX: overflow? */ + } + } + + if (substdio_flush(&c->ss) == -1) return -1; + if (seek_begin(c->fd) == -1) return -1; + return substdio_putflush(&c->ss,c->cdbm.final,sizeof(c->cdbm.final)); +} diff --git a/cdbmss.h b/cdbmss.h @@ -0,0 +1,16 @@ +#ifndef CDBMSS_H +#define CDBMSS_H + +#include "cdbmake.h" +#include "substdio.h" + +struct cdbmss { + char ssbuf[1024]; + struct cdbmake cdbm; + substdio ss; + char packbuf[8]; + uint32 pos; + int fd; +} ; + +#endif diff --git a/chkshsgr.c b/chkshsgr.c @@ -0,0 +1,9 @@ +#include "exit.h" +void main() +{ + short x[4]; + + x[0] = x[1] = 0; + if (getgroups(1,x) == 0) if (setgroups(1,x) == -1) _exit(1); + _exit(0); +} diff --git a/chkspawn.c b/chkspawn.c @@ -0,0 +1,48 @@ +#include "substdio.h" +#include "subfd.h" +#include "fmt.h" +#include "select.h" +#include "exit.h" +#include "auto_spawn.h" + +char num[FMT_ULONG]; +fd_set fds; + +void main() +{ + unsigned long hiddenlimit; + unsigned long maxnumd; + + hiddenlimit = sizeof(fds) * 8; + maxnumd = (hiddenlimit - 5) / 2; + + if (auto_spawn < 1) { + substdio_puts(subfderr,"Oops. You have set conf-spawn lower than 1.\n"); + substdio_flush(subfderr); + _exit(1); + } + + if (auto_spawn > 255) { + substdio_puts(subfderr,"Oops. You have set conf-spawn higher than 255.\n"); + substdio_flush(subfderr); + _exit(1); + } + + if (auto_spawn > maxnumd) { + substdio_puts(subfderr,"Oops. Your system's FD_SET() has a hidden limit of "); + substdio_put(subfderr,num,fmt_ulong(num,hiddenlimit)); + substdio_puts(subfderr," descriptors.\n\ +This means that the qmail daemons could crash if you set the run-time\n\ +concurrency higher than "); + substdio_put(subfderr,num,fmt_ulong(num,maxnumd)); + substdio_puts(subfderr,". So I'm going to insist that the concurrency\n\ +limit in conf-spawn be at most "); + substdio_put(subfderr,num,fmt_ulong(num,maxnumd)); + substdio_puts(subfderr,". Right now it's "); + substdio_put(subfderr,num,fmt_ulong(num,(unsigned long) auto_spawn)); + substdio_puts(subfderr,".\n"); + substdio_flush(subfderr); + _exit(1); + } + _exit(0); +} diff --git a/coe.3 b/coe.3 @@ -0,0 +1,25 @@ +.TH coe 3 +.SH NAME +coe \- set close-on-exec flag for a descriptor +.SH SYNTAX +.B #include <coe.h> + +int \fBcoe\fP(\fIfd\fR); + +int \fIfd\fR; +.SH DESCRIPTION +.B coe +sets the close-on-exec flag for +file descriptor +.IR fd , +returning 0 if it was successful +or -1 on error. +If +.B coe +is successful, +.I fd +will be closed when the process calls +.BR execve . +.SH "SEE ALSO" +execve(2), +fcntl(2) diff --git a/coe.c b/coe.c @@ -0,0 +1,8 @@ +#include <fcntl.h> +#include "coe.h" + +int coe(fd) +int fd; +{ + return fcntl(fd,F_SETFD,1); +} diff --git a/coe.h b/coe.h @@ -0,0 +1,6 @@ +#ifndef COE_H +#define COE_H + +extern int coe(); + +#endif diff --git a/condredirect.1 b/condredirect.1 @@ -0,0 +1,54 @@ +.TH condredirect 1 +.SH NAME +condredirect \- perhaps redirect mail to another address +.SH SYNOPSIS +in +.BR .qmail : +.B |condredirect +.I newaddress +.I program +[ +.I arg ... +] +.SH DESCRIPTION +.B condredirect +feeds each new mail message to +.I program +with the given arguments. +If +.I program +exits 0, +.B condredirect +forwards the mail message to +.IR newaddress , +and then exits 99, +so further commands in +.B .qmail +are ignored. + +If +.I program +exits 111, +.B condredirect +exits 111, +so delivery will be retried later. + +If +.I program +exits anything else +(or does not exist), +.B condredirect +exits 0, +so the rest of +.B .qmail +will be processed as usual. + +Note that +it is not safe for +.I program +to fork a child that +reads the message in the background. +.SH "SEE ALSO" +dot-qmail(5), +qmail-command(8), +qmail-queue(8) diff --git a/condredirect.c b/condredirect.c @@ -0,0 +1,87 @@ +#include "sig.h" +#include "readwrite.h" +#include "exit.h" +#include "env.h" +#include "error.h" +#include "fork.h" +#include "wait.h" +#include "seek.h" +#include "qmail.h" +#include "stralloc.h" +#include "subfd.h" +#include "substdio.h" + +void die_success() { _exit(0); } +void die_99() { _exit(99); } +void die_perm(s) char *s; { substdio_putsflush(subfderr,s); _exit(100); } +void die_temp(s) char *s; { substdio_putsflush(subfderr,s); _exit(111); } +void die_nomem() { die_temp("condredirect: fatal: out of memory\n"); } + +struct qmail qqt; + +int mywrite(fd,buf,len) int fd; char *buf; int len; +{ + qmail_put(&qqt,buf,len); + return len; +} + +substdio ssin; +substdio ssout; +char inbuf[SUBSTDIO_INSIZE]; +char outbuf[16]; + +void main(argc,argv) +int argc; +char **argv; +{ + char *sender; + char *dtline; + int pid; + int wstat; + + if (!argv[1] || !argv[2]) + die_perm("condredirect: usage: condredirect newaddress program arg ...\n"); + + switch(pid = fork()) + { + case -1: die_temp("condredirect: fatal: unable to fork\n"); + case 0: + execvp(argv[2],argv + 2); + if (error_temp(errno)) _exit(111); + _exit(100); + } + if (wait_pid(&wstat,pid) != pid) + die_perm("condredirect: fatal: internal bug\n"); + if (wait_crashed(wstat)) die_temp("condredirect: fatal: child crashed\n"); + switch(wait_exitcode(wstat)) + { + case 0: break; + case 111: die_temp("condredirect: fatal: temporary child error\n"); + default: die_success(); + } + + if (seek_begin(0) == -1) die_temp("condredirect: fatal: unable to rewind\n"); + sig_pipeignore(); + + sender = env_get("SENDER"); + if (!sender) die_perm("condredirect: fatal: SENDER not set\n"); + dtline = env_get("DTLINE"); + if (!dtline) die_perm("condredirect: fatal: DTLINE not set\n"); + + if (qmail_open(&qqt) == -1) die_temp("condredirect: fatal: unable to fork\n"); + qmail_puts(&qqt,dtline); + substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf)); + substdio_fdbuf(&ssout,mywrite,-1,outbuf,sizeof(outbuf)); + if (substdio_copy(&ssout,&ssin) != 0) + die_temp("condredirect: fatal: error while reading message\n"); + substdio_flush(&ssout); + + qmail_from(&qqt,sender); + qmail_to(&qqt,argv[1]); + switch(qmail_close(&qqt)) + { + case 0: die_99(); + case QMAIL_TOOLONG: die_perm("condredirect: fatal: permanent qmail-queue error\n"); + default: die_temp("condredirect: fatal: temporary qmail-queue error\n"); + } +} diff --git a/conf-break b/conf-break @@ -0,0 +1,9 @@ +- + +This character is the user-ext delimiter. The default delimiter is -, +meaning that user joe controls joe-anything. Some system administrators +prefer + or =. + +You can override this choice at run time with the qmail-users mechanism. + +Multicharacter delimiters are not permitted. diff --git a/conf-cc b/conf-cc @@ -0,0 +1,3 @@ +cc -O2 + +This will be used to compile .c files. diff --git a/conf-groups b/conf-groups @@ -0,0 +1,6 @@ +qmail +nofiles + +These are the qmail groups. The second group should not have access to +any files, but it must be usable for processes; this requirement +excludes the ``nogroup'' and ``nobody'' groups on many systems. diff --git a/conf-ld b/conf-ld @@ -0,0 +1,3 @@ +cc -s + +This will be used to link .o files into an executable. diff --git a/conf-patrn b/conf-patrn @@ -0,0 +1,5 @@ +022 + +These stat bits are not allowed in ~ and ~/.qmail. + +Note that ~ftp, ~www, ~uucp, etc. should be owned by root. diff --git a/conf-qmail b/conf-qmail @@ -0,0 +1,4 @@ +/var/qmail + +This is the qmail home directory. It must be a local directory, not +shared among machines. This is where qmail queues all mail messages. diff --git a/conf-spawn b/conf-spawn @@ -0,0 +1,5 @@ +120 + +This is a silent concurrency limit. You can't set it above 255. On some +systems you can't set it above 125. qmail will refuse to compile if the +limit is too high. diff --git a/conf-split b/conf-split @@ -0,0 +1,3 @@ +23 + +This is the queue subdirectory split. diff --git a/conf-users b/conf-users @@ -0,0 +1,15 @@ +alias +qmaild +qmaill +root +qmailp +qmailq +qmailr +qmails + +The qmail system is heavily partitioned for security; it does almost +nothing as root. + +The first eight lines of this file are the alias user, the daemon user, +the log user, the owner of miscellaneous files such as binaries, the +passwd user, the queue user, the remote user, and the send user. diff --git a/constmap.c b/constmap.c @@ -0,0 +1,123 @@ +#include "constmap.h" +#include "alloc.h" +#include "case.h" + +static constmap_hash hash(s,len) +char *s; +int len; +{ + unsigned char ch; + constmap_hash h; + h = 5381; + while (len > 0) + { + ch = *s++ - 'A'; + if (ch <= 'Z' - 'A') ch += 'a' - 'A'; + h = ((h << 5) + h) ^ ch; + --len; + } + return h; +} + +char *constmap(cm,s,len) +struct constmap *cm; +char *s; +int len; +{ + constmap_hash h; + int pos; + h = hash(s,len); + pos = cm->first[h & cm->mask]; + while (pos != -1) + { + if (h == cm->hash[pos]) + if (len == cm->inputlen[pos]) + if (!case_diffb(cm->input[pos],len,s)) + return cm->input[pos] + cm->inputlen[pos] + 1; + pos = cm->next[pos]; + } + return 0; +} + +int constmap_init(cm,s,len,flagcolon) +struct constmap *cm; +char *s; +int len; +int flagcolon; +{ + int i; + int j; + int k; + int pos; + constmap_hash h; + + cm->num = 0; + for (j = 0;j < len;++j) if (!s[j]) ++cm->num; + + h = 64; + while (h && (h < cm->num)) h += h; + cm->mask = h - 1; + + cm->first = (int *) alloc(sizeof(int) * h); + if (cm->first) + { + cm->input = (char **) alloc(sizeof(char *) * cm->num); + if (cm->input) + { + cm->inputlen = (int *) alloc(sizeof(int) * cm->num); + if (cm->inputlen) + { + cm->hash = (constmap_hash *) alloc(sizeof(constmap_hash) * cm->num); + if (cm->hash) + { + cm->next = (int *) alloc(sizeof(int) * cm->num); + if (cm->next) + { + for (h = 0;h <= cm->mask;++h) + cm->first[h] = -1; + pos = 0; + i = 0; + for (j = 0;j < len;++j) + if (!s[j]) + { + k = j - i; + if (flagcolon) + { + for (k = i;k < j;++k) + if (s[k] == ':') + break; + if (k >= j) { i = j + 1; continue; } + k -= i; + } + cm->input[pos] = s + i; + cm->inputlen[pos] = k; + h = hash(s + i,k); + cm->hash[pos] = h; + h &= cm->mask; + cm->next[pos] = cm->first[h]; + cm->first[h] = pos; + ++pos; + i = j + 1; + } + return 1; + } + alloc_free(cm->hash); + } + alloc_free(cm->inputlen); + } + alloc_free(cm->input); + } + alloc_free(cm->first); + } + return 0; +} + +void constmap_free(cm) +struct constmap *cm; +{ + alloc_free(cm->next); + alloc_free(cm->hash); + alloc_free(cm->inputlen); + alloc_free(cm->input); + alloc_free(cm->first); +} diff --git a/constmap.h b/constmap.h @@ -0,0 +1,22 @@ +#ifndef CONSTMAP_H +#define CONSTMAP_H + +typedef unsigned long constmap_hash; + +struct constmap + { + int num; + constmap_hash mask; + constmap_hash *hash; + int *first; + int *next; + char **input; + int *inputlen; + } +; + +extern int constmap_init(); +extern void constmap_free(); +extern char *constmap(); + +#endif diff --git a/control.c b/control.c @@ -0,0 +1,129 @@ +#include "readwrite.h" +#include "open.h" +#include "getln.h" +#include "stralloc.h" +#include "substdio.h" +#include "error.h" +#include "control.h" +#include "alloc.h" +#include "scan.h" + +static char inbuf[64]; +static stralloc line = {0}; +static stralloc me = {0}; +static int meok = 0; + +static void striptrailingwhitespace(sa) +stralloc *sa; +{ + while (sa->len > 0) + switch(sa->s[sa->len - 1]) + { + case '\n': case ' ': case '\t': + --sa->len; + break; + default: + return; + } +} + +int control_init() +{ + int r; + r = control_readline(&me,"control/me"); + if (r == 1) meok = 1; + return r; +} + +int control_rldef(sa,fn,flagme,def) +stralloc *sa; +char *fn; +int flagme; +char *def; +{ + int r; + r = control_readline(sa,fn); + if (r) return r; + if (flagme) if (meok) return stralloc_copy(sa,&me) ? 1 : -1; + if (def) return stralloc_copys(sa,def) ? 1 : -1; + return r; +} + +int control_readline(sa,fn) +stralloc *sa; +char *fn; +{ + substdio ss; + int fd; + int match; + + fd = open_read(fn); + if (fd == -1) { if (errno == error_noent) return 0; return -1; } + + substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf)); + + if (getln(&ss,sa,&match,'\n') == -1) { close(fd); return -1; } + + striptrailingwhitespace(sa); + close(fd); + return 1; +} + +int control_readint(i,fn) +int *i; +char *fn; +{ + unsigned long u; + switch(control_readline(&line,fn)) + { + case 0: return 0; + case -1: return -1; + } + if (scan_nbblong(line.s,line.len,10,0,&u) == 0) return 0; + *i = u; + return 1; +} + +int control_readfile(sa,fn,flagme) +stralloc *sa; +char *fn; +int flagme; +{ + substdio ss; + int fd; + int match; + + if (!stralloc_copys(sa,"")) return -1; + + fd = open_read(fn); + if (fd == -1) + { + if (errno == error_noent) + { + if (flagme && meok) + { + if (!stralloc_copy(sa,&me)) return -1; + if (!stralloc_0(sa)) return -1; + return 1; + } + return 0; + } + return -1; + } + + substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf)); + + for (;;) + { + if (getln(&ss,&line,&match,'\n') == -1) break; + if (!match && !line.len) { close(fd); return 1; } + striptrailingwhitespace(&line); + if (!stralloc_0(&line)) break; + if (line.s[0]) + if (line.s[0] != '#') + if (!stralloc_cat(sa,&line)) break; + if (!match) { close(fd); return 1; } + } + close(fd); + return -1; +} diff --git a/control.h b/control.h @@ -0,0 +1,10 @@ +#ifndef CONTROL_H +#define CONTROL_H + +extern int control_init(); +extern int control_readline(); +extern int control_rldef(); +extern int control_readint(); +extern int control_readfile(); + +#endif diff --git a/date822fmt.c b/date822fmt.c @@ -0,0 +1,29 @@ +#include "datetime.h" +#include "fmt.h" +#include "date822fmt.h" + +static char *montab[12] = { +"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +unsigned int date822fmt(s,dt) +char *s; +struct datetime *dt; +{ + unsigned int i; + unsigned int len; + len = 0; + i = fmt_uint(s,dt->mday); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_str(s,montab[dt->mon]); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_uint(s,dt->year + 1900); len += i; if (s) s += i; + i = fmt_str(s," "); len += i; if (s) s += i; + i = fmt_uint0(s,dt->hour,2); len += i; if (s) s += i; + i = fmt_str(s,":"); len += i; if (s) s += i; + i = fmt_uint0(s,dt->min,2); len += i; if (s) s += i; + i = fmt_str(s,":"); len += i; if (s) s += i; + i = fmt_uint0(s,dt->sec,2); len += i; if (s) s += i; + i = fmt_str(s," -0000\n"); len += i; if (s) s += i; + return len; +} diff --git a/date822fmt.h b/date822fmt.h @@ -0,0 +1,7 @@ +#ifndef DATE822FMT_H +#define DATE822FMT_H + +extern unsigned int date822fmt(); +#define DATE822FMT 60 + +#endif diff --git a/datemail.sh b/datemail.sh @@ -0,0 +1 @@ +exec QMAIL/bin/predate QMAIL/bin/sendmail ${1+"$@"} diff --git a/datetime.3 b/datetime.3 @@ -0,0 +1,73 @@ +.TH datetime 3 +.SH NAME +datetime \- convert between TAI labels and seconds +.SH SYNTAX +.B #include <datetime.h> + +void \fBdatetime_tai\fP(&\fIdt\fR,\fIt\fR); + +datetime_sec \fBdatetime_untai\fP(&\fIdt\fR); + +struct datetime \fIdt\fR; +.br +datetime_sec \fIt\fR; +.SH DESCRIPTION +International Atomic Time, TAI, +is the fundamental unit for time measurements. +TAI has one label for every second of real time, +without complications such as leap seconds. + +A +struct datetime +variable, +such as +.IR dt , +stores a TAI label. +.I dt\fB.year +is the year number minus 1900; +.I dt\fB.mon +is the month number, from 0 (January) through 11 (December); +.I dt\fB.mday +is the day of the month, from 1 through 31; +.I dt\fB.hour +is the hour, from 0 through 23; +.I dt\fB.min +is the minute, from 0 through 59; +.I dt\fB.sec +is the second, from 0 through 59; +.I dt\fB.wday +is the day of the week, from 0 (Sunday) through 6 (Saturday); +.I dt\fB.yday +is the day of the year, from 0 through 365. + +The +.B datetime +library supports more convenient TAI manipulation with +the datetime_sec type. +A datetime_sec value, such as +.IR t , +is an integer referring to the +.IR t th +second after the beginning of 1970 TAI. +The first second of 1970 TAI was 0; +the next second was 1; +the last second of 1969 TAI was -1. +The difference between two datetime_sec values is a number +of real-time seconds. + +.B datetime_tai +converts a datetime_sec to a TAI label. + +.B datetime_untai +reads a TAI label +(specifically +.IR dt\fB.year , +.IR dt\fB.mon , +.IR dt\fB.mday , +.IR dt\fB.hour , +.IR dt\fB.min , +and +.IR dt\fB.sec ) +and returns a datetime_sec. +.SH "SEE ALSO" +now(3) diff --git a/datetime.c b/datetime.c @@ -0,0 +1,55 @@ +/* 19950925 */ +#include "datetime.h" + +void datetime_tai(dt,t) +struct datetime *dt; +datetime_sec t; +{ + int day; + int tod; + int year; + int yday; + int wday; + int mon; + + tod = t % 86400; + day = t / 86400; + if (tod < 0) { tod += 86400; --day; } + + dt->hour = tod / 3600; + tod %= 3600; + dt->min = tod / 60; + dt->sec = tod % 60; + + wday = (day + 4) % 7; if (wday < 0) wday += 7; + dt->wday = wday; + + day -= 11017; + /* day 0 is march 1, 2000 */ + year = 5 + day / 146097; + day = day % 146097; if (day < 0) { day += 146097; --year; } + /* from now on, day is nonnegative */ + year *= 4; + if (day == 146096) { year += 3; day = 36524; } + else { year += day / 36524; day %= 36524; } + year *= 25; + year += day / 1461; + day %= 1461; + year *= 4; + yday = (day < 306); + if (day == 1460) { year += 3; day = 365; } + else { year += day / 365; day %= 365; } + yday += day; + + day *= 10; + mon = (day + 5) / 306; + day = day + 5 - 306 * mon; + day /= 10; + if (mon >= 10) { yday -= 306; ++year; mon -= 10; } + else { yday += 59; mon += 2; } + + dt->yday = yday; + dt->year = year - 1900; + dt->mon = mon; + dt->mday = day + 1; +} diff --git a/datetime.h b/datetime.h @@ -0,0 +1,20 @@ +#ifndef DATETIME_H +#define DATETIME_H + +struct datetime { + int hour; + int min; + int sec; + int wday; + int mday; + int yday; + int mon; + int year; +} ; + +typedef long datetime_sec; + +extern void datetime_tai(); +extern datetime_sec datetime_untai(); + +#endif diff --git a/datetime_un.c b/datetime_un.c @@ -0,0 +1,35 @@ +#include "datetime.h" + +/* roughly 100x faster than mktime() */ +datetime_sec datetime_untai(dt) +struct datetime *dt; +{ + int year; + int day; + int mon; + + year = dt->year + 1900; + + mon = dt->mon; + if (mon >= 2) { mon -= 2; } + else { mon += 10; --year; } + + day = (dt->mday - 1) * 10 + 5 + 306 * mon; + day /= 10; + + if (day == 365) { year -= 3; day = 1460; } + else { day += 365 * (year % 4); } + year /= 4; + + day += 1461 * (year % 25); + year /= 25; + + if (day == 36524) { year -= 3; day = 146096; } + else { day += 36524 * (year % 4); } + year /= 4; + + day += 146097 * (year - 5); + day += 11017; + + return ((day * 24 + dt->hour) * 60 + dt->min) * 60 + dt->sec; +} diff --git a/direntry.3 b/direntry.3 @@ -0,0 +1,36 @@ +.TH direntry 3 +.SH NAME +direntry \- read directory entries +.SH SYNTAX +.B #include <direntry.h> + +DIR *\fBopendir\fP(\fIfn\fR); + +struct direntry *\fBreaddir\fP(\fIdir\fP); + +void \fBclosedir\fP(\fIdir\fP); + +DIR *\fIdir\fR; +.br +char *\fIfn\fR; +.SH DESCRIPTION +The point of +.B direntry.h +is to provide a uniform interface to BSD's +.B sys/dir.h +and POSIX's +.BR dirent.h . + +The +.B readdir +interface is highly unsatisfactory. +It does not distinguish between I/O errors and end-of-directory. +It uses +.BR malloc . +The return type for +.B closedir +varies: some implementations return the +.B close +return value. +.SH "SEE ALSO" +readdir(3) diff --git a/direntry.h1 b/direntry.h1 @@ -0,0 +1,8 @@ +#ifndef DIRENTRY_H +#define DIRENTRY_H + +#include <sys/types.h> +#include <sys/dir.h> +#define direntry struct direct + +#endif diff --git a/direntry.h2 b/direntry.h2 @@ -0,0 +1,8 @@ +#ifndef DIRENTRY_H +#define DIRENTRY_H + +#include <sys/types.h> +#include <dirent.h> +#define direntry struct dirent + +#endif diff --git a/dns.c b/dns.c @@ -0,0 +1,402 @@ +#include <stdio.h> +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <errno.h> +extern int res_query(); +extern int res_search(); +extern int errno; +extern int h_errno; +#include "ip.h" +#include "ipalloc.h" +#include "fmt.h" +#include "alloc.h" +#include "str.h" +#include "stralloc.h" +#include "dns.h" +#include "case.h" + +static unsigned short getshort(c) unsigned char *c; +{ unsigned short u; u = c[0]; return (u << 8) + c[1]; } + +static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response; +static int responselen; +static unsigned char *responseend; +static unsigned char *responsepos; + +static int numanswers; +static char name[MAXDNAME]; +static struct ip_address ip; +unsigned short pref; + +static stralloc glue = {0}; + +static int (*lookup)() = res_query; + +static int resolve(domain,type) +stralloc *domain; +int type; +{ + int n; + int i; + + errno = 0; + if (!stralloc_copy(&glue,domain)) return DNS_MEM; + if (!stralloc_0(&glue)) return DNS_MEM; + responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response)); + if (responselen <= 0) + { + if (errno == ECONNREFUSED) return DNS_SOFT; + if (h_errno == TRY_AGAIN) return DNS_SOFT; + return DNS_HARD; + } + if (responselen >= sizeof(response)) + responselen = sizeof(response); + responseend = response.buf + responselen; + responsepos = response.buf + sizeof(HEADER); + n = ntohs(response.hdr.qdcount); + while (n-- > 0) + { + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + i = responseend - responsepos; + if (i < QFIXEDSZ) return DNS_SOFT; + responsepos += QFIXEDSZ; + } + numanswers = ntohs(response.hdr.ancount); + return 0; +} + +static int findname(wanttype) +int wanttype; +{ + unsigned short rrtype; + unsigned short rrdlen; + int i; + + if (numanswers <= 0) return 2; + --numanswers; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + rrtype = getshort(responsepos); + rrdlen = getshort(responsepos + 8); + responsepos += 10; + + if (rrtype == wanttype) + { + if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0) + return DNS_SOFT; + responsepos += rrdlen; + return 1; + } + + responsepos += rrdlen; + return 0; +} + +static int findip(wanttype) +int wanttype; +{ + unsigned short rrtype; + unsigned short rrdlen; + int i; + + if (numanswers <= 0) return 2; + --numanswers; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + rrtype = getshort(responsepos); + rrdlen = getshort(responsepos + 8); + responsepos += 10; + + if (rrtype == wanttype) + { + if (rrdlen < 4) + return DNS_SOFT; + ip.d[0] = responsepos[0]; + ip.d[1] = responsepos[1]; + ip.d[2] = responsepos[2]; + ip.d[3] = responsepos[3]; + responsepos += rrdlen; + return 1; + } + + responsepos += rrdlen; + return 0; +} + +static int findmx(wanttype) +int wanttype; +{ + unsigned short rrtype; + unsigned short rrdlen; + int i; + + if (numanswers <= 0) return 2; + --numanswers; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + rrtype = getshort(responsepos); + rrdlen = getshort(responsepos + 8); + responsepos += 10; + + if (rrtype == wanttype) + { + if (rrdlen < 3) + return DNS_SOFT; + pref = (responsepos[0] << 8) + responsepos[1]; + if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0) + return DNS_SOFT; + responsepos += rrdlen; + return 1; + } + + responsepos += rrdlen; + return 0; +} + +void dns_init(flagsearch) +int flagsearch; +{ + res_init(); + if (flagsearch) lookup = res_search; +} + +int dns_cname(sa) +stralloc *sa; +{ + int r; + int loop; + for (loop = 0;loop < 10;++loop) + { + if (!sa->len) return loop; + if (sa->s[sa->len - 1] == ']') return loop; + if (sa->s[sa->len - 1] == '.') { --sa->len; continue; } + switch(resolve(sa,T_ANY)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return loop; + default: + while ((r = findname(T_CNAME)) != 2) + { + if (r == DNS_SOFT) return DNS_SOFT; + if (r == 1) + { + if (!stralloc_copys(sa,name)) return DNS_MEM; + break; + } + } + if (r == 2) return loop; + } + } + return DNS_HARD; /* alias loop */ +} + +#define FMT_IAA 40 + +static int iaafmt(s,ip) +char *s; +struct ip_address *ip; +{ + unsigned int i; + unsigned int len; + len = 0; + i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i; + i = fmt_str(s,"."); len += i; if (s) s += i; + i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i; + i = fmt_str(s,"."); len += i; if (s) s += i; + i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i; + i = fmt_str(s,"."); len += i; if (s) s += i; + i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i; + i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i; + return len; +} + +int dns_ptr(sa,ip) +stralloc *sa; +struct ip_address *ip; +{ + int r; + + if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM; + sa->len = iaafmt(sa->s,ip); + switch(resolve(sa,T_PTR)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return DNS_HARD; + } + while ((r = findname(T_PTR)) != 2) + { + if (r == DNS_SOFT) return DNS_SOFT; + if (r == 1) + { + if (!stralloc_copys(sa,name)) return DNS_MEM; + return 0; + } + } + return DNS_HARD; +} + +static int dns_ipplus(ia,sa,pref) +ipalloc *ia; +stralloc *sa; +int pref; +{ + int r; + struct ip_mx ix; + + if (sa->len && (sa->s[0] == '[')) + { + if (!stralloc_copy(&glue,sa)) return DNS_MEM; + if (!stralloc_0(&glue)) return DNS_MEM; + ix.pref = 0; + if (!glue.s[ip_scanbracket(glue.s,&ix.ip)]) + { + if (!ipalloc_append(ia,&ix)) return DNS_MEM; + return 0; + } + } + + switch(resolve(sa,T_A)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return DNS_HARD; + } + while ((r = findip(T_A)) != 2) + { + ix.ip = ip; + ix.pref = pref; + if (r == DNS_SOFT) return DNS_SOFT; + if (r == 1) + if (!ipalloc_append(ia,&ix)) return DNS_MEM; + } + return 0; +} + +int dns_ip(ia,sa) +ipalloc *ia; +stralloc *sa; +{ + if (!ipalloc_readyplus(ia,0)) return DNS_MEM; + ia->len = 0; + return dns_ipplus(ia,sa,0); +} + +int dns_mxip(ia,sa,random) +ipalloc *ia; +stralloc *sa; +unsigned long random; +{ + int r; + struct mx { stralloc sa; unsigned short p; } *mx; + int nummx; + int i; + int j; + int flagsoft; + + if (!ipalloc_readyplus(ia,0)) return DNS_MEM; + ia->len = 0; + + if (sa->len && (sa->s[0] == '[')) + { + struct ip_mx ix; + if (!stralloc_copy(&glue,sa)) return DNS_MEM; + if (!stralloc_0(&glue)) return DNS_MEM; + ix.pref = 0; + if (!glue.s[ip_scanbracket(glue.s,&ix.ip)]) + { + if (!ipalloc_append(ia,&ix)) return DNS_MEM; + return 0; + } + } + + switch(resolve(sa,T_MX)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return dns_ip(ia,sa); + } + + mx = (struct mx *) alloc(numanswers * sizeof(struct mx)); + if (!mx) return DNS_MEM; + nummx = 0; + + while ((r = findmx(T_MX)) != 2) + { + if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; } + if (r == 1) + { + mx[nummx].p = pref; + mx[nummx].sa.s = 0; + if (!stralloc_copys(&mx[nummx].sa,name)) + { + while (nummx > 0) alloc_free(mx[--nummx].sa.s); + alloc_free(mx); return DNS_MEM; + } + ++nummx; + } + } + + if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */ + + flagsoft = 0; + while (nummx > 0) + { + unsigned long numsame; + + i = 0; + numsame = 1; + for (j = 1;j < nummx;++j) + if (mx[j].p < mx[i].p) + { + i = j; + numsame = 1; + } + else if (mx[j].p == mx[i].p) + { + ++numsame; + random = random * 69069 + 1; + if ((random / 2) < (2147483647 / numsame)) + i = j; + } + + switch(dns_ipplus(ia,&mx[i].sa,mx[i].p)) + { + case DNS_MEM: case DNS_SOFT: + flagsoft = 1; break; + } + + alloc_free(mx[i].sa.s); + mx[i] = mx[--nummx]; + } + + alloc_free(mx); + return flagsoft; +} diff --git a/dns.h b/dns.h @@ -0,0 +1,14 @@ +#ifndef DNS_H +#define DNS_H + +#define DNS_SOFT -1 +#define DNS_HARD -2 +#define DNS_MEM -3 + +void dns_init(); +int dns_cname(); +int dns_mxip(); +int dns_ip(); +int dns_ptr(); + +#endif diff --git a/dnscname.c b/dnscname.c @@ -0,0 +1,25 @@ +#include "substdio.h" +#include "subfd.h" +#include "stralloc.h" +#include "dns.h" +#include "dnsdoe.h" +#include "readwrite.h" +#include "exit.h" + +stralloc sa = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + if (!argv[1]) _exit(100); + + if (!stralloc_copys(&sa,argv[1])) + { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); } + + dns_init(0); + dnsdoe(dns_cname(&sa)); + substdio_putflush(subfdout,sa.s,sa.len); + substdio_putsflush(subfdout,"\n"); + _exit(0); +} diff --git a/dnsdoe.c b/dnsdoe.c @@ -0,0 +1,16 @@ +#include "substdio.h" +#include "subfd.h" +#include "exit.h" +#include "dns.h" +#include "dnsdoe.h" + +void dnsdoe(r) +int r; +{ + switch (r) + { + case DNS_HARD: substdio_putsflush(subfderr,"hard error\n"); _exit(100); + case DNS_SOFT: substdio_putsflush(subfderr,"soft error\n"); _exit(111); + case DNS_MEM: substdio_putsflush(subfderr,"out of memory\n"); _exit(111); + } +} diff --git a/dnsdoe.h b/dnsdoe.h @@ -0,0 +1,6 @@ +#ifndef DNSDOE_H +#define DNSDOE_H + +extern void dnsdoe(); + +#endif diff --git a/dnsfq.c b/dnsfq.c @@ -0,0 +1,32 @@ +#include "substdio.h" +#include "subfd.h" +#include "stralloc.h" +#include "dns.h" +#include "dnsdoe.h" +#include "ip.h" +#include "ipalloc.h" +#include "exit.h" + +stralloc sa = {0}; +ipalloc ia = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + if (!argv[1]) _exit(100); + + if (!stralloc_copys(&sa,argv[1])) + { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); } + + dns_init(1); + dnsdoe(dns_ip(&ia,&sa)); + if (ia.len <= 0) + { + substdio_putsflush(subfderr,"no IP addresses\n"); _exit(100); + } + dnsdoe(dns_ptr(&sa,&ia.ix[0].ip)); + substdio_putflush(subfdout,sa.s,sa.len); + substdio_putsflush(subfdout,"\n"); + _exit(0); +} diff --git a/dnsip.c b/dnsip.c @@ -0,0 +1,34 @@ +#include "substdio.h" +#include "subfd.h" +#include "stralloc.h" +#include "dns.h" +#include "dnsdoe.h" +#include "ip.h" +#include "ipalloc.h" +#include "exit.h" + +char temp[IPFMT]; + +stralloc sa = {0}; +ipalloc ia = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + int j; + + if (!argv[1]) _exit(100); + + if (!stralloc_copys(&sa,argv[1])) + { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); } + + dns_init(0); + dnsdoe(dns_ip(&ia,&sa)); + for (j = 0;j < ia.len;++j) + { + substdio_put(subfdout,temp,ip_fmt(temp,&ia.ix[j].ip)); + substdio_putsflush(subfdout,"\n"); + } + _exit(0); +} diff --git a/dnsmxip.c b/dnsmxip.c @@ -0,0 +1,40 @@ +#include "substdio.h" +#include "subfd.h" +#include "stralloc.h" +#include "fmt.h" +#include "dns.h" +#include "dnsdoe.h" +#include "ip.h" +#include "ipalloc.h" +#include "now.h" +#include "exit.h" + +char temp[IPFMT + FMT_ULONG]; + +stralloc sa = {0}; +ipalloc ia = {0}; + +void main(argc,argv) +int argc; +char **argv; +{ + int j; + unsigned long r; + + if (!argv[1]) _exit(100); + + if (!stralloc_copys(&sa,argv[1])) + { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); } + + r = now() + getpid(); + dns_init(0); + dnsdoe(dns_mxip(&ia,&sa,r)); + for (j = 0;j < ia.len;++j) + { + substdio_put(subfdout,temp,ip_fmt(temp,&ia.ix[j].ip)); + substdio_puts(subfdout," "); + substdio_put(subfdout,temp,fmt_ulong(temp,(unsigned long) ia.ix[j].pref)); + substdio_putsflush(subfdout,"\n"); + } + _exit(0); +} diff --git a/dnsptr.c b/dnsptr.c @@ -0,0 +1,27 @@ +#include "substdio.h" +#include "subfd.h" +#include "stralloc.h" +#include "str.h" +#include "scan.h" +#include "dns.h" +#include "dnsdoe.h" +#include "ip.h" +#include "exit.h" + +stralloc sa = {0}; +struct ip_address ip; + +void main(argc,argv) +int argc; +char **argv; +{ + if (!argv[1]) _exit(100); + + ip_scan(argv[1],&ip); + + dns_init(0); + dnsdoe(dns_ptr(&sa,&ip)); + substdio_putflush(subfdout,sa.s,sa.len); + substdio_putsflush(subfdout,"\n"); + _exit(0); +} diff --git a/dot-qmail.9 b/dot-qmail.9 @@ -0,0 +1,394 @@ +.TH dot-qmail 5 +.SH NAME +dot-qmail \- control the delivery of mail messages +.SH DESCRIPTION +Normally the +.B qmail-local +program delivers each incoming message to your system mailbox, +.IR homedir\fB/Mailbox , +where +.I homedir +is your home directory. + +It can instead +write the mail to a different file or directory, +forward it to another address, +distribute it to a mailing list, +or even execute programs, +all under your control. +.SH "THE QMAIL FILE" +To change +.BR qmail-local 's +behavior, set up a +.B .qmail +file in your home directory. + +.B .qmail +contains one or more lines. +Each line is a delivery instruction. +.B qmail-local +follows each instruction in turn. +There are five types of delivery instructions: +(1) comment; (2) program; (3) forward; (4) mbox; (5) maildir. +.TP 5 +(1) +A comment line begins with a number sign: + +.EX + # this is a comment +.EE + +.B qmail-local +ignores the line. +.TP 5 +(2) +A program line begins with a vertical bar: + +.EX + |/usr/ucb/vacation djb +.EE + +.B qmail-local +takes the rest of the line as a command to supply to +.BR sh . +See +.B qmail-command(8) +for further information. +.TP 5 +(3) +A forward line begins with an ampersand: + +.EX + &me@new.job.com +.EE + +.B qmail-local +takes the rest of the line as a mail address; +it uses +.B qmail-queue +to forward the message to that address. +The address must contain a fully qualified domain name; +it must not contain extra spaces, angle brackets, or comments: + +.EX + # the following examples are WRONG +.br + &me@new +.br + &<me@new.job.com> +.br + & me@new.job.com +.br + &me@new.job.com (New Address) +.EE + +If the address begins with a letter or number, +you may leave out the ampersand: + +.EX + me@new.job.com +.EE + +Note that +.B qmail-local +omits its new +.B Return-Path +line when forwarding messages. +.TP 5 +(4) +An +.I mbox +line begins with a slash or dot, +and does not end with a slash: + +.EX + /home/djb/Mailbox.sos +.EE + +.B qmail-local +takes the entire line as a filename. +It appends the mail message to that file, +using +.BR flock -style +file locking if possible. +.B qmail-local +stores the mail message in +.I mbox +format, as described in +.BR mbox(5) . + +.B WARNING: +On many systems, +anyone who can read a file can +.B flock +it, and thus hold up +.BR qmail-local 's +delivery forever. +Do not deliver mail to a publicly accessible file! + +If +.B qmail-local +is able to lock the file, but has trouble writing to it +(because, for example, the disk is full), +it will truncate the file back to its original length. +However, it cannot prevent mailbox corruption if the system +crashes during delivery. +.TP 5 +(5) +A +.I maildir +line begins with a slash or dot, +and ends with a slash: + +.EX + /home/djb/Maildir/ +.EE + +.B qmail-local +takes the entire line as the name of a directory in +.I maildir +format. +It reliably stores the incoming message in that directory. +See +.B maildir(5) +for more details. +.PP +If +.B .qmail +has the execute bit set, +it must not contain any +program lines, +.I mbox +lines, +or +.I maildir +lines. +If +.B qmail-local +sees any such lines, +it will stop and indicate a temporary failure. + +If +.B .qmail +is completely empty (0 bytes long), or does not exist, +.B qmail-local +follows the +.I aliasempty +instructions set by your system administrator; +normally +.I aliasempty +is +.BR ./Mailbox , +so +.B qmail-local +appends the mail message to +.B Mailbox +in +.I mbox +format. + +.B .qmail +may contain extra spaces and tabs at the end of a line. +Blank lines are allowed, but not for the first line of +.BR .qmail . + +If +.B .qmail +is world-writable or group-writable, +.B qmail-local +stops and indicates a temporary failure. +.SH "SAFE QMAIL EDITING" +Incoming messages can arrive at any moment. +If you want to safely edit your +.B .qmail +file, first set the sticky bit on your home directory: + +.EX + chmod +t $HOME +.EE + +.B qmail-local +will temporarily defer delivery of any message to you +if your home directory is sticky +(or group-writable or other-writable, +which should never happen). +Make sure to + +.EX + chmod -t $HOME +.EE + +when you are done! +It's a good idea to test your new +.B .qmail +file as follows: + +.EX + qmail-local -n $USER $HOME $USER '' '' '' '' +.EE +.SH "EXTENSION ADDRESSES" +In the +.B qmail +system, +you control all local addresses of the form +.IR user\fBBREAK\fIanything , +as well as the address +.I user +itself, +where +.I user +is your account name. +Delivery to +.I user\fBBREAK\fIanything +is controlled by the file +.IR homedir/\fB.qmail\-\fIanything . +(These rules may be changed by the system administrator; +see +.BR qmail-users (5).) + +The +.B alias +user controls all other addresses. +Delivery to +.I local +is controlled by the file +.IR homedir/\fB.qmail\-\fIlocal , +where +.I homedir +is +.BR alias 's +home directory. + +In the following description, +.B qmail-local +is handling a message addressed to +.IR local@domain , +where +.I local +is controlled by +.BR .qmail\-\fIext . +Here is what it does. + +If +.B .qmail\-\fIext +is completely empty, +.B qmail-local +follows the +.I aliasempty +instructions set by your system administrator. + +If +.B .qmail\-\fIext +doesn't exist, +.B qmail-local +will try some default +.B .qmail +files. +For example, +if +.I ext +is +.BR foo-bar , +.B qmail-local +will try first +.BR .qmail-foo-bar , +then +.BR .qmail-foo-default , +and finally +.BR .qmail-default . +If none of these exist, +.B qmail-local +will bounce the message. +(Exception: for the basic +.I user +address, +.B qmail-local +treats a nonexistent +.B .qmail +the same as an empty +.BR .qmail .) + +.B WARNING: +For security, +.B qmail-local +replaces any dots in +.I ext +with colons before checking +.BR .qmail\-\fIext . +For convenience, +.B qmail-local +converts any uppercase letters in +.I ext +to lowercase. + +When +.B qmail-local +forwards a message as instructed in +.B .qmail\-\fIext +(or +.BR .qmail-default ), +it checks whether +.B .qmail\-\fIext\fB-owner\fP +exists. +If so, +it uses +.I local\fB-owner@\fIdomain +as the envelope sender for the forwarded message. +Otherwise it retains the envelope sender of the original message. +Exception: +.B qmail-local +always retains the original envelope sender +if it is the empty address or +.BR #@[] , +i.e., if this is a bounce message. + +.B qmail-local +also supports +.B variable envelope return paths +(VERPs): +if +.B .qmail\-\fIext\fB-owner\fP +and +.B .qmail\-\fIext\fB-owner-default\fP +both exist, it uses +.I local\fB\-owner\-@\fIdomain\fB-@[] +as the envelope sender. +This will cause a recipient +.I recip\fB@\fIreciphost +to see an envelope sender of +.IR local\fB\-owner\-\fIrecip\fB=\fIreciphost\fB@\fIdomain . +.SH "ERROR HANDLING" +If a delivery instruction fails, +.B qmail-local +stops immediately and reports failure. +.B qmail-local +handles forwarding after all other instructions, +so any error in another type of delivery will prevent all forwarding. + +If a program returns exit code 99, +.B qmail-local +ignores all succeeding lines in +.BR .qmail , +but it still pays attention to previous forward lines. + +To set up independent instructions, +where a temporary or permanent failure in one instruction +does not affect the others, +move each instruction into a separate +.B .qmail\-\fIext +file, and set up a central +.B .qmail +file that forwards to all of the +.BR .qmail\-\fIext s. +Note that +.B qmail-local +can handle any number of forward lines simultaneously. +.SH "SEE ALSO" +envelopes(5), +maildir(5), +mbox(5), +qmail-users(5), +qmail-local(8), +qmail-command(8), +qmail-queue(8), +qmail-lspawn(8) diff --git a/elq.sh b/elq.sh @@ -0,0 +1 @@ +QMAIL/bin/maildir2mbox && exec elm ${1+"$@"} diff --git a/env.3 b/env.3 @@ -0,0 +1,31 @@ +.TH env 3 +.SH NAME +env \- manage the environment +.SH SYNTAX +.B #include <env.h> + +char **\fBenviron\fP; + +char *\fBenv_get\fP(\fIname\fR); +.br +char *\fBenv_pick\fP(); + +char *\fIname\fR; +.SH DESCRIPTION +The environment, +.BR environ , +is a 0-terminated array of 0-terminated strings, +called environment variables. +Each environment variable is of the form +.IR name\fB=\fIvalue . + +.B env_get +returns the value of the first variable whose name is +.IR name , +or 0 if there is no such variable. + +.B env_pick +returns any variable in the environment, +or 0 if the environment is empty. +.SH "SEE ALSO" +environ(7) diff --git a/env.c b/env.c @@ -0,0 +1,113 @@ +/* env.c, envread.c, env.h: environ library +Daniel J. Bernstein, djb@silverton.berkeley.edu. +Depends on str.h, alloc.h. +Requires environ. +19960113: rewrite. warning: interface is different. +No known patent problems. +*/ + +#include "str.h" +#include "alloc.h" +#include "env.h" + +int env_isinit = 0; /* if env_isinit: */ +static int ea; /* environ is a pointer to ea+1 char*'s. */ +static int en; /* the first en of those are ALLOCATED. environ[en] is 0. */ + +static void env_goodbye(i) int i; +{ + alloc_free(environ[i]); + environ[i] = environ[--en]; + environ[en] = 0; +} + +static char *null = 0; + +void env_clear() +{ + if (env_isinit) while (en) env_goodbye(0); + else environ = &null; +} + +static void env_unsetlen(s,len) char *s; int len; +{ + int i; + for (i = en - 1;i >= 0;--i) + if (!str_diffn(s,environ[i],len)) + if (environ[i][len] == '=') + env_goodbye(i); +} + +int env_unset(s) char *s; +{ + if (!env_isinit) if (!env_init()) return 0; + env_unsetlen(s,str_len(s)); + return 1; +} + +static int env_add(s) char *s; +{ + char *t; + t = env_findeq(s); + if (t) env_unsetlen(s,t - s); + if (en == ea) + { + ea += 30; + if (!alloc_re(&environ,(en + 1) * sizeof(char *),(ea + 1) * sizeof(char *))) + { ea = en; return 0; } + } + environ[en++] = s; + environ[en] = 0; + return 1; +} + +int env_put(s) char *s; +{ + char *u; + if (!env_isinit) if (!env_init()) return 0; + u = alloc(str_len(s) + 1); + if (!u) return 0; + str_copy(u,s); + if (!env_add(u)) { alloc_free(u); return 0; } + return 1; +} + +int env_put2(s,t) char *s; char *t; +{ + char *u; + int slen; + if (!env_isinit) if (!env_init()) return 0; + slen = str_len(s); + u = alloc(slen + str_len(t) + 2); + if (!u) return 0; + str_copy(u,s); + u[slen] = '='; + str_copy(u + slen + 1,t); + if (!env_add(u)) { alloc_free(u); return 0; } + return 1; +} + +int env_init() +{ + char **newenviron; + int i; + for (en = 0;environ[en];++en) ; + ea = en + 10; + newenviron = (char **) alloc((ea + 1) * sizeof(char *)); + if (!newenviron) return 0; + for (en = 0;environ[en];++en) + { + newenviron[en] = alloc(str_len(environ[en]) + 1); + if (!newenviron[en]) + { + for (i = 0;i < en;++i) alloc_free(newenviron[i]); + alloc_free(newenviron); + return 0; + } + str_copy(newenviron[en],environ[en]); + } + newenviron[en] = 0; + environ = newenviron; + env_isinit = 1; + return 1; +} diff --git a/env.h b/env.h @@ -0,0 +1,17 @@ +#ifndef ENV_H +#define ENV_H + +extern int env_isinit; + +extern int env_init(); +extern int env_put(); +extern int env_put2(); +extern int env_unset(); +extern /*@null@*/char *env_get(); +extern char *env_pick(); +extern void env_clear(); +extern char *env_findeq(); + +extern char **environ; + +#endif diff --git a/envelopes.5 b/envelopes.5 @@ -0,0 +1,231 @@ +.TH envelopes 5 +.SH "NAME" +envelopes \- sender/recipient lists attached to messages +.SH "INTRODUCTION" +Electronic mail messages are delivered in +.IR envelopes . + +An envelope lists a +.I sender +and one or more +.IR recipients . +Usually these +envelope addresses are the same +as the addresses listed in the message header: + +.EX + (envelope) from djb to root +.br + From: djb +.br + To: root +.EE + +In more complicated situations, though, +the envelope addresses may differ from the header addresses. +.SH "ENVELOPE EXAMPLES" +When a message is delivered to +several people at different locations, +it is first photocopied +and placed into several envelopes: + +.EX + (envelope) from djb to root +.br + From: djb Copy #1 of message +.br + To: root, god@brl.mil +.EE + +.EX + (envelope) from djb to god@brl.mil +.br + From: djb Copy #2 of message +.br + To: root, god@brl.mil +.EE + +When a message is delivered +to several people at the same loca