Index: qmail/.cvsignore
diff -c /dev/null qmail/.cvsignore:1.2
*** /dev/null	Fri Aug  7 11:03:19 2009
--- qmail/.cvsignore	Sat May  6 16:37:20 2006
***************
*** 0 ****
--- 1,108 ----
+ *.[0-9]
+ auto-ccld.sh
+ make-load
+ find-systype
+ systype
+ load
+ make-compile
+ compile
+ fork.h
+ make-makelib
+ makelib
+ hassgprm.h
+ hassgact.h
+ hasflock.h
+ haswaitp.h
+ auto-str
+ auto_qmail.c
+ auto-int8
+ auto_patrn.c
+ socket.lib
+ qmail-local
+ uint32.h
+ select.h
+ auto-int
+ auto_spawn.c
+ chkspawn
+ chkshsgr
+ hasshsgr.h
+ auto-uid
+ auto-gid
+ auto_uids.c
+ qmail-lspawn
+ auto_break.c
+ auto_usera.c
+ qmail-getpw
+ hassalen.h
+ dns.lib
+ qmail-remote
+ qmail-rspawn
+ direntry.h
+ auto_split.c
+ qmail-clean
+ hasmkffo.h
+ hasnpbg1.h
+ qmail-send
+ qmail-start
+ syslog.lib
+ splogger
+ qmail-queue
+ qmail-inject
+ predate
+ datemail
+ mailsubj
+ qmail-upq
+ qmail-showctl
+ qmail-newu
+ qmail-pw2u
+ qmail-qread
+ qmail-qstat
+ qmail-tcpto
+ qmail-tcpok
+ qmail-pop3d
+ qmail-popup
+ qmail-qmqpc
+ qmail-qmqpd
+ qmail-qmtpd
+ qmail-smtpd
+ sendmail
+ tcp-env
+ qmail-newmrh
+ config
+ config-fast
+ dnscname
+ dnsptr
+ dnsip
+ dnsmxip
+ dnsfq
+ hostname
+ ipmeprint
+ qreceipt
+ qsmhook
+ qbiff
+ forward
+ preline
+ condredirect
+ bouncesaying
+ except
+ maildirmake
+ maildir2mbox
+ maildirwatch
+ qail
+ elq
+ pinq
+ idedit
+ install-big
+ install
+ instcheck
+ home
+ home+df
+ proc
+ proc+df
+ binm1
+ binm1+df
+ binm2
+ binm2+df
+ binm3
+ binm3+df
+ qmail-dk
Index: qmail/ChangeLog.arctic.org
diff -c /dev/null qmail/ChangeLog.arctic.org:1.36
*** /dev/null	Fri Aug  7 11:03:19 2009
--- qmail/ChangeLog.arctic.org	Tue Dec 26 02:54:15 2006
***************
*** 0 ****
--- 1,213 ----
+ Tue Dec 26 02:53:38 2006  dean gaudet <dean@arctic.org>
+ 	
+ 	* qmail-remote.c: fix segfault due to missing prototypes -- include
+ 	  openssl/err.h.
+ 
+ Fri Oct 20 01:12:09 2006  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: allow at most 5 MAIL FROM or RCPT TO failures
+ 	  configurable via smtp_max_failures control file.
+ 
+ Fri Jul 21 12:23:15 2006  dean gaudet <dean@arctic.org>
+ 
+ 	* readwrite.h: include unistd to get the right read/write prototypes
+ 	* ipme.c: apply
+ 	http://www.suspectclass.com/~sgifford/qmail/qmail-0.0.0.0.patch
+ 	* qmail-local.c: apply bugfix from netqmail-1.05
+ 
+ Sat May  6 21:29:22 2006  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: if no checkpasswd is given then disable SMTP AUTH
+ 
+ Sat May  6 15:42:00 2006  dean gaudet <dean@arctic.org>
+ 
+ 	* bugfix to qmail-smtpd.c -- was using RELAYCLIENT env var where it
+ 	  should use relayclient local
+ 	* apply http://qmail.org/qmail-1.03-dk-0.54.patch
+ 	* added qmail-dk install targets to hier.c
+ 	* added qmail-dk exit codes to qmail.c
+ 
+ Fri Jan 13 14:22:12 2006  dean gaudet <dean@arctic.org>
+ 
+ 	* apply http://www.qmail.org/outgoingip.patch
+ 
+ Tue Sep 27 00:00:00 2005  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-rspawn.c: support QMAILREMOTE env var for alternate
+ 	  qmail-remote executable
+ 	* qmail.c: add X-Spam-Status error message
+ 
+ Wed Mar 30 15:31:23 2005  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: SSL_accept() wasn't being timed out... and we weren't
+ 	  using safewrite when doing ssl -- it was possible for clients to
+ 	  DoS us by closing their tcp window and causing our writes to block.
+ 	  Also lowered default timeout to 30 seconds.
+ 
+ Thu Mar 10 23:47:39 2005  dean gaudet <dean@arctic.org>
+ 
+ 	* control.c: read 16384 bytes at a time from control files
+ 	* qmail-smtpd.c: support rfc 3848 -- see also 
+ 	  <http://www.iana.org/assignments/mail-parameters> where
+ 	  it defines the "with protocol" type for Received headers.
+ 
+ Sun Jan 23 13:51:39 2005  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-send.c qmail-send.9: applied
+ 	  http://www.qmail.org/doublebounce-trim.patch
+ 
+ Fri Oct 29 22:32:45 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-lspawn.c: add QMAILLOCAL support so that we can send
+ 	  messages through /var/qmail/bin/spamodo before qmail-local.
+ 
+ Tue Oct 26 01:27:29 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail.c: add exit code 33 for viruses
+ 	* qmail-smtpd.c: revert qmail-smtpd-viruscan-1.3.patch ... we're using
+ 	  clamav now.
+ 	* qmail-smtpd.c: log all the DATA failure reasons
+ 
+ Wed Sep 29 16:17:22 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: added SMTP_TLS_FORCED environment variable which
+ 	  forces ssl initialisation even without starttls -- this is for
+ 	  port 465 ssmtp.
+ 
+ Tue Sep  7 10:53:30 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: added SMTP_AUTH_REQUIRED so we can start
+ 	  running this on port 587
+ 	* qmail-smtpd.c: log ehlo/helo
+ 	* qmail-smtpd.c: realmf support -- if the domain is local and the user
+ 	  can be proved not to exist then don't accept the MAIL FROM.
+ 
+ Tue Jul 13 22:33:01 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* Makefile qmail-qmtpd.c qmail-smtpd.c realrcptto.c: apply
+ 	  <http://multivac.cwru.edu/qmail/qmail-1.03-realrcptto-2004.02.05.patch>
+ 	  well only a small part of a cleanup in it... i redid
+ 	  logging in the way i prefer it (inside qmail-smtpd.c).
+ 
+ Tue Jul 13 21:57:26 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: log okrcptto, okmf, and rset -- which enables
+ 	  a bunch of log processing.
+ 
+ Thu Jul  8 23:15:18 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: fix an off-by-1 in signature support
+ 	* qmail-smtpd.c: support passing more arguments to checkpassword
+ 	  because i've switched to checkpassword-pam and want to pass
+ 	  it a -s qmail-smtpd.  to do this i removed cram-md5 support
+ 	  because we're not using it and it was an easier hack.
+ 
+ Wed Jan 28 23:48:07 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: clean up logging; log auth and tls info
+ 
+ Wed Jan 28 10:03:51 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* apply <http://qmail.area.com/qmail-smtpd-viruscan-1.3.patch>
+ 	  with logging addition (search for "virus signature")
+ 
+ Sun Jan 25 14:28:27 2004  dean gaudet <dean@arctic.org>
+ 
+ 	* Makefile qmail-qmtpd.c qmail-smtpd.c realrcptto.c: apply
+ 	  <http://multivac.cwru.edu/qmail/qmail-1.03-realrcptto-2003.12.23.patch>
+ 	  with some local mods for logging.
+ 
+ Sun Nov 16 14:49:21 2003  dean gaudet <dean@arctic.org>
+ 
+ 	* error.h: need to include errno.h for most recent glibc
+ 
+ Sat Sep 27 07:46:43 2003  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-queue.c: apply http://www.qmail.org/qmailqueue-patch
+ 
+ Wed Jun 18 10:39:29 2003  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: SSL sessions did not properly timeout -- the
+ 	  flagtimedout boolean wasn't being tested for SSL reads or
+ 	  writes.
+ 
+ Mon May 19 13:58:53 2003  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: applied
+ 	  <http://www.qmail.org/qmail-smtpd-relay-reject> with an
+ 	  additional logging tweak... i'm tired of seeing all the relay
+ 	  probes from places like dsbl.org.
+ 
+ Sun May 11 23:04:09 2003  dean gaudet <dean@arctic.org>
+ 
+ 	* sendmail.c: turns out pine uses "sendmail -bs" to mail
+ 	  which execs qmail-smtpd -- and pine doesn't like it if any of
+ 	  the subprocesses do anything on stderr.  so now sendmail -bs
+ 	  will set up a pipe to "splogger sendmail-bs" on stderr.
+ 
+ Sun May 11 20:43:06 2003  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: log "pid N qp M" for each message... so that
+ 	  the logs contain complete info to be able to tie together
+ 	  tcpserver stats with the info logged by qmail-queue.
+ 
+ Sun May 11 20:24:15 2003  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: require a domain in MAIL FROM:<foo>
+ 
+ Sun Apr 13 10:13:25 2003  dale woolridge <dale@woolridge.ca>
+ 	* qmail-smtpd.c: log mailfrom on badrcptto trigger
+ 
+ Sun Oct 27 20:43:50 2002  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd.c: use TCPLOCALIP rather than TCPLOCALHOST
+ 	  because TCPLOCALHOST is always 0 ... at least in
+ 	  twinlark's config (where we run tcpserver with addr 0)
+ 
+ Mon Jul 29 12:25:36 2002  dean gaudet <dean@arctic.org>
+ 
+ 	* tagged arctic-2 to distribute patch
+ 
+ Sat Jun  8 18:14:17 2002  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-smtpd now logs when it rejects mail due to badmailfrom,
+ 	  badrcptto, or mfcheck.
+ 
+ Fri May 31 10:06:20 2002  dean gaudet <dean@arctic.org>
+ 	
+ 	* applied http://www.qmail.org/www.jedi.claranet.fr/qmail-bounce.patch
+ 	  which limits the size of bounced messages
+ 	* applied http://www.qmail.org/qmail-1.03-mfcheck.3.patch which
+ 	  requires a valid domain in envelope from.
+ 
+ Mon Jan 28 13:01:25 2002  dean gaudet <dean@arctic.org>
+ 	
+ 	* update / apply my bare linefeed patch
+ 	  http://arctic.org/~dean/patches/qmail-0.95-liberal-lf.patch
+ 	  
+ Fri Dec 28 11:03:31 2001  dean gaudet <dean@arctic.org>
+ 
+ 	* tagged arctic-1 to distribute patch
+ 
+ Thu Dec 27 10:06:44 2001  dean gaudet <dean@arctic.org>
+ 
+ 	* picked up syncdir library from <http://untroubled.org/syncdir/>,
+ 	  this is necessary on linux because linux doesn't sync directory
+ 	  metadata.
+ 	* tweaked make-load.sh and Makefile to use syncdir for all
+ 	  executables.
+ 
+ Thu Dec 27 09:35:45 2001  dean gaudet <dean@arctic.org>
+ 
+ 	* qmail-1.03 was imported, source <ftp://cr.yp.to/software/>
+ 	* badrcptto patch was added, source
+ 	  <http://patch.be/qmail/badrcptto.html>
+ 	* STARTTLS, SMTP AUTH, requireauth all added from patch at
+ 	  <http://drpepper.org/~zwhite/qmail-1.03-starttls-requireauth.patch>
+ 	  there was a small conflict with badrcptto which was easy to fix
+ 	* added (AUTH username) to Received: headers when SMTP AUTH is used
+ 	* note that there's a small difficulty with the checkpassword package
+ 	  when used with qmail-smtpd (for SMTP AUTH) -- since qmail-smtpd
+ 	  does NOT run as root, checkpassword won't be able to change
+ 	  uid/gid ... i just commented out the uid/gid changes and recompiled,
+ 	  and then named it /bin/checkpassword-smtp.
Index: qmail/Makefile
diff -c qmail/Makefile:1.1.1.1 qmail/Makefile:1.12
*** qmail/Makefile:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/Makefile	Sat May  6 16:37:21 2006
***************
*** 808,816 ****
  forward preline condredirect bouncesaying except maildirmake \
  maildir2mbox maildirwatch qail elq pinq idedit install-big install \
  instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
  binm3 binm3+df
  
! load: \
  make-load warn-auto.sh systype
  	( cat warn-auto.sh; ./make-load "`cat systype`" ) > load
  	chmod 755 load
--- 808,821 ----
  forward preline condredirect bouncesaying except maildirmake \
  maildir2mbox maildirwatch qail elq pinq idedit install-big install \
  instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
+ qmail-dk \
  binm3 binm3+df
  
! libsyncdir.a: \
! makelib syncdir.o
! 	./makelib libsyncdir.a syncdir.o
! 
! load: libsyncdir.a \
  make-load warn-auto.sh systype
  	( cat warn-auto.sh; ./make-load "`cat systype`" ) > load
  	chmod 755 load
***************
*** 1107,1112 ****
--- 1112,1141 ----
  	| sed s}SPAWN}"`head -1 conf-spawn`"}g \
  	> qmail-control.5
  
+ qmail-dk: \
+ load qmail-dk.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 fd.a wait.a \
+ ../libdomainkeys/libdomainkeys.a env.a getln.a control.o stralloc.a dns.lib
+ 	./load qmail-dk triggerpull.o fmtqfn.o now.o \
+ 	date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \
+ 	substdio.a error.a fs.a auto_qmail.o \
+ 	auto_split.o auto_uids.o \
+ 	fd.a wait.a \
+         ../libdomainkeys/libdomainkeys.a -lcrypto env.a control.o open.a getln.a \
+ 	stralloc.a alloc.a  scan_ulong.o str.a `cat dns.lib`
+ 
+ qmail-dk.0: \
+ qmail-dk.8
+ 	nroff -man qmail-dk.8 > qmail-dk.0
+ 
+ qmail-dk.o: \
+ compile qmail-dk.c readwrite.h sig.h exit.h open.h seek.h fmt.h \
+ alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \
+ env.h wait.h fd.h fork.h str.h \
+ auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
+ 	./compile qmail-dk.c
+ 
  qmail-getpw: \
  load qmail-getpw.o case.a substdio.a error.a str.a fs.a auto_break.o \
  auto_usera.o
***************
*** 1200,1210 ****
  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
--- 1229,1239 ----
  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 env.a str_diffn.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 env.a str_diffn.o
  
  qmail-lspawn.0: \
  qmail-lspawn.8
***************
*** 1213,1219 ****
  qmail-lspawn.o: \
  compile qmail-lspawn.c fd.h wait.h prot.h substdio.h stralloc.h \
  gen_alloc.h scan.h exit.h fork.h error.h cdb.h uint32.h case.h \
! slurpclose.h auto_qmail.h auto_uids.h qlx.h
  	./compile qmail-lspawn.c
  
  qmail-newmrh: \
--- 1242,1248 ----
  qmail-lspawn.o: \
  compile qmail-lspawn.c fd.h wait.h prot.h substdio.h stralloc.h \
  gen_alloc.h scan.h exit.h fork.h error.h cdb.h uint32.h case.h \
! slurpclose.h auto_qmail.h auto_uids.h qlx.h env.h
  	./compile qmail-lspawn.c
  
  qmail-newmrh: \
***************
*** 1367,1380 ****
  	./compile qmail-qmqpd.c
  
  qmail-qmtpd: \
! load qmail-qmtpd.o rcpthosts.o control.o constmap.o received.o \
  date822fmt.o now.o qmail.o cdb.a 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 rcpthosts.o control.o constmap.o \
  	received.o date822fmt.o now.o qmail.o cdb.a 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
--- 1396,1410 ----
  	./compile qmail-qmqpd.c
  
  qmail-qmtpd: \
! load qmail-qmtpd.o realrcptto.o rcpthosts.o control.o constmap.o received.o \
  date822fmt.o now.o qmail.o cdb.a 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 auto_break.o auto_usera.o
! 	./load qmail-qmtpd realrcptto.o rcpthosts.o control.o constmap.o \
  	received.o date822fmt.o now.o qmail.o cdb.a 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 auto_break.o \
! 	auto_usera.o
  
  qmail-qmtpd.0: \
  qmail-qmtpd.8
***************
*** 1446,1452 ****
  	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
--- 1476,1483 ----
  	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` \
! 	-L/usr/local/ssl/lib -lssl -lcrypto
  
  qmail-remote.0: \
  qmail-remote.8
***************
*** 1467,1473 ****
  	./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
--- 1498,1504 ----
  	./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 env.a str_diffn.o
  
  qmail-rspawn.0: \
  qmail-rspawn.8
***************
*** 1475,1481 ****
  
  qmail-rspawn.o: \
  compile qmail-rspawn.c fd.h wait.h substdio.h exit.h fork.h error.h \
! tcpto.h
  	./compile qmail-rspawn.c
  
  qmail-send: \
--- 1506,1512 ----
  
  qmail-rspawn.o: \
  compile qmail-rspawn.c fd.h wait.h substdio.h exit.h fork.h error.h \
! tcpto.h env.h
  	./compile qmail-rspawn.c
  
  qmail-send: \
***************
*** 1483,1494 ****
  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
--- 1514,1525 ----
  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 env.a
  	./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 env.a
  
  qmail-send.0: \
  qmail-send.8
***************
*** 1532,1548 ****
  	./compile qmail-showctl.c
  
  qmail-smtpd: \
! load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
  timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
  date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
  open.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 rcpthosts.o commands.o timeoutread.o \
  	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
  	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
  	datetime.a getln.a open.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
--- 1563,1580 ----
  	./compile qmail-showctl.c
  
  qmail-smtpd: \
! load qmail-smtpd.o realrcptto.o rcpthosts.o commands.o timeoutread.o \
  timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
  date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
  open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
! fs.a auto_qmail.o auto_break.o auto_usera.o socket.lib dns.o dns.lib
! 	./load qmail-smtpd realrcptto.o rcpthosts.o commands.o timeoutread.o \
  	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
  	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
  	datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
! 	alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_break.o \
! 	auto_usera.o `cat socket.lib` dns.o `cat dns.lib` \
! 	-L/usr/local/ssl/lib -lssl -lcrypto
  
  qmail-smtpd.0: \
  qmail-smtpd.8
***************
*** 1686,1691 ****
--- 1718,1728 ----
  auto_split.h
  	./compile readsubdir.c
  
+ realrcptto.o: \
+ compile realrcptto.c auto_break.h auto_usera.h byte.h case.h cdb.h \
+ constmap.h error.h fmt.h open.h str.h stralloc.h uint32.h
+ 	./compile realrcptto.c
+ 
  received.o: \
  compile received.c fmt.h qmail.h substdio.h now.h datetime.h \
  datetime.h date822fmt.h received.h
***************
*** 2053,2058 ****
--- 2090,2099 ----
  compile substdo.c substdio.h str.h byte.h error.h
  	./compile substdo.c
  
+ syncdir.o: \
+ compile syncdir.c
+ 	./compile syncdir.c
+ 
  syslog.lib: \
  trysyslog.c compile load
  	( ( ./compile trysyslog.c && \
***************
*** 2139,2141 ****
--- 2180,2201 ----
  wait_pid.o: \
  compile wait_pid.c error.h haswaitp.h
  	./compile wait_pid.c
+ 
+ cert:
+ 	/usr/bin/openssl req -new -x509 -nodes \
+ 	-out /var/qmail/control/servercert.pem -days 366 \
+ 	-keyout /var/qmail/control/servercert.pem
+ 	chmod 640 /var/qmail/control/servercert.pem
+ 	chown qmaild.qmail /var/qmail/control/servercert.pem
+ 	ln -s /var/qmail/control/servercert.pem /var/qmail/control/clientcert.pem
+ 
+ cert-req:
+ 	/usr/bin/openssl req -new -nodes \
+ 	-out req.pem \
+ 	-keyout /var/qmail/control/servercert.pem
+ 	chmod 640 /var/qmail/control/servercert.pem
+ 	chown qmaild.qmail /var/qmail/control/servercert.pem
+ 	ln -s /var/qmail/control/servercert.pem /var/qmail/control/clientcert.pem
+ 	@echo
+ 	@echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
+ 	@echo "cat signed_req.pem >> /var/qmail/control/servercert.pem"
Index: qmail/README-starttls-requireauth
diff -c /dev/null qmail/README-starttls-requireauth:1.2
*** /dev/null	Fri Aug  7 11:03:19 2009
--- qmail/README-starttls-requireauth	Wed Dec 26 20:41:14 2001
***************
*** 0 ****
--- 1,1450 ----
+ Wed Dec 26 20:40:00 2001  dean gaudet <dean@arctic.org>
+ - note that there's some stupid prot_gid()/prot_uid() crap
+   in checkpassword.c which isn't necessary for qmail-smtpd to
+   work with SMTP AUTH ... and since it won't be running as root
+   you'll need to hack checkpassword.c to disable that crap.
+ 
+ 
+ ---
+ 
+ 
+ Zach White <zwhite@netlsd.org> 20010812
+ http://drpepper.org/~zwhite/qmail-1.03-starttls-requireauth
+ 
+ This patch combines 3 patches that seem to conflict with one another.
+ The first is Frederick Wermeulen's tls.patch to implement STARTTLS in
+ qmail-smtpd and qmail-remote. The other two are for SMTP AUTH, so you can
+ authenticate a user before allowing them to relay. The first is Krzysztof 
+ Dabrowski's patch to implement SMTP AUTH, the second is dburkes@netable.com's
+ patch to require AUTH.
+ 
+ Frederick Wermeulen released his patch under the same license as qmail, 
+ however after consulting him the license was more restrictive than he
+ intended, and he has granted me permission to incorporate his patch into
+ this patch.
+ 
+ Sources:
+ http://www.esat.kuleuven.ac.be/~vermeule/qmail/tls.patch  STARTTLS
+ http://members.elysium.pl/brush/qmail-smtpd-auth/         SMTP AUTH
+ http://www.netable.com/~dburkes/qmail-smtpd-requireauth/  Require AUTH
+ http://www.elysium.pl/members/brush/cmd5checkpw/         CRAM-MD5 Checkpassword
+ 
+ Usage:
+ 
+ Apply this patch. Compile, install, blah, blah. Put your pem enceded server
+ key in /var/qmail/control/servercert.pem. Chown it to qmails, chmod it 600.
+ Change your qmail-smtpd invoction to call "qmail-smtpd <checkpassword> <path 
+ to true> <cram-md5 checkpassword> <pah to true>" instead of just qmail-send. 
+ Setup either tcp wrappers or your tcprules file to add the environment 
+ variable REQUIREAUTH="" for IP's you wish to require authentication from.
+ 
+ If you run into problems with this patch, tcpdump and strace are your friend.
+ 
+ This was tested using Netscape 4.75's mail client, with the require TLS option
+ checked. It asked me for a password and then sent the mail. You should see
+ headers similer to the following if everything worked correctly:
+ 
+ Received: from unknown (HELO netlsd.org) (192.168.0.13) by 192.168.0.1 with RC4-MD5 encrypted SMTP; 12 Aug 2001 23:26:59 -0000
+ 
+ The Recieved header indicates that tls was used and what cipher type.
+ 
+ Questions, comments, and deathtreats can be sent to zwhite@netlsd.org. If you
+ are having problems getting it to work, I probably won't help you, I do 
+ enough of that with my real job. If you've found a bug and have a patch, 
+ I'd love to see it. If you've found a bug and don't know how to fix it,
+ I'll see if I can (But I'm not a programmer, and I'm not really sure this
+ is the best way to have combined the patches. I'm just a sysadmin who needed
+ this to work.)
+ 
+ I've attached all the original documentation. You may find it useful.
+ 
+ ---- Included at the top of the starttls patchfile ----
+ Frederik Vermeulen <jos-tls@kotnet.org> 20010627
+ http://www.esat.kuleuven.ac.be/~vermeule/qmail/tls.patch
+ 
+ This patch implements RFC2487 in qmail. This means you can 
+ get SSL or TLS encrypted and authenticated SMTP between 
+ the MTAs and between MTA and an MUA like Netscape. 
+ The code is considered experimental (but has worked for
+ many since its first release on 1999-03-21).
+ 
+ Usage: - install OpenSSL-0.9.6a http://www.openssl.org/
+        - apply patch to qmail-1.03 http://www.qmail.org/ 
+          Makefile and conf-cc were patched for appropriate
+          linking. Apart from that, the patches to qmail-remote.c
+          and qmail-smtpd.c can be applied separately.
+        - provide a server certificate in /var/qmail/control/servercert.pem.
+          "make cert" makes a self-signed certificate.
+          "make cert-req" makes a certificate request.
+          Note: you can add the CA certificate and intermediate
+          certs to the end of servercert.pem.
+        - replace qmail-smtpd and/or qmail-remote binary
+        - verify operation (header information should show
+          somothing like
+          "Received [..] with DES-CBC3-SHA encrypted SMTP;")
+          If you don't have a server to test with, you can test
+          by sending mail to ping@mail.linux.student.kuleuven.ac.be,
+          which will bounce your mail.
+ 
+ Optional: - when DEBUG is defined, some extra TLS info will be logged
+           - qmail-remote will authenticate with the certificate in
+             /var/qmail/control/clientcert.pem. By preference this is
+             the same as servercert.pem, where nsCertType should be 
+             == server,client or be a generic certificate (no usage specified). 
+           - when a 512 RSA key is provided in /var/qmail/control/rsa512.pem,
+             this key will be used instead of on-the-fly generation by
+             qmail-smtpd. Periodical replacement can be done by crontab:
+             01 01 * * *  umask 0077; /usr/local/ssl/bin/openssl genrsa \
+              -out /var/qmail/control/rsa512.new 512 > /dev/null 2>&1;\
+              chmod 600 /var/qmail/control/rsa512.new; chown qmaild.qmail \
+              /var/qmail/control/rsa512.new; /bin/mv -f \
+              /var/qmail/control/rsa512.new /var/qmail/control/rsa512.pem
+           - server authentication:
+             qmail-remote requires authentication from servers for which
+             /var/qmail/control/tlshosts/host.dom.ain.pem exists.
+             The .pem file contains the validating CA certificates
+             (or self-signed server certificate with openssl-0.9.5).
+             CommonName has to match.
+             WARNING: this option may cause mail to be delayed, bounced,
+             doublebounced, and lost.
+           - client authentication:
+             when relay rules would reject an incoming mail, 
+             qmail-smtpd can allow the mail based on a presented cert.
+             Certs are verified against a CA list in 
+             /var/qmail/control/clientca.pem (eg. http://www.modssl.org/
+             source/cvs/exp/mod_ssl/pkg.mod_ssl/pkg.sslcfg/ca-bundle.crt)
+             and the cert email-address has to match a line in
+             /var/qmail/control/tlsclients. This email-address is logged
+             in the headers.
+           - cipher selection:
+             qmail-remote: 
+               openssl cipher string read from 
+               /var/qmail/control/tlsclientciphers
+             qmail-smtpd: 
+               openssl cipher string read from TLSCIPHERS environment variable
+               (can be different based on client IP address e.g.)
+               or if that is not available /var/qmail/control/tlsserverciphers
+ 
+ Caveats: - from this version on the server cert is in servercert.pem.
+          - binaries dynamically linked with current openssl versions need
+            recompilation when the shared openssl libs are upgraded.
+          - this patch could conflict with other patches (notably those
+            replacing \n with \r\n, which is a bad idea on encrypted links).
+          - some broken servers have a problem with TLSv1 compatibility.
+            Uncomment the line where we set the SSL_OP_NO_TLSv1 option.
+ 
+ Copyright: Same terms as qmail
+            Links with OpenSSL
+            Inspiration and code from examples in SSLeay (E. Young
+            <eay@cryptsoft.com> and T. Hudson <tjh@cryptsoft.com>),
+            stunnel (M. Trojnara <mtrojnar@ddc.daewoo.com.pl>),
+            Postfix/TLS (L. Jaenicke <Lutz.Jaenicke@aet.tu-cottbus.de>),
+            and modssl (R. Engelschall <rse@engelschall.com>).
+            Debug code, tlscipher selection, many feature suggestions,
+            French docs https://www.TBS-internet.com/ssl/qmail-tls.html 
+            from Jean-Philippe Donnio <tag-ssl@tbs-internet.com>
+            Openssl usage consulting from Bodo M"oller <bmoeller@acm.org>
+            Bug report from Andy Dustman <adustman@comstar.net>
+ 
+ Bug reports: mailto:<jos-tls@kotnet.org>
+ 
+ ----- README file from qmail-smtpd-auth-0.26 -----
+ 
+ This patch adds support for smtp auth authetication protocol to qmail.
+ It's based on Mrs.Brisby's smtp-auth patch with large enhancemets from me.
+ 
+ You can always get the newest version from:
+ http://members.elysium.pl/brush/qmail-smtpd-auth/
+ 
+ To use all of it's fuctionality you will also have to obtain and install
+ my cmd5checkpw utility available at:
+ http://members.elysium.pl/brush/cmd5checkpw/
+ 
+ If you need more information about SMTP-AUTH itself and the client/server
+ support and configuration, visit: 
+ http://members.elysium.pl/brush/smtp-auth/
+ 
+ How to install it:
+ 
+ Simply patch your qmail-1.03 distribution with the included patch file and
+ recompile & install like usual.
+ Also obtain, unpack , compile and isntall cmd5checkpw utility and add sample
+ account to /etc/poppasswd file.
+ 
+ How to use it:
+ 
+ Patched qmail-smtpd should be invoked from inetd or tcpserver like this:
+ 
+ smtp stream tcp nowait qmaild /var/qmail/bin/tcp-env tcp-env /var/qmail/bin/qmail-smtpd /bin/checkpassword /bin/true /bin/cmd5checkpw /bin/true
+ 
+ the first parameter for qmail-smtpd is a checkpassword utility for clear
+ text auth types, the second is arg for checkpassword, the third is a name of
+ cram-md5 checkpassword utlity (my cmd5checkpw) and fourth is arg for it.
+ 
+ give yout inetd a kill -HUP or restart tcpserver and here you go.
+ 
+ Features:
+ 
+ This patch supports the following auth methods: LOGIN, PLAIN and CRAM-MD5
+ 
+ Compatibility :
+ 
+ The following MUA's are confirmed to work with this patch:
+ 
+ Eudora 4.2.2		-	CRAM-MD5
+ The Bat 1.39		-	LOGIN & CRAM-MD5
+ Outlook Express 4	- 	LOGIN
+ Outlook Express 5	-	LOGIN
+ Netscape 4.x		-	LOGIN
+ Netscape 4.0x		-	LOGIN
+ Pegassus Mail 3.1x	-	CRAM-MD5
+ 
+ Various compatibility issues:
+ 
+ There used to be a problem with Netscape's Messenger but it's over.
+ 
+ After test with Pegasus Mail 3.1 i've added the new style (rfc
+ recommended) greeting message. Yoo can select beetwen them by #defining or
+ ew#undefining USE_NEW_GREETING and USE_OLD_GREETING on the begining of 
+ qmail-smtpd.c (around line 30). You can even enable both to maintain highest degree of 
+ compatibility with various clients. This fix was suggested by 
+ David Harris <David.Harris@pmail.gen.nz>, the developer of Pegasus Mail.
+ 
+ ----- README file from qmail-smtpd-requireauth-0.30 -----
+ 
+ This patch enables you to optionally require authentication for qmail-smtpd 
+ clients.
+ 
+ How to install it:
+ 
+ First, apply Krzysztof Dabrowski's qmail-smtpd-auth patch version 0.30 (see 
+ http://members.elysium.pl/brush/qmail-smtpd-auth/).  Then, simply patch the 
+ resulting qmail-smtpd.c with the included patch file.  Recompile and install 
+ as usual.
+ 
+ How to use it:
+ 
+ If the REQUIREAUTH environment variable is set to anything (empty or 
+ non-empty), the patched qmail-smtpd will require the client to authenticate 
+ before accepting any MAIL FROM commands.
+ 
+ See http://www.netable.com/~dburkes/qmail-smtpd-requireauth/index.html for a 
+ practical usage scenario.
+ 
+ ----- End of Included documentation, patch below -----
+ 
+ diff -ur qmail-1.03.orig/Makefile qmail-1.03/Makefile
+ --- qmail-1.03.orig/Makefile	Mon Jun 15 10:53:16 1998
+ +++ qmail-1.03/Makefile	Sun Aug 12 23:35:33 2001
+ @@ -1446,7 +1446,8 @@
+  	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`
+ +	str.a fs.a auto_qmail.o  `cat dns.lib` `cat socket.lib` \
+ +	-L/usr/local/ssl/lib -lssl -lcrypto
+  
+  qmail-remote.0: \
+  qmail-remote.8
+ @@ -1542,7 +1543,7 @@
+  	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
+  	datetime.a getln.a open.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`
+ +	socket.lib` -L/usr/local/ssl/lib -lssl -lcrypto
+  
+  qmail-smtpd.0: \
+  qmail-smtpd.8
+ @@ -2139,3 +2140,22 @@
+  wait_pid.o: \
+  compile wait_pid.c error.h haswaitp.h
+  	./compile wait_pid.c
+ +
+ +cert:
+ +	/usr/local/ssl/bin/openssl req -new -x509 -nodes \
+ +	-out /var/qmail/control/servercert.pem -days 366 \
+ +	-keyout /var/qmail/control/servercert.pem
+ +	chmod 640 /var/qmail/control/servercert.pem
+ +	chown qmaild.qmail /var/qmail/control/servercert.pem
+ +	ln -s /var/qmail/control/servercert.pem /var/qmail/control/clientcert.pem
+ +
+ +cert-req:
+ +	/usr/local/ssl/bin/openssl req -new -nodes \
+ +	-out req.pem \
+ +	-keyout /var/qmail/control/servercert.pem
+ +	chmod 640 /var/qmail/control/servercert.pem
+ +	chown qmaild.qmail /var/qmail/control/servercert.pem
+ +	ln -s /var/qmail/control/servercert.pem /var/qmail/control/clientcert.pem
+ +	@echo
+ +	@echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
+ +	@echo "cat signed_req.pem >> /var/qmail/control/servercert.pem"
+ Only in qmail-1.03: Makefile.orig
+ diff -ur qmail-1.03.orig/conf-cc qmail-1.03/conf-cc
+ --- qmail-1.03.orig/conf-cc	Mon Jun 15 10:53:16 1998
+ +++ qmail-1.03/conf-cc	Sun Aug 12 23:35:35 2001
+ @@ -1,3 +1,3 @@
+ -cc -O2
+ +cc -O2 -DTLS -I/usr/local/ssl/include
+  
+  This will be used to compile .c files.
+ Only in qmail-1.03: conf-cc.orig
+ diff -ur qmail-1.03.orig/dns.c qmail-1.03/dns.c
+ --- qmail-1.03.orig/dns.c	Mon Jun 15 10:53:16 1998
+ +++ qmail-1.03/dns.c	Sun Aug 12 23:35:38 2001
+ @@ -270,6 +270,14 @@
+  {
+   int r;
+   struct ip_mx ix;
+ +#ifdef TLS
+ + stralloc fqdn = {0};
+ +
+ + if (!stralloc_copy(&fqdn,sa)) return DNS_MEM;
+ + if (!stralloc_0(&fqdn)) return DNS_MEM;
+ + ix.fqdn = fqdn.s;
+ + alloc_free(fqdn);
+ +#endif
+  
+   if (!stralloc_copy(&glue,sa)) return DNS_MEM;
+   if (!stralloc_0(&glue)) return DNS_MEM;
+ @@ -330,6 +338,9 @@
+     ix.pref = 0;
+     if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
+      {
+ +#ifdef TLS
+ +     ix.fqdn = NULL;
+ +#endif
+       if (!ipalloc_append(ia,&ix)) return DNS_MEM;
+       return 0;
+      }
+ Only in qmail-1.03: dns.c.orig
+ diff -ur qmail-1.03.orig/ipalloc.h qmail-1.03/ipalloc.h
+ --- qmail-1.03.orig/ipalloc.h	Mon Jun 15 10:53:16 1998
+ +++ qmail-1.03/ipalloc.h	Sun Aug 12 23:35:38 2001
+ @@ -3,7 +3,12 @@
+  
+  #include "ip.h"
+  
+ +#ifdef TLS
+ +#include "stralloc.h"
+ +struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ;
+ +#else
+  struct ip_mx { struct ip_address ip; int pref; } ;
+ +#endif
+  
+  #include "gen_alloc.h"
+  
+ Only in qmail-1.03: ipalloc.h.orig
+ diff -ur qmail-1.03.orig/qmail-remote.c qmail-1.03/qmail-remote.c
+ --- qmail-1.03.orig/qmail-remote.c	Mon Jun 15 10:53:16 1998
+ +++ qmail-1.03/qmail-remote.c	Sun Aug 12 23:35:34 2001
+ @@ -26,8 +26,18 @@
+  #include "tcpto.h"
+  #include "readwrite.h"
+  #include "timeoutconn.h"
+ +#ifndef TLS
+  #include "timeoutread.h"
+  #include "timeoutwrite.h"
+ +#endif
+ +
+ +#ifdef TLS
+ +#include <sys/stat.h>
+ +#include <openssl/ssl.h>
+ +SSL *ssl = NULL;
+ +
+ +stralloc tlsclientciphers = {0};
+ +#endif
+  
+  #define HUGESMTPTEXT 5000
+  
+ @@ -107,17 +117,94 @@
+  int smtpfd;
+  int timeout = 1200;
+  
+ +#ifdef TLS
+ +int flagtimedout = 0;
+ +void sigalrm()
+ +{
+ + flagtimedout = 1;
+ +}
+ +
+ +int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
+ +{
+ + int r; int saveerrno;
+ + if (flagtimedout) { errno = error_timeout; return -1; }
+ + alarm(timeout);
+ + if (ssl) {
+ +   while(((r = SSL_read(ssl,buf,n)) <= 0)
+ +         && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_READ));
+ +   if (SSL_get_error(ssl, r) != SSL_ERROR_NONE)
+ +    {char buf[1024];
+ + 
+ +     out("ZTLS connection to "); outhost(); out(" died: ");
+ +     SSL_load_error_strings();
+ +     out(ERR_error_string(ERR_get_error(), buf)); out("\n");
+ +     SSL_shutdown(ssl);
+ +     zerodie();
+ +    }
+ + }else r = read(fd,buf,n);
+ + saveerrno = errno;
+ + alarm(0);
+ + if (flagtimedout) { errno = error_timeout; return -1; }
+ + errno = saveerrno;
+ + return r;
+ +}
+ +
+ +int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
+ +{
+ + int r; int saveerrno;
+ + if (flagtimedout) { errno = error_timeout; return -1; }
+ + alarm(timeout);
+ + if (ssl) {
+ +   while(((r = SSL_write(ssl,buf,n)) <= 0)
+ +         && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_WRITE));
+ +   if (SSL_get_error(ssl, r) != SSL_ERROR_NONE)
+ +    {char buf[1024];
+ +
+ +     out("ZTLS connection to "); outhost(); out(" died: ");
+ +     SSL_load_error_strings();
+ +     out(ERR_error_string(ERR_get_error(), buf)); out("\n");
+ +     SSL_shutdown(ssl);
+ +     zerodie();
+ +    }
+ + }else r = write(fd,buf,n);
+ + saveerrno = errno;
+ + alarm(0);
+ + if (flagtimedout) { errno = error_timeout; return -1; }
+ + errno = saveerrno;
+ + return r;
+ +}
+ +
+ +static int client_cert_cb(SSL *s,X509 **x509, EVP_PKEY **pkey)
+ +{
+ + out("ZTLS found no client cert in control/clientcert.pem\n");
+ + zerodie(NULL,NULL);
+ +}
+ +
+ +static int verify_cb(int ok, X509_STORE_CTX * ctx)
+ +{
+ +  return (1);
+ +}
+ +#endif 
+ +
+  int saferead(fd,buf,len) int fd; char *buf; int len;
+  {
+    int r;
+ +#ifdef TLS
+ +  r = ssl_timeoutread(timeout,smtpfd,buf,len);
+ +#else
+    r = timeoutread(timeout,smtpfd,buf,len);
+ +#endif
+    if (r <= 0) dropped();
+    return r;
+  }
+  int safewrite(fd,buf,len) int fd; char *buf; int len;
+  {
+    int r;
+ +#ifdef TLS
+ +  r = ssl_timeoutwrite(timeout,smtpfd,buf,len);
+ +#else
+    r = timeoutwrite(timeout,smtpfd,buf,len);
+ +#endif
+    if (r <= 0) dropped();
+    return r;
+  }
+ @@ -186,6 +273,34 @@
+    out(append);
+    out(".\n");
+    outsmtptext();
+ +
+ +/* TAG */
+ +#if defined(TLS) && defined(DEBUG)
+ +#define ONELINE_NAME(X) X509_NAME_oneline(X,NULL,0)
+ +
+ + if(ssl){
+ + X509 *peer;
+ +
+ +  out("STARTTLS proto="); out(SSL_get_version(ssl));
+ +  out("; cipher="); out(SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
+ +
+ +  /* we want certificate details */
+ +  peer=SSL_get_peer_certificate(ssl);
+ +  if (peer != NULL) {
+ +   char *str;
+ +
+ +   str=ONELINE_NAME(X509_get_subject_name(peer));
+ +   out("; subject="); out(str);
+ +   Free(str);
+ +   str=ONELINE_NAME(X509_get_issuer_name(peer));
+ +   out("; issuer="); out(str);
+ +   Free(str);
+ +   X509_free(peer);
+ +  }
+ +  out(";\n");
+ + }
+ +#endif
+ +
+    zerodie();
+  }
+  
+ @@ -216,20 +331,158 @@
+  
+  stralloc recip = {0};
+  
+ +#ifdef TLS
+ +void smtp(fqdn)
+ +char *fqdn;
+ +#else
+  void smtp()
+ +#endif
+  {
+    unsigned long code;
+    int flagbother;
+    int i;
+ - 
+ +#ifdef TLS
+ +  int needtlsauth = 0;
+ +  SSL_CTX *ctx;
+ +  int saveerrno, r;
+ +
+ +  stralloc servercert = {0};
+ +  struct stat st;
+ +  if(fqdn){
+ +   if(!stralloc_copys(&servercert, "control/tlshosts/")) temp_nomem();
+ +   if(!stralloc_catb(&servercert, fqdn, str_len(fqdn))) temp_nomem();
+ +   if(!stralloc_catb(&servercert, ".pem", 4)) temp_nomem();
+ +   if(!stralloc_0(&servercert)) temp_nomem();
+ +   if (stat(servercert.s,&st) == 0)  needtlsauth = 1;
+ +  }
+ +#endif
+ +
+    if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
+   
+ +#ifdef TLS
+ +  substdio_puts(&smtpto,"EHLO ");
+ +#else
+    substdio_puts(&smtpto,"HELO ");
+ +#endif
+    substdio_put(&smtpto,helohost.s,helohost.len);
+    substdio_puts(&smtpto,"\r\n");
+    substdio_flush(&smtpto);
+ +#ifdef TLS
+ +  if (smtpcode() != 250){
+ +   substdio_puts(&smtpto,"HELO ");
+ +   substdio_put(&smtpto,helohost.s,helohost.len);
+ +   substdio_puts(&smtpto,"\r\n");
+ +   substdio_flush(&smtpto);
+ +   if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
+ +  }
+ +#else
+    if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
+ - 
+ +#endif
+ +
+ +#ifdef TLS
+ +  i = 0; 
+ +  while((i += str_chr(smtptext.s+i,'\n') + 1) && (i+12 < smtptext.len) &&
+ +        str_diffn(smtptext.s+i+4,"STARTTLS\n",9));
+ +  if (i+12 < smtptext.len)
+ +   {
+ +    substdio_puts(&smtpto,"STARTTLS\r\n");
+ +    substdio_flush(&smtpto);
+ +    if (smtpcode() == 220)
+ +     {
+ +      SSL_library_init();
+ +      if(!(ctx=SSL_CTX_new(SSLv23_client_method())))
+ +       {char buf[1024];
+ +
+ +        out("ZTLS not available: error initializing ctx: ");
+ +        SSL_load_error_strings();
+ +        out(ERR_error_string(ERR_get_error(), buf));
+ +        out("\n");
+ +        SSL_shutdown(ssl);
+ +        zerodie();
+ +      }
+ +      if((stat("control/clientcert.pem", &st) == 0) &&
+ +         ((SSL_CTX_use_RSAPrivateKey_file(ctx, "control/clientcert.pem", SSL_FILETYPE_PEM) <= 0) ||
+ +         (SSL_CTX_use_certificate_chain_file(ctx, "control/clientcert.pem") <= 0) ||
+ +         (SSL_CTX_check_private_key(ctx) <= 0)))
+ +        /* if there is a cert and it is bad, I fail
+ +           if there is no cert, I leave it to the other side to complain */
+ +        SSL_CTX_set_client_cert_cb(ctx, client_cert_cb);
+ + 
+ +      /*SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);*/
+ +      SSL_CTX_set_cipher_list(ctx,tlsclientciphers.s);
+ + 
+ +      if (needtlsauth){
+ +        if (!SSL_CTX_load_verify_locations(ctx, servercert.s, NULL))
+ +          {out("ZTLS unable to load "); out(servercert.s); out("\n");
+ +           zerodie();}
+ +        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
+ +      }
+ +     
+ +      if(!(ssl=SSL_new(ctx)))
+ +        {char buf[1024];
+ +
+ +         out("ZTLS not available: error initializing ssl: "); 
+ +         SSL_load_error_strings();
+ +         out(ERR_error_string(ERR_get_error(), buf));
+ +         out("\n");
+ +         SSL_shutdown(ssl);
+ +         zerodie();
+ +        }
+ +      SSL_set_fd(ssl,smtpfd);
+ +
+ +      alarm(timeout);
+ +      r = SSL_connect(ssl); saveerrno = errno;
+ +      alarm(0); 
+ +      if (flagtimedout) 
+ +       {out("ZTLS not available: connect timed out\n");
+ +        zerodie();}
+ +      errno = saveerrno;
+ +      if (r<=0)
+ +        {char buf[1024];
+ +
+ +         out("ZTLS not available: connect failed: ");
+ +         SSL_load_error_strings();
+ +         out(ERR_error_string(ERR_get_error(), buf));
+ +         out("\n");
+ +         SSL_shutdown(ssl);
+ +         zerodie();
+ +        }
+ +      if (needtlsauth)
+ +       /* should also check alternate names */
+ +       {char commonName[256];
+ +
+ +        if ((r=SSL_get_verify_result(ssl)) != X509_V_OK)
+ +         {out("ZTLS unable to verify server with ");
+ +          out(servercert.s); out(": ");
+ +          out(X509_verify_cert_error_string(r)); out("\n");
+ +          zerodie();
+ +         }
+ +        X509_NAME_get_text_by_NID(X509_get_subject_name(
+ +                                   SSL_get_peer_certificate(ssl)),
+ +                                   NID_commonName, commonName, 256);
+ +        if (strcasecmp(fqdn,commonName)){
+ +         out("ZTLS connection to "); out(fqdn);
+ +         out(" wanted, certificate for "); out(commonName);
+ +         out(" received\n");
+ +         zerodie();}
+ +        }
+ +
+ +      substdio_puts(&smtpto,"EHLO ");
+ +      substdio_put(&smtpto,helohost.s,helohost.len);
+ +      substdio_puts(&smtpto,"\r\n");
+ +      substdio_flush(&smtpto);
+ +
+ +      if (smtpcode() != 250)
+ +       {
+ +        quit("ZTLS connected to "," but my name was rejected");
+ +       }
+ +     } 
+ +   }
+ +  if ((!ssl) && needtlsauth)
+ +   {out("ZNo TLS achieved while "); out(servercert.s); out(" exists.\n");
+ +    quit();}
+ +#endif
+ +
+    substdio_puts(&smtpto,"MAIL FROM:<");
+    substdio_put(&smtpto,sender.s,sender.len);
+    substdio_puts(&smtpto,">\r\n");
+ @@ -324,6 +577,11 @@
+      case 1:
+        if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
+    }
+ +#ifdef TLS
+ +  if (control_rldef(&tlsclientciphers,"control/tlsclientciphers",0,"DEFAULT") != 1)
+ +    temp_control();
+ +  if(!stralloc_0(&tlsclientciphers)) temp_nomem();
+ +#endif
+  }
+  
+  void main(argc,argv)
+ @@ -338,7 +596,10 @@
+    int flagallaliases;
+    int flagalias;
+    char *relayhost;
+ - 
+ +
+ +#ifdef TLS
+ +  sig_alarmcatch(sigalrm);
+ +#endif
+    sig_pipeignore();
+    if (argc < 4) perm_usage();
+    if (chdir(auto_qmail) == -1) temp_chdir();
+ @@ -417,7 +678,11 @@
+      if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
+        tcpto_err(&ip.ix[i].ip,0);
+        partner = ip.ix[i].ip;
+ +#ifdef TLS
+ +      smtp(ip.ix[i].fqdn); /* does not return */
+ +#else
+        smtp(); /* does not return */
+ +#endif
+      }
+      tcpto_err(&ip.ix[i].ip,errno == error_timeout);
+      close(smtpfd);
+ Only in qmail-1.03: qmail-remote.c.orig
+ diff -ur qmail-1.03.orig/qmail-smtpd.c qmail-1.03/qmail-smtpd.c
+ --- qmail-1.03.orig/qmail-smtpd.c	Mon Jun 15 10:53:16 1998
+ +++ qmail-1.03/qmail-smtpd.c	Sun Aug 12 23:35:34 2001
+ @@ -1,4 +1,7 @@
+  #include "sig.h"
+ +#include <stdio.h>
+ +#include <unistd.h>
+ +#include <string.h>
+  #include "readwrite.h"
+  #include "stralloc.h"
+  #include "substdio.h"
+ @@ -16,22 +19,80 @@
+  #include "scan.h"
+  #include "byte.h"
+  #include "case.h"
+ +#include "wait.h"
+  #include "env.h"
+  #include "now.h"
+  #include "exit.h"
+  #include "rcpthosts.h"
+ +#ifndef TLS
+  #include "timeoutread.h"
+  #include "timeoutwrite.h"
+ +#endif
+  #include "commands.h"
+ +#ifdef TLS
+ +#include <openssl/ssl.h>
+ +SSL *ssl = NULL;
+ +
+ +stralloc clientcert = {0};
+ +stralloc tlsserverciphers = {0};
+ +#endif
+  
+  #define MAXHOPS 100
+ +#define USE_SMTPAUTH
+ +/*
+ +#define USE_OLD_GREETING
+ +#define USE_NEW_GREETING
+ +*/
+ +
+  unsigned int databytes = 0;
+  int timeout = 1200;
+  
+ +#ifdef TLS
+ +int flagtimedout = 0;
+ +void sigalrm()
+ +{
+ + flagtimedout = 1;
+ +}
+ +int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
+ +{
+ + int r; int saveerrno;
+ + if (flagtimedout) { errno = error_timeout; return -1; }
+ + alarm(timeout);
+ + if (ssl) {
+ +   while(((r = SSL_read(ssl,buf,n)) <= 0)
+ +         && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_READ));
+ + }else r = read(fd,buf,n);
+ + saveerrno = errno;
+ + alarm(0);
+ + if (flagtimedout) { errno = error_timeout; return -1; }
+ + errno = saveerrno;
+ + return r;
+ +}
+ +int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
+ +{
+ + int r; int saveerrno;
+ + if (flagtimedout) { errno = error_timeout; return -1; }
+ + alarm(timeout);
+ + if (ssl) { 
+ +   while(((r = SSL_write(ssl,buf,n)) <= 0)
+ +         && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_WRITE));
+ + }else r = write(fd,buf,n);
+ + saveerrno = errno;
+ + alarm(0);
+ + if (flagtimedout) { errno = error_timeout; return -1; }
+ + errno = saveerrno;
+ + return r;
+ +}
+ +#endif
+ +
+  int safewrite(fd,buf,len) int fd; char *buf; int len;
+  {
+    int r;
+ +#ifdef TLS
+ +  r = ssl_timeoutwrite(timeout,fd,buf,len);
+ +#else
+    r = timeoutwrite(timeout,fd,buf,len);
+ +#endif
+    if (r <= 0) _exit(1);
+    return r;
+  }
+ @@ -45,12 +106,17 @@
+  void die_read() { _exit(1); }
+  void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
+  void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
+ +void die_crash() { out("421 child crashed (#4.3.0)\r\n"); flush(); _exit(1); }
+ +void die_fork() { out("421 unable to start checkpassword.\r\n"); flush(); _exit(1); }
+  void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
+  void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
+  void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
+  
+  void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
+  void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
+ +#ifdef TLS
+ +void err_nogwcert() { out("553 no valid cert for gatewaying (#5.7.1)\r\n"); }
+ +#endif
+  void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
+  void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
+  void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
+ @@ -81,13 +147,16 @@
+  char *remoteinfo;
+  char *local;
+  char *relayclient;
+ +#ifdef TLS
+ +char *tlsciphers;
+ +#endif
+  
+  stralloc helohost = {0};
+  char *fakehelo; /* pointer into helohost, or 0 */
+  
+  void dohelo(arg) char *arg; {
+ -  if (!stralloc_copys(&helohost,arg)) die_nomem(); 
+ -  if (!stralloc_0(&helohost)) die_nomem(); 
+ +  if (!stralloc_copys(&helohost,arg)) die_nomem();
+ +  if (!stralloc_0(&helohost)) die_nomem();
+    fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
+  }
+  
+ @@ -101,7 +170,10 @@
+  {
+    char *x;
+    unsigned long u;
+ - 
+ +#ifdef TLS
+ +  char *tlsciphers;
+ +#endif
+ +
+    if (control_init() == -1) die_control();
+    if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)
+      die_control();
+ @@ -116,12 +188,12 @@
+    if (bmfok == -1) die_control();
+    if (bmfok)
+      if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+ - 
+ +
+    if (control_readint(&databytes,"control/databytes") == -1) die_control();
+    x = env_get("DATABYTES");
+    if (x) { scan_ulong(x,&u); databytes = u; }
+    if (!(databytes + 1)) --databytes;
+ - 
+ +
+    remoteip = env_get("TCPREMOTEIP");
+    if (!remoteip) remoteip = "unknown";
+    local = env_get("TCPLOCALHOST");
+ @@ -131,6 +203,17 @@
+    if (!remotehost) remotehost = "unknown";
+    remoteinfo = env_get("TCPREMOTEINFO");
+    relayclient = env_get("RELAYCLIENT");
+ +#ifdef TLS
+ +  if (tlsciphers = env_get("TLSCIPHERS")){
+ +    if (!stralloc_copys(&tlsserverciphers,tlsciphers)) die_nomem();
+ +  } 
+ +  else {
+ +    if (control_rldef(&tlsserverciphers,"control/tlsserverciphers",0,"DEFAULT") != 1) 
+ +      die_control();
+ +  }
+ +  if (!stralloc_0(&tlsserverciphers)) die_nomem();
+ +#endif
+ +
+    dohelo(remotehost);
+  }
+  
+ @@ -146,7 +229,7 @@
+    struct ip_address ip;
+    int flagesc;
+    int flagquoted;
+ - 
+ +
+    terminator = '>';
+    i = str_chr(arg,'<');
+    if (arg[i])
+ @@ -229,7 +312,18 @@
+  }
+  void smtp_ehlo(arg) char *arg;
+  {
+ -  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+ +  smtp_greet("250-"); 
+ +#ifdef TLS
+ +# ifdef USE_SMTPAUTH
+ +   if (ssl) out("\r\n250-PIPELINING\r\n250-AUTH LOGIN CRAM-MD5 PLAIN\r\n250 8BITMIME\r\n");
+ +   else out("\r\n250-PIPELINING\r\n250-STARTTLS\r\n250-AUTH LOGIN CRAM-MD5 PLAIN\r\n250 8BITMIME\r\n");
+ +# else
+ +   if (ssl) out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+ +   else out("\r\n250-PIPELINING\r\n250-STARTTLS\r\n250 8BITMIME\r\n");
+ +# endif /* USE_SMTP_AUTH */
+ +#else
+ +  out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+ +#endif /* TLS */
+    seenmail = 0; dohelo(arg);
+  }
+  void smtp_rset()
+ @@ -247,6 +341,12 @@
+    if (!stralloc_0(&mailfrom)) die_nomem();
+    out("250 ok\r\n");
+  }
+ +#ifdef TLS
+ +static int verify_cb(int ok, X509_STORE_CTX * ctx)
+ +{
+ +  return (1);
+ +}
+ +#endif
+  void smtp_rcpt(arg) char *arg; {
+    if (!seenmail) { err_wantmail(); return; }
+    if (!addrparse(arg)) { err_syntax(); return; }
+ @@ -257,7 +357,55 @@
+      if (!stralloc_0(&addr)) die_nomem();
+    }
+    else
+ +#ifndef TLS
+      if (!addrallowed()) { err_nogateway(); return; }
+ +#else
+ +    if (!addrallowed())
+ +     {
+ +      if (ssl)
+ +      { STACK_OF(X509_NAME) *sk;
+ +        X509 *peercert;
+ +        stralloc tlsclients = {0};
+ +        struct constmap maptlsclients;
+ +        int r;
+ +
+ +        SSL_set_verify(ssl,
+ +                       SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
+ +                       verify_cb);
+ +        if ((sk = SSL_load_client_CA_file("control/clientca.pem")) == NULL)
+ +         { err_nogateway(); return; }
+ +        SSL_set_client_CA_list(ssl, sk);
+ +        if((control_readfile(&tlsclients,"control/tlsclients",0) != 1) ||
+ +           !constmap_init(&maptlsclients,tlsclients.s,tlsclients.len,0))
+ +          { err_nogateway(); return; }
+ + 
+ +        SSL_renegotiate(ssl);
+ +        SSL_do_handshake(ssl);
+ +        ssl->state = SSL_ST_ACCEPT;
+ +        SSL_do_handshake(ssl);
+ +        if ((r = SSL_get_verify_result(ssl)) != X509_V_OK)
+ +         {out("553 no valid cert for gatewaying: ");
+ +          out(X509_verify_cert_error_string(r));
+ +          out(" (#5.7.1)\r\n");
+ +          return;
+ +         }
+ +  
+ +        if (peercert = SSL_get_peer_certificate(ssl))
+ +         {char emailAddress[256];
+ +
+ +          X509_NAME_get_text_by_NID(X509_get_subject_name(
+ +                                     SSL_get_peer_certificate(ssl)),
+ +                                     NID_pkcs9_emailAddress, emailAddress, 256);
+ +          if (!stralloc_copys(&clientcert, emailAddress)) die_nomem();
+ +          if (!constmap(&maptlsclients,clientcert.s,clientcert.len))
+ +            { err_nogwcert(); return; }
+ +          relayclient = "";
+ +         }
+ +          else { err_nogwcert(); return; }
+ +       }
+ +      else { err_nogateway(); return; }
+ +     }
+ +#endif
+    if (!stralloc_cats(&rcptto,"T")) die_nomem();
+    if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
+    if (!stralloc_0(&rcptto)) die_nomem();
+ @@ -269,7 +417,11 @@
+  {
+    int r;
+    flush();
+ +#ifdef TLS
+ +  r = ssl_timeoutread(timeout,fd,buf,len);
+ +#else
+    r = timeoutread(timeout,fd,buf,len);
+ +#endif
+    if (r == -1) if (errno == error_timeout) die_alarm();
+    if (r <= 0) die_read();
+    return r;
+ @@ -300,7 +452,7 @@
+    int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
+    int flagmaybey; /* 1 if this line might match \r\n, if fih */
+    int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
+ - 
+ +
+    state = 1;
+    *hops = 0;
+    flaginheader = 1;
+ @@ -369,6 +521,9 @@
+    int hops;
+    unsigned long qp;
+    char *qqx;
+ +#ifdef TLS
+ +  stralloc protocolinfo = {0};
+ +#endif
+   
+    if (!seenmail) { err_wantmail(); return; }
+    if (!rcptto.len) { err_wantrcpt(); return; }
+ @@ -377,8 +532,20 @@
+    if (qmail_open(&qqt) == -1) { err_qqt(); return; }
+    qp = qmail_qp(&qqt);
+    out("354 go ahead\r\n");
+ - 
+ +#ifdef TLS
+ +  if(ssl){
+ +   if (!stralloc_copys(&protocolinfo, SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)))) die_nomem();
+ +   if (!stralloc_catb(&protocolinfo, " encrypted SMTP", 15)) die_nomem();
+ +   if (clientcert.len){
+ +     if (!stralloc_catb(&protocolinfo," cert ", 6)) die_nomem();
+ +     if (!stralloc_catb(&protocolinfo,clientcert.s, clientcert.len)) die_nomem();
+ +   }
+ +   if (!stralloc_0(&protocolinfo)) die_nomem();
+ +  } else if (!stralloc_copyb(&protocolinfo,"SMTP",5)) die_nomem();
+ +  received(&qqt,protocolinfo.s,local,remoteip,remotehost,remoteinfo,case_diffs(remotehost,helohost.s) ? helohost.s : 0);
+ +#else
+    received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
+ +#endif
+    blast(&hops);
+    hops = (hops >= MAXHOPS);
+    if (hops) qmail_fail(&qqt);
+ @@ -394,22 +561,437 @@
+    out("\r\n");
+  }
+  
+ +#ifdef TLS
+ +static RSA *tmp_rsa_cb(ssl,export,keylength) SSL *ssl; int export; int keylength; 
+ +{
+ +  RSA* rsa;
+ +  BIO* in;
+ +
+ +  if (!export || keylength == 512)
+ +   if (in=BIO_new(BIO_s_file_internal()))
+ +    if (BIO_read_filename(in,"control/rsa512.pem") > 0)
+ +     if (rsa=PEM_read_bio_RSAPrivateKey(in,NULL,NULL,NULL))
+ +      return rsa;
+ +  return (RSA_generate_key(export?keylength:512,RSA_F4,NULL,NULL));
+ +}
+ +
+ +void smtp_tls(arg) char *arg; 
+ +{
+ +  SSL_CTX *ctx;
+ +
+ +  if (*arg)
+ +   {out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n");
+ +    return;}
+ +
+ +  SSL_library_init();
+ +  if(!(ctx=SSL_CTX_new(SSLv23_server_method())))
+ +   {out("454 TLS not available: unable to initialize ctx (#4.3.0)\r\n"); 
+ +    return;}
+ +  if(!SSL_CTX_use_RSAPrivateKey_file(ctx, "control/servercert.pem", SSL_FILETYPE_PEM))
+ +   {out("454 TLS not available: missing RSA private key (#4.3.0)\r\n"); 
+ +    return;}
+ +  if(!SSL_CTX_use_certificate_chain_file(ctx, "control/servercert.pem"))
+ +   {out("454 TLS not available: missing certificate (#4.3.0)\r\n"); 
+ +    return;}
+ +  SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb);
+ +  SSL_CTX_set_cipher_list(ctx,tlsserverciphers.s);
+ +  SSL_CTX_load_verify_locations(ctx, "control/clientca.pem",NULL);
+ +  SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb);
+ + 
+ +  out("220 ready for tls\r\n"); flush();
+ +
+ +  if(!(ssl=SSL_new(ctx))) die_read();
+ +  SSL_set_fd(ssl,0);
+ +  if(SSL_accept(ssl)<=0) die_read();
+ +  substdio_fdbuf(&ssout,SSL_write,ssl,ssoutbuf,sizeof(ssoutbuf));
+ +
+ +  remotehost = env_get("TCPREMOTEHOST");
+ +  if (!remotehost) remotehost = "unknown";
+ +  dohelo(remotehost);
+ +}
+ +#endif
+ +
+ +#ifdef USE_SMTPAUTH
+ +static unsigned char authenticated=0;
+ +static unsigned char *base64_alphabet =
+ +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ +static int unbase64(ch) int ch; {
+ +  int i;
+ +  if (ch == '=') return 0;
+ +  for (i = 0; i < 64; i++)
+ +    if (ch == base64_alphabet[i])
+ +      return i;
+ +  return 0;
+ +}
+ +static int base64_dec_buffer(str,dst,len) const char *str;void *dst;int len;
+ +{
+ +  int i, j, l;
+ +  unsigned char input[4], output[3], *result = (char *)dst;
+ +  if (str == 0)
+ +    return 0;
+ +  l = str_len(str);
+ +  if (dst == 0 || l > len)
+ +    return (l / 4) * 3;
+ +  memset(dst,0,len);
+ +  for (i=j=0; i<l; i +=4) {
+ +    input[0] = unbase64(str[i]);
+ +    input[1] = unbase64(str[i+1]);
+ +    input[2] = unbase64(str[i+2]);
+ +    input[3] = unbase64(str[i+3]);
+ +    output[0] = (input[0] << 2) | (input[1] >> 4);
+ +    output[1] = (input[1] << 4) | (input[2] >> 2);
+ +    output[2] = (input[2] << 6) | (input[3]);
+ +    result[j] = output[0];
+ +    if (str[i+1] == '=') return j+1;
+ +    result[j+1]=output[1];
+ +    if (str[i+2] == '=') return j+2;
+ +    result[j+2]=output[2];
+ +    j += 3;
+ +  }
+ +  return j;
+ +}
+ +static char **smtpauth_argv;
+ +static char *auth_argv[4];
+ +static stralloc smtpauth = {0};
+ +static char smtpauthlogin[65];
+ +static char smtpauthpass[65];
+ +static char smtpauthtimestamp[65];
+ +
+ +char unique[FMT_ULONG + FMT_ULONG + 3];
+ +
+ +void base64encode(stralloc *input, stralloc *output)
+ +{
+ +int	a=0,b=0,c=0;
+ +int	i, j;
+ +int	d, e, f, g;
+ +
+ +	if (input->len == 0)	return;
+ +
+ +	for (j=i=0; i< input->len ; i += 3)
+ +	{
+ +		a=input->s[i];
+ +		b= i+1 < input->len ? input->s[i+1]:0;
+ +		c= i+2 < input->len ? input->s[i+2]:0;
+ +
+ +		d=base64_alphabet[ a >> 2 ];
+ +		e=base64_alphabet[ ((a & 3 ) << 4) | (b >> 4)];
+ +		f=base64_alphabet[ ((b & 15) << 2) | (c >> 6)];
+ +		g=base64_alphabet[ c & 63 ];
+ +		if (i + 1 >= input->len) f='=';
+ +		if (i + 2 >= input->len) g='=';
+ +		stralloc_append(output,&d);
+ +		stralloc_append(output,&e);
+ +		stralloc_append(output,&f);
+ +		stralloc_append(output,&g);
+ +	}
+ +}
+ +
+ +static int smtpauth_getl(void) {
+ +  int i;
+ +  if (!stralloc_copys(&smtpauth, "")) return -1;
+ +  for (;;) {
+ +    if (!stralloc_readyplus(&smtpauth,1)) return -1;
+ +    i = substdio_get(&ssin, smtpauth.s + smtpauth.len, 1);
+ +    if (i != 1) return i;
+ +    if (smtpauth.s[smtpauth.len] == '\n') break;
+ +    ++smtpauth.len;
+ +  }
+ +  if (smtpauth.len > 0) if (smtpauth.s[smtpauth.len-1] == '\r') --smtpauth.len;
+ +  smtpauth.s[smtpauth.len] = 0;
+ +  return smtpauth.len;
+ +}
+ +
+ +static void smtpauth_authenticate(void)
+ +{
+ +  int st, pid, fds[2];
+ +  
+ +    if (pipe(fds)) {
+ +      out("535 pipe failure\r\n");
+ +      flush();
+ +      _exit(0);
+ +    }
+ +    /* spawn external program
+ +
+ +    external program should return '0' if it was successful,
+ +
+ +    submit: /bin/checkpassword /bin/true
+ +  
+ +    */
+ +    switch ((pid=fork())) {
+ +      case -1: die_fork();
+ +      case 0: close(fds[1]);
+ +        fd_copy(3,fds[0]);
+ +        flush();
+ +        execvp(auth_argv[1], auth_argv+1);
+ +        die_nomem();
+ +    };
+ +    close(fds[0]);
+ +    write(fds[1], smtpauthlogin, str_len(smtpauthlogin)+1);
+ +    write(fds[1], smtpauthpass, str_len(smtpauthpass)+1);
+ +    if (str_len(smtpauthtimestamp))
+ +    {
+ +          write(fds[1], smtpauthtimestamp, str_len(smtpauthtimestamp)+1);
+ +    }
+ +    close(fds[1]);
+ +    wait_pid(&st, pid);
+ +
+ +    if (wait_crashed(st))
+ +      die_crash();
+ +    if (wait_exitcode(st) == 0) {
+ +      out("235 go ahead\r\n");
+ +      flush();
+ +      relayclient="";
+ +      authenticated=1;
+ +      return;
+ +    }
+ +    sleep(2);
+ +    out("535 auth failure\r\n"); 
+ +    flush(); 
+ +    return;
+ +}
+ +
+ +void smtp_auth(arg) char *arg; {
+ +  int ret,i,toolong,start;
+ +  char *helper;
+ +  /* netscape 4.5 sends AUTH LOGIN <base64encodedusername>
+ +     microsoft outlook express sends AUTH LOGIN
+ +
+ +     idea is simple
+ +
+ +     use an external program to test authority
+ +     if success, set 'RELAYCLIENT'
+ +     otherwise, let them know nicely (hangup)
+ +
+ +     note, i really don't like djb's coding style even though i'm using it here.
+ +     i think using spaces for tabs is bad.
+ +                                                -mrs.brisby@nimh.org
+ +  */
+ +  /* Here i've added support for other auth types.
+ +  
+ +  						-brush@elysium.pl	*/
+ +  if (!authenticated)
+ +  {
+ +    if ((ret=strncasecmp(arg,"login",5))==0)
+ +    {
+ +      while (arg && *arg && *arg != ' ') arg++;
+ +
+ +      /* pass over the space */
+ +      while (arg && *arg && *arg == ' ') arg++;
+ +
+ +      if (arg && *arg) {
+ +        /* here's the base64 encoded login */
+ +        base64_dec_buffer(arg, smtpauthlogin, sizeof(smtpauthlogin));
+ +      } else {
+ +        out("334 VXNlcm5hbWU6\r\n"); /* b64 <- 'Username:' */
+ +        flush();
+ +        if (smtpauth_getl() > 0)
+ +          base64_dec_buffer(smtpauth.s, smtpauthlogin, sizeof(smtpauthlogin));
+ +        else
+ +          die_read();
+ +      }
+ +      out("334 UGFzc3dvcmQ6\r\n"); /* b64 <- 'Password:' */
+ +      flush();
+ +      if (smtpauth_getl() > 0)
+ +        base64_dec_buffer(smtpauth.s, smtpauthpass, sizeof(smtpauthpass));
+ +      else
+ +        die_read();
+ +      smtpauthtimestamp[0]=0;
+ +      auth_argv[1]=smtpauth_argv[1];	/* change checkpass prg */
+ +      auth_argv[2]=smtpauth_argv[2];	/* change checkpass prg */
+ +      auth_argv[3]=NULL;			/* change checkpass prg */
+ +      smtpauth_authenticate();  
+ +      return;
+ +    }
+ +    else if ((ret=strncasecmp(arg,"plain",5))==0)
+ +    {
+ +      static char smtpauthloginpass[200];
+ +
+ +      while (arg && *arg && *arg != ' ') arg++;
+ +
+ +      /* pass over the space */
+ +      while (arg && *arg && *arg == ' ') arg++;
+ + 
+ +      if (arg && *arg)
+ +      {
+ +        if(strlen(arg)*3/4 >= sizeof(smtpauthloginpass))
+ +        {
+ +          out("535 input too long\r\n");
+ +          flush();
+ +          return;
+ +        }
+ +        /* here's the base64 encoded login/password */
+ +        base64_dec_buffer(arg, smtpauthloginpass, sizeof(smtpauthloginpass)-1);
+ +      } else {
+ +        out("334 ok. go on.\r\n");
+ +        flush();
+ +        i=smtpauth_getl();
+ +        if(i <= 0)
+ +          die_read();
+ +        else if(i*3/4 >= sizeof(smtpauthloginpass))
+ +        {
+ +          out("535 input too long\r\n");
+ +          flush();
+ +          return;
+ +        } else base64_dec_buffer(smtpauth.s, smtpauthloginpass, sizeof(smtpauthloginpass)-1);
+ +      }
+ +      smtpauthloginpass[sizeof(smtpauthloginpass)-1]=0;
+ +      start=strlen(smtpauthloginpass)+1;
+ +      if((start >= sizeof(smtpauthloginpass)) || (strlen(smtpauthloginpass+start) >= 65))
+ +      {
+ +          out("535 malformed input\r\n");
+ +          flush();
+ +          return;
+ +      }
+ +      strcpy(smtpauthlogin,smtpauthloginpass+start);
+ +
+ +      start+=strlen(smtpauthlogin)+1;
+ +      if((start >= sizeof(smtpauthloginpass)) || (strlen(smtpauthloginpass+start) >= 65))
+ +      {
+ +          out("535 malformed input\r\n");
+ +          flush();
+ +          return;
+ +      }
+ +      strcpy(smtpauthpass,smtpauthloginpass+start);
+ +
+ +      smtpauthtimestamp[0]=0;
+ +      auth_argv[1]=smtpauth_argv[1];	/* change checkpass prg */
+ +      auth_argv[2]=smtpauth_argv[2];	/* change checkpass prg */
+ +      auth_argv[3]=NULL;		/* change checkpass prg */
+ +      smtpauth_authenticate();
+ +      return;
+ +    }
+ +    else if ((ret=strncasecmp(arg,"cram-md5",8))==0)  
+ +    {
+ +      int r;
+ +      static stralloc me = {0};
+ +      static stralloc greet = {0};
+ +      static stralloc greetenc = {0};
+ +      char *s;
+ +      r = control_readline(&me,"control/me");
+ +      if (r != 1) 
+ +      {
+ +        out("535 internal server error\r\n"); flush(); _exit(0);
+ +      }
+ +      for (r=0;r <= me.len;r++)
+ +      {
+ +        if (me.s[r]=='\n')
+ +        {
+ +          me.s[r]=0;
+ +          break;
+ +        }
+ +      }
+ +
+ +      s = unique;
+ +      s += fmt_uint(s,getpid());
+ +      *s++ = '.';
+ +      s += fmt_ulong(s,(unsigned long) now());
+ +      *s++ = '@';
+ +      *s++ = 0;
+ +      if (greet.len)
+ +      {
+ +	for (i=0;i<greet.len;i++)
+ +	{
+ +	  greet.s[i]=0;
+ +	}
+ +        greet.len=0;
+ +      }
+ +      stralloc_append(&greet,"<");
+ +      stralloc_cats(&greet,unique);
+ +      stralloc_cats(&greet,me.s);
+ +      stralloc_cats(&greet,">");
+ +      greet.s[greet.len]=0;	// obscure fix but it works
+ +      stralloc_readyplus(&greet,3);
+ +      if (greetenc.len)
+ +      {
+ +	for (i=0;i<greetenc.len;i++)
+ +	{
+ +	  greetenc.s[i]=0;
+ +	}
+ +        greetenc.len=0;
+ +      }
+ +      flush();
+ +      base64encode(&greet,&greetenc);
+ +      greetenc.s[greetenc.len]=0;	// obscure fix but it works
+ +      out("334 ");
+ +      out(greetenc.s);
+ +      out("\r\n");
+ +      flush();
+ +      if (smtpauth_getl() > 0)
+ +      {
+ +        s=calloc((size_t) strlen(smtpauth.s),(size_t)1);
+ +        base64_dec_buffer(smtpauth.s, s, strlen(smtpauth.s));
+ +      }
+ +      helper=strtok(s," ");
+ +      if(helper!=NULL)
+ +      {
+ +        strncpy (smtpauthlogin,helper,64);
+ +      }
+ +      else
+ +      {
+ +        out("535 malformed input\r\n"); 
+ +        return;
+ +      }
+ +      helper=strtok(NULL," ");
+ +      if(helper!=NULL)
+ +      {
+ +        strncpy (smtpauthtimestamp,helper,64);
+ +      }
+ +      else
+ +      {
+ +        out("535 malformed input\r\n"); 
+ +        return;
+ +      }
+ +      strncpy (smtpauthpass,greet.s,64);
+ +      auth_argv[1]=smtpauth_argv[3];	/* change checkpass prg */
+ +      auth_argv[2]=smtpauth_argv[4];	/* change checkpass prg */
+ +      auth_argv[3]=NULL;		/* change checkpass prg */
+ +      smtpauth_authenticate();
+ +      return;
+ +    }
+ +    else
+ +    {
+ +      out("504 auth type not supported\r\n"); 
+ +      flush();
+ +      return;
+ +    }
+ +  }
+ +  else
+ +  {
+ +      out("503 you are already authenticated\r\n"); 
+ +      flush(); 
+ +      return;
+ +  }
+ +}
+ +#endif
+ +
+  struct commands smtpcommands[] = {
+    { "rcpt", smtp_rcpt, 0 }
+  , { "mail", smtp_mail, 0 }
+  , { "data", smtp_data, flush }
+ +#ifdef USE_SMTPAUTH
+ +, { "auth", smtp_auth, flush }
+ +#endif
+  , { "quit", smtp_quit, flush }
+  , { "helo", smtp_helo, flush }
+  , { "ehlo", smtp_ehlo, flush }
+  , { "rset", smtp_rset, 0 }
+  , { "help", smtp_help, flush }
+ +#ifdef TLS
+ +, { "starttls", smtp_tls, flush }
+ +#endif
+  , { "noop", err_noop, flush }
+  , { "vrfy", err_vrfy, flush }
+  , { 0, err_unimpl, flush }
+  } ;
+  
+ -void main()
+ +void main(argc,argv) int argc; char **argv;
+  {
+ +#ifdef TLS
+ +  sig_alarmcatch(sigalrm);
+ +#endif
+ +#ifdef USE_SMTPAUTH
+ +  smtpauth_argv = argv;
+ +#endif
+    sig_pipeignore();
+    if (chdir(auto_qmail) == -1) die_control();
+    setup();
Index: qmail/conf-cc
diff -c qmail/conf-cc:1.1.1.1 qmail/conf-cc:1.3
*** qmail/conf-cc:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/conf-cc	Tue May 21 19:37:53 2002
***************
*** 1,3 ****
! cc -O2
  
  This will be used to compile .c files.
--- 1,3 ----
! cc -O2 -DTLS -I/usr/include
  
  This will be used to compile .c files.
Index: qmail/control.c
diff -c qmail/control.c:1.1.1.1 qmail/control.c:1.2
*** qmail/control.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/control.c	Thu Mar 10 23:47:33 2005
***************
*** 8,14 ****
  #include "alloc.h"
  #include "scan.h"
  
! static char inbuf[64];
  static stralloc line = {0};
  static stralloc me = {0};
  static int meok = 0;
--- 8,14 ----
  #include "alloc.h"
  #include "scan.h"
  
! static char inbuf[16384];
  static stralloc line = {0};
  static stralloc me = {0};
  static int meok = 0;
Index: qmail/dns.c
diff -c qmail/dns.c:1.1.1.1 qmail/dns.c:1.2
*** qmail/dns.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/dns.c	Thu Dec 20 19:29:00 2001
***************
*** 270,275 ****
--- 270,283 ----
  {
   int r;
   struct ip_mx ix;
+ #ifdef TLS
+  stralloc fqdn = {0};
+ 
+  if (!stralloc_copy(&fqdn,sa)) return DNS_MEM;
+  if (!stralloc_0(&fqdn)) return DNS_MEM;
+  ix.fqdn = fqdn.s;
+  alloc_free(fqdn);
+ #endif
  
   if (!stralloc_copy(&glue,sa)) return DNS_MEM;
   if (!stralloc_0(&glue)) return DNS_MEM;
***************
*** 330,335 ****
--- 338,346 ----
     ix.pref = 0;
     if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
      {
+ #ifdef TLS
+      ix.fqdn = NULL;
+ #endif
       if (!ipalloc_append(ia,&ix)) return DNS_MEM;
       return 0;
      }
Index: qmail/error.h
diff -c qmail/error.h:1.1.1.1 qmail/error.h:1.2
*** qmail/error.h:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/error.h	Thu Dec 25 14:49:59 2003
***************
*** 1,7 ****
  #ifndef ERROR_H
  #define ERROR_H
  
! extern int errno;
  
  extern int error_intr;
  extern int error_nomem;
--- 1,7 ----
  #ifndef ERROR_H
  #define ERROR_H
  
! #include <errno.h>
  
  extern int error_intr;
  extern int error_nomem;
Index: qmail/hier.c
diff -c qmail/hier.c:1.1.1.1 qmail/hier.c:1.2
*** qmail/hier.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/hier.c	Sat May  6 16:37:21 2006
***************
*** 143,148 ****
--- 143,149 ----
    c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755);
    c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755);
    c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","qmail-dk",auto_uido,auto_gidq,0755);
  
    c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
    c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644);
***************
*** 249,252 ****
--- 250,254 ----
    c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644);
    c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644);
    c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"man/man8","qmail-dk.8",auto_uido,auto_gidq,0644);
  }
Index: qmail/ipalloc.h
diff -c qmail/ipalloc.h:1.1.1.1 qmail/ipalloc.h:1.2
*** qmail/ipalloc.h:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/ipalloc.h	Thu Dec 20 19:29:00 2001
***************
*** 3,9 ****
--- 3,14 ----
  
  #include "ip.h"
  
+ #ifdef TLS
+ #include "stralloc.h"
+ struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ;
+ #else
  struct ip_mx { struct ip_address ip; int pref; } ;
+ #endif
  
  #include "gen_alloc.h"
  
Index: qmail/ipme.c
diff -c qmail/ipme.c:1.1.1.1 qmail/ipme.c:1.2
*** qmail/ipme.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/ipme.c	Fri Jul 21 12:23:06 2006
***************
*** 46,51 ****
--- 46,56 ----
    ipme.len = 0;
    ix.pref = 0;
   
+   /* 0.0.0.0 is a special address which always refers to 
+    * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a.
+   */
+   byte_copy(&ix.ip,4,"\0\0\0\0");
+   if (!ipalloc_append(&ipme,&ix)) { return 0; }
    if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1;
   
    len = 256;
Index: qmail/make-load.sh
diff -c qmail/make-load.sh:1.1.1.1 qmail/make-load.sh:1.2
*** qmail/make-load.sh:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/make-load.sh	Thu Dec 27 10:08:09 2001
***************
*** 1,2 ****
  echo 'main="$1"; shift'
! echo exec "$LD" '-o "$main" "$main".o ${1+"$@"}'
--- 1,2 ----
  echo 'main="$1"; shift'
! echo exec "$LD" '-o "$main" "$main".o ${1+"$@"} -L. -lsyncdir'
Index: qmail/qmail-control.9
diff -c qmail/qmail-control.9:1.1.1.1 qmail/qmail-control.9:1.4
*** qmail/qmail-control.9:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-control.9	Fri Jan 13 14:22:28 2006
***************
*** 43,48 ****
--- 43,49 ----
  .I badmailfrom	\fR(none)	\fRqmail-smtpd
  .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
  .I bouncehost	\fIme	\fRqmail-send
+ .I bouncemaxbytes	\fR50000	\fRqmail-send
  .I concurrencylocal	\fR10	\fRqmail-send
  .I concurrencyremote	\fR20	\fRqmail-send
  .I defaultdomain	\fIme	\fRqmail-inject
***************
*** 55,61 ****
--- 56,64 ----
  .I idhost	\fIme	\fRqmail-inject
  .I localiphost	\fIme	\fRqmail-smtpd
  .I locals	\fIme	\fRqmail-send
+ .I mfcheck	\fR0	\fRqmail-smtpd
  .I morercpthosts	\fR(none)	\fRqmail-smtpd
+ .I outgoingip	\fR0.0.0.0	\fRqmail-remote
  .I percenthack	\fR(none)	\fRqmail-send
  .I plusdomain	\fIme	\fRqmail-inject
  .I qmqpservers	\fR(none)	\fRqmail-qmqpc
Index: qmail/qmail-dk.8
diff -c /dev/null qmail/qmail-dk.8:1.1
*** /dev/null	Fri Aug  7 11:03:19 2009
--- qmail/qmail-dk.8	Sat May  6 16:37:21 2006
***************
*** 0 ****
--- 1,115 ----
+ .TH qmail-dk 8
+ .SH NAME
+ qmail-dk \- sign/verify and queue a mail message for delivery
+ .SH SYNOPSIS
+ .B qmail-dk
+ .SH DESCRIPTION
+ .B qmail-dk
+ has the same interface as
+ .B qmail-queue
+ except that it inserts an appropriate DomainKeys header before it
+ queues the message.  There are two separate ways to invoke
+ .BR qmail-dk .
+ For one way, you can patch qmail with the http://qmail.org/qmailqueue
+ patch and set QMAILQUEUE to point to qmail-dk in the environment when
+ you send or receive email.
+ For another way, you can rename qmail-queue to qmail-queue.orig, and set DKQUEUE=bin/qmail-queue.orig.
+ 
+ .B qmail-dk
+ supports DomainKey signing and verification.  It uses the libdomainkey
+ and OpenSSL libraries.  To sign a message, set the
+ .B DKSIGN
+ environment variable to the pathname to the private key that will be
+ used to sign the message.  If there is a % character in the environment
+ variable, it is removed and replaced by the domain name in the From: header.
+ If, after substituting the %, that file does not exist, the message will not be signed.
+ If there is no % and the file does not exist, the message will be rejected with error 32.
+ The selector will be taken from the
+ basename of the file.  The private key should be created by 
+ .BR dknewkey ,
+ which comes with libdomainkey.
+ 
+ To verify a message, set the
+ .B DKVERIFY
+ environment variable to a desired set of letters.  Precisely, if you
+ want a libdomainkey return status to generate an error, include that
+ letter, where A is the first return status (DK_STAT_OK), B is the
+ second (DK_STAT_BADSIG), etc.  The letter should be uppercase if you
+ want a permanent error to be returned (exit code 13), and lowercase if
+ you want a temporary error to be returned (exit code 82).
+ 
+ For example, if you want to permanently reject messages that have a
+ signature that has been revoked, include the letter 'K' in the
+ .B DKVERIFY
+ environment variable.  A conservative set of letters is
+ .BR DEGIJKfh .
+ Reject permanently BADSIG, NOKEY, BADKEY, SYNTAX, ARGS, REVOKED, and
+ INTERNAL errors, and temporarily CANTVRFY and NORESOURCE.  Add in
+ .B B
+ if you want to reject messages that have a signature that doesn't
+ verify (presumably because the message is a forgery or has been
+ damaged in transit.  Note that
+ .B qmail-dk
+ always inserts the 
+ .B DomainKey-Status
+ header, so that messages can be
+ rejected at delivery time, or in the mail reader.
+ 
+ Typically, you would sign messages generated on-host by setting
+ .B DKSIGN
+ in the environment before running an email program.  DKSIGN will be carried
+ through qmail's sendmail emulation through 
+ .B qmail-inject
+ to
+ .BR qmail-dk .
+ You would also set it for
+ .B qmail-smtpd
+ at the same time
+ .B RELAYCLIENT
+ is set, most often in the tcpserver cdb file.  If a host is authorized
+ to relay, you probably want to sign messages sent by that host.
+ .B DKVERIFY
+ should be set for all other hosts.
+ 
+ If neither
+ .B DKSIGN
+ nor
+ .B DKVERIFY
+ are set, then
+ .B DKSIGN
+ will be set to /etc/domainkeys/%/default.  If such a private key exists, it will be used to sign the domain.
+ 
+ .B qmail-dk
+ will ordinarily spawn qmail-queue, but if DKQUEUE is set in the environment,
+ the program that it points to will be executed instead.  If DKQUEUE is not set, and
+ .B qmail-dk
+ has been invoked as
+ .B qmail-queue
+ then
+ .B qmail-queue.orig
+ is spawned instead.
+ 
+ .SH "EXIT CODES"
+ .B qmail-dk
+ returns the same exit codes as qmail-queue with these additions:
+ .TP 5
+ .B 32
+ The private key file does not exist.
+ .TP 5
+ .B 57
+ Trouble waiting for qmail-queue to exit.
+ .TP 5
+ .B 58
+ Unable to vfork.
+ .TP 5
+ .B 59
+ Unable to create a pipe to qmail-queue.
+ .SH "SEE ALSO"
+ addresses(5),
+ envelopes(5),
+ qmail-header(5),
+ qmail-inject(8),
+ qmail-qmqpc(8),
+ qmail-queue(8),
+ qmail-send(8),
+ qmail-smtpd(8)
Index: qmail/qmail-dk.c
diff -c /dev/null qmail/qmail-dk.c:1.1
*** /dev/null	Fri Aug  7 11:03:19 2009
--- qmail/qmail-dk.c	Sat May  6 16:37:21 2006
***************
*** 0 ****
--- 1,297 ----
+ #include <sys/types.h>
+ #include "readwrite.h"
+ #include "sig.h"
+ #include "exit.h"
+ #include "open.h"
+ #include "seek.h"
+ #include "fmt.h"
+ #include "alloc.h"
+ #include "str.h"
+ #include "stralloc.h"
+ #include "substdio.h"
+ #include "datetime.h"
+ #include "now.h"
+ #include "fork.h"
+ #include "wait.h"
+ #include "extra.h"
+ #include "auto_qmail.h"
+ #include "auto_uids.h"
+ #include "date822fmt.h"
+ #include "fmtqfn.h"
+ #include "env.h"
+ #include "control.h"
+ #include "../libdomainkeys/domainkeys.h"
+ 
+ #define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
+ #define ADDR 1003
+ 
+ char inbuf[2048];
+ struct substdio ssin;
+ char outbuf[256];
+ struct substdio ssout;
+ 
+ datetime_sec starttime;
+ struct datetime dt;
+ unsigned long mypid;
+ unsigned long uid;
+ char *pidfn;
+ int messfd;
+ int readfd;
+ 
+ void die(e) int e; { _exit(e); }
+ void die_write() { die(53); }
+ void die_read() { die(54); }
+ void sigalrm() { /* thou shalt not clean up here */ die(52); }
+ void sigbug() { die(81); }
+ void maybe_die_dk(e) DK_STAT e; {
+   switch(e) {
+   case DK_STAT_BADKEY: _exit(55);
+   case DK_STAT_CANTVRFY: _exit(74);
+   case DK_STAT_NORESOURCE: _exit(51);
+   case DK_STAT_ARGS: _exit(12);
+   case DK_STAT_SYNTAX: _exit(31);
+   case DK_STAT_INTERNAL: _exit(81);
+   }
+ }
+ 
+ unsigned int pidfmt(s,seq)
+ char *s;
+ unsigned long seq;
+ {
+  unsigned int i;
+  unsigned int len;
+ 
+  len = 0;
+  i = fmt_str(s,"/tmp/qmail-dk."); len += i; if (s) s += i;
+  i = fmt_ulong(s,mypid); len += i; if (s) s += i;
+  i = fmt_str(s,"."); len += i; if (s) s += i;
+  i = fmt_ulong(s,starttime); len += i; if (s) s += i;
+  i = fmt_str(s,"."); len += i; if (s) s += i;
+  i = fmt_ulong(s,seq); len += i; if (s) s += i;
+  ++len; if (s) *s++ = 0;
+ 
+  return len;
+ }
+ 
+ void pidopen()
+ {
+  unsigned int len;
+  unsigned long seq;
+ 
+  seq = 1;
+  len = pidfmt((char *) 0,seq);
+  pidfn = alloc(len);
+  if (!pidfn) die(51);
+ 
+  for (seq = 1;seq < 10;++seq)
+   {
+    if (pidfmt((char *) 0,seq) > len) die(81); /* paranoia */
+    pidfmt(pidfn,seq);
+    messfd = open_excl(pidfn);
+    if (messfd != -1) return;
+   }
+ 
+  die(63);
+ }
+ 
+ char tmp[FMT_ULONG];
+ 
+ char *dksign = 0;
+ stralloc dksignature = {0};
+ stralloc dkoutput = {0};
+ char *dkverify = 0;
+ char *dkqueue = 0;
+ DK_LIB *dklib;
+ DK *dk;
+ DK_STAT st;
+ 
+ static void write_signature(DK *dk, char *keyfn)
+ {
+  char advice[2048];
+  char *selector;
+  char *from;
+  static stralloc keyfnfrom = {0};
+  int i;
+ 
+  from = dk_from(dk);
+  i = str_chr(keyfn, '%');
+  if (keyfn[i]) {
+    if (!stralloc_copyb(&keyfnfrom,keyfn,i)) die(51);
+    if (!stralloc_cats(&keyfnfrom,from)) die(51);
+    if (!stralloc_cats(&keyfnfrom,keyfn + i + 1)) die(51);
+  } else {
+    if (!stralloc_copys(&keyfnfrom,keyfn)) die(51);
+  }
+  if (!stralloc_0(&keyfnfrom)) die(51);
+ 
+  switch(control_readfile(&dksignature,keyfnfrom.s,0)) {
+  case 0:
+    if (keyfn[i]) return;
+    die(32);
+  case 1: break;
+  default: die(31);
+  }
+  for(i=0; i < dksignature.len; i++)
+    if (dksignature.s[i] == '\0') dksignature.s[i] = '\n';
+  if (!stralloc_0(&dksignature)) die(51);
+ 
+  st = dk_getsig(dk, dksignature.s, advice, sizeof(advice));
+  maybe_die_dk(st);
+ 
+  if (!stralloc_cats(&dkoutput,
+ 	   "DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws;\n"
+ 	   "  s=")) die(51);
+  selector = keyfn;
+  while (*keyfn) {
+    if (*keyfn == '/') selector = keyfn+1;
+     keyfn++;
+  }
+  if (!stralloc_cats(&dkoutput,selector)) die(51);
+  if (!stralloc_cats(&dkoutput,"; d=")) die(51);
+  if (from) {
+    if (!stralloc_cats(&dkoutput,from)) die(51);
+  } else if (!stralloc_cats(&dkoutput,"unknown")) die(51);
+  if (!stralloc_cats(&dkoutput,";\n  b=")) die(51);
+  if (!stralloc_cats(&dkoutput,advice)) die(51);
+  if (!stralloc_cats(&dkoutput,"  ;\n")) die(51);
+ }
+ 
+ static char *binqqargs[2] = { "bin/qmail-queue", 0 } ;
+ 
+ void main(int argc, char *argv[])
+ {
+  unsigned int len;
+  char ch;
+  int pim[2];
+  int wstat;
+  unsigned long pid;
+ 
+  sig_blocknone();
+  umask(033);
+ 
+  dksign = env_get("DKSIGN");
+  dkverify = env_get("DKVERIFY");
+  if (!dksign && !dkverify)
+    dksign = "/etc/domainkeys/%/default";
+ 
+  dkqueue = env_get("DKQUEUE");
+  if (dkqueue && *dkqueue) binqqargs[0] = dkqueue;
+  else if (str_equal(argv[0]+str_rchr(argv[0], '/'), "/qmail-queue"))
+    binqqargs[0] = "bin/qmail-queue.orig";
+ 
+  if (dksign || dkverify) {
+    dklib = dk_init(0);
+    if (!dklib) die(51);
+  }
+  if (dksign) {
+     dk = dk_sign(dklib, &st, DK_CANON_NOFWS);
+     if (!dk) die(31);
+  } else if (dkverify) {
+     dk = dk_verify(dklib, &st);
+     if (!dk) die(31);
+  }
+ 
+  mypid = getpid();
+  uid = getuid();
+  starttime = now();
+  datetime_tai(&dt,starttime);
+ 
+  sig_pipeignore();
+  sig_miscignore();
+  sig_alarmcatch(sigalrm);
+  sig_bugcatch(sigbug);
+ 
+  alarm(DEATH);
+ 
+  pidopen();
+  readfd = open_read(pidfn);
+  if (unlink(pidfn) == -1) die(63);
+ 
+  substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));
+  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
+ 
+  for (;;) {
+    register int n;
+    register char *x;
+    int i;
+ 
+    n = substdio_feed(&ssin);
+    if (n < 0) die_read();
+    if (!n) break;
+    x = substdio_PEEK(&ssin);
+    if (dksign || dkverify)
+      for(i=0; i < n; i++) {
+        if (x[i] == '\n') st = dk_message(dk, "\r\n", 2);
+        else st = dk_message(dk, x+i, 1);
+        maybe_die_dk(st);
+       }
+    if (substdio_put(&ssout,x,n) == -1) die_write();
+    substdio_SEEK(&ssin,n);
+  }
+ 
+  if (substdio_flush(&ssout) == -1) die_write();
+ 
+  if (dksign || dkverify) {
+    st = dk_eom(dk, (void *)0);
+    maybe_die_dk(st);
+    if (dksign) {
+      write_signature(dk, dksign);
+    } else if (dkverify) {
+      char *status;
+      if (!stralloc_copys(&dkoutput,"DomainKey-Status: ")) die(51);
+      switch(st) {
+      case DK_STAT_OK:         status = "good        "; break;
+      case DK_STAT_BADSIG:     status = "bad         "; break;
+      case DK_STAT_NOSIG:      status = "no signature"; break;
+      case DK_STAT_NOKEY:
+      case DK_STAT_CANTVRFY:   status = "no key      "; break;
+      case DK_STAT_BADKEY:     status = "bad key     "; break;
+      case DK_STAT_INTERNAL:
+      case DK_STAT_ARGS:
+      case DK_STAT_SYNTAX:     status = "bad format  "; break;
+      case DK_STAT_NORESOURCE: status = "no resources"; break;
+      case DK_STAT_REVOKED:    status = "revoked     "; break;
+      }
+      if (!stralloc_cats(&dkoutput,status)) die(51);
+      if (!stralloc_cats(&dkoutput,"\n")) die(51);
+      if (dkverify[str_chr(dkverify, 'A'+st)]) die(13);
+      if (dkverify[str_chr(dkverify, 'a'+st)]) die(82);
+    }
+  }
+ 
+  if (pipe(pim) == -1) die(59);
+  
+  switch(pid = vfork()) {
+  case -1:
+    close(pim[0]); close(pim[1]);
+    die(58);
+  case 0:
+    close(pim[1]);
+    if (fd_move(0,pim[0]) == -1) die(120);
+    if (chdir(auto_qmail) == -1) die(61);
+    execv(*binqqargs,binqqargs);
+    die(120);
+  }
+ 
+  close(pim[0]);
+ 
+  substdio_fdbuf(&ssin,read,readfd,inbuf,sizeof(inbuf));
+  substdio_fdbuf(&ssout,write,pim[1],outbuf,sizeof(outbuf));
+ 
+  if (substdio_bput(&ssout,dkoutput.s,dkoutput.len) == -1) die_write();
+  switch(substdio_copy(&ssout,&ssin))
+   {
+    case -2: die_read();
+    case -3: die_write();
+   }
+ 
+  if (substdio_flush(&ssout) == -1) die_write();
+  close(pim[1]);
+ 
+  if (wait_pid(&wstat,pid) != pid)
+    die(57);
+  if (wait_crashed(wstat))
+    die(57);
+  die(wait_exitcode(wstat));
+ 
+ }
Index: qmail/qmail-local.c
diff -c qmail/qmail-local.c:1.1.1.1 qmail/qmail-local.c:1.2
*** qmail/qmail-local.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-local.c	Fri Jul 21 12:26:52 2006
***************
*** 645,651 ****
      {
       cmds.s[j] = 0;
       k = j;
!      while ((k > i) && (cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t'))
         cmds.s[--k] = 0;
       switch(cmds.s[i])
        {
--- 645,651 ----
      {
       cmds.s[j] = 0;
       k = j;
!      while ((k > i) && ((cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t')))
         cmds.s[--k] = 0;
       switch(cmds.s[i])
        {
Index: qmail/qmail-lspawn.c
diff -c qmail/qmail-lspawn.c:1.1.1.1 qmail/qmail-lspawn.c:1.2
*** qmail/qmail-lspawn.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-lspawn.c	Fri Oct 29 22:33:32 2004
***************
*** 13,18 ****
--- 13,19 ----
  #include "auto_qmail.h"
  #include "auto_uids.h"
  #include "qlx.h"
+ #include "env.h"
  
  char *aliasempty;
  
***************
*** 191,197 ****
     x = nughde.s;
     xlen = nughde.len;
  
!    args[0] = "bin/qmail-local";
     args[1] = "--";
     args[2] = x;
     n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n;
--- 192,201 ----
     x = nughde.s;
     xlen = nughde.len;
  
! 
!    args[0] = env_get("QMAILLOCAL");
!    if (!args[0])
!     args[0] = "bin/qmail-local";
     args[1] = "--";
     args[2] = x;
     n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n;
Index: qmail/qmail-qmqpd.c
diff -c qmail/qmail-qmqpd.c:1.1.1.1 qmail/qmail-qmqpd.c:1.2
*** qmail/qmail-qmqpd.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-qmqpd.c	Wed Dec 26 20:55:04 2001
***************
*** 78,84 ****
    if (!local) local = env_get("TCPLOCALIP");
    if (!local) local = "unknown";
   
!   received(&qq,"QMQP",local,remoteip,remotehost,remoteinfo,(char *) 0);
  }
  
  char buf[1000];
--- 78,84 ----
    if (!local) local = env_get("TCPLOCALIP");
    if (!local) local = "unknown";
   
!   received(&qq,"QMQP",local,remoteip,remotehost,remoteinfo,(char *) 0, (char *) 0);
  }
  
  char buf[1000];
Index: qmail/qmail-qmtpd.c
diff -c qmail/qmail-qmtpd.c:1.1.1.1 qmail/qmail-qmtpd.c:1.3
*** qmail/qmail-qmtpd.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-qmtpd.c	Tue Jul 13 22:35:15 2004
***************
*** 14,19 ****
--- 14,26 ----
  
  void badproto() { _exit(100); }
  void resources() { _exit(111); }
+ void die_nomem() { resources(); }
+ void die_control() { resources(); }
+ void die_cdb() { resources(); }
+ void die_sys() { resources(); }
+ 
+ extern void realrcptto_init();
+ extern int realrcptto();
  
  int safewrite(fd,buf,len) int fd; char *buf; int len;
  {
***************
*** 98,103 ****
--- 105,112 ----
    if (rcpthosts_init() == -1) resources();
    relayclient = env_get("RELAYCLIENT");
    relayclientlen = relayclient ? str_len(relayclient) : 0;
+ 
+   realrcptto_init();
   
    if (control_readint(&databytes,"control/databytes") == -1) resources();
    x = env_get("DATABYTES");
***************
*** 216,221 ****
--- 225,234 ----
              case -1: resources();
              case 0: failure.s[failure.len - 1] = 'D';
            }
+ 
+         if (!failure.s[failure.len - 1])
+           if (!realrcptto(buf))
+             failure.s[failure.len - 1] = 'D';
   
          if (!failure.s[failure.len - 1]) {
            qmail_to(&qq,buf);
Index: qmail/qmail-remote.8
diff -c qmail/qmail-remote.8:1.1.1.1 qmail/qmail-remote.8:1.2
*** qmail/qmail-remote.8:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-remote.8	Fri Jan 13 14:22:28 2006
***************
*** 124,129 ****
--- 124,136 ----
  .B qmail-remote
  refuses to run.
  .TP 5
+ .I outgoingip
+ IP address to be used on outgoing connections.
+ Default: system-defined.
+ The value 
+ .IR 0.0.0.0 
+ is equivalent to the system default.
+ .TP 5
  .I smtproutes
  Artificial SMTP routes.
  Each route has the form
Index: qmail/qmail-remote.c
diff -c qmail/qmail-remote.c:1.1.1.1 qmail/qmail-remote.c:1.4
*** qmail/qmail-remote.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-remote.c	Tue Dec 26 02:54:15 2006
***************
*** 26,33 ****
--- 26,44 ----
  #include "tcpto.h"
  #include "readwrite.h"
  #include "timeoutconn.h"
+ #ifndef TLS
  #include "timeoutread.h"
  #include "timeoutwrite.h"
+ #endif
+ 
+ #ifdef TLS
+ #include <sys/stat.h>
+ #include <openssl/ssl.h>
+ #include <openssl/err.h>
+ SSL *ssl = NULL;
+ 
+ stralloc tlsclientciphers = {0};
+ #endif
  
  #define HUGESMTPTEXT 5000
  
***************
*** 39,44 ****
--- 50,56 ----
  static stralloc sauninit = {0};
  
  stralloc helohost = {0};
+ stralloc outgoingip = {0};
  stralloc routes = {0};
  struct constmap maproutes;
  stralloc host = {0};
***************
*** 47,52 ****
--- 59,65 ----
  saa reciplist = {0};
  
  struct ip_address partner;
+ struct ip_address outip;
  
  void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
  void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
***************
*** 56,61 ****
--- 69,75 ----
  ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?';
  if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } }
  
+ void temp_noip() { out("Zinvalid ipaddr in control/outgoingip (#4.3.0)\n"); zerodie(); }
  void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); }
  void temp_oserr() { out("Z\
  System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); }
***************
*** 107,123 ****
--- 121,214 ----
  int smtpfd;
  int timeout = 1200;
  
+ #ifdef TLS
+ int flagtimedout = 0;
+ void sigalrm()
+ {
+  flagtimedout = 1;
+ }
+ 
+ int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
+ {
+  int r; int saveerrno;
+  if (flagtimedout) { errno = error_timeout; return -1; }
+  alarm(timeout);
+  if (ssl) {
+    while(((r = SSL_read(ssl,buf,n)) <= 0)
+          && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_READ));
+    if (SSL_get_error(ssl, r) != SSL_ERROR_NONE)
+     {char buf[1024];
+  
+      out("ZTLS connection to "); outhost(); out(" died: ");
+      SSL_load_error_strings();
+      out(ERR_error_string(ERR_get_error(), buf)); out("\n");
+      SSL_shutdown(ssl);
+      zerodie();
+     }
+  }else r = read(fd,buf,n);
+  saveerrno = errno;
+  alarm(0);
+  if (flagtimedout) { errno = error_timeout; return -1; }
+  errno = saveerrno;
+  return r;
+ }
+ 
+ int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
+ {
+  int r; int saveerrno;
+  if (flagtimedout) { errno = error_timeout; return -1; }
+  alarm(timeout);
+  if (ssl) {
+    while(((r = SSL_write(ssl,buf,n)) <= 0)
+          && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_WRITE));
+    if (SSL_get_error(ssl, r) != SSL_ERROR_NONE)
+     {char buf[1024];
+ 
+      out("ZTLS connection to "); outhost(); out(" died: ");
+      SSL_load_error_strings();
+      out(ERR_error_string(ERR_get_error(), buf)); out("\n");
+      SSL_shutdown(ssl);
+      zerodie();
+     }
+  }else r = write(fd,buf,n);
+  saveerrno = errno;
+  alarm(0);
+  if (flagtimedout) { errno = error_timeout; return -1; }
+  errno = saveerrno;
+  return r;
+ }
+ 
+ static int client_cert_cb(SSL *s,X509 **x509, EVP_PKEY **pkey)
+ {
+  out("ZTLS found no client cert in control/clientcert.pem\n");
+  zerodie(NULL,NULL);
+ }
+ 
+ static int verify_cb(int ok, X509_STORE_CTX * ctx)
+ {
+   return (1);
+ }
+ #endif 
+ 
  int saferead(fd,buf,len) int fd; char *buf; int len;
  {
    int r;
+ #ifdef TLS
+   r = ssl_timeoutread(timeout,smtpfd,buf,len);
+ #else
    r = timeoutread(timeout,smtpfd,buf,len);
+ #endif
    if (r <= 0) dropped();
    return r;
  }
  int safewrite(fd,buf,len) int fd; char *buf; int len;
  {
    int r;
+ #ifdef TLS
+   r = ssl_timeoutwrite(timeout,smtpfd,buf,len);
+ #else
    r = timeoutwrite(timeout,smtpfd,buf,len);
+ #endif
    if (r <= 0) dropped();
    return r;
  }
***************
*** 186,191 ****
--- 277,310 ----
    out(append);
    out(".\n");
    outsmtptext();
+ 
+ /* TAG */
+ #if defined(TLS) && defined(DEBUG)
+ #define ONELINE_NAME(X) X509_NAME_oneline(X,NULL,0)
+ 
+  if(ssl){
+  X509 *peer;
+ 
+   out("STARTTLS proto="); out(SSL_get_version(ssl));
+   out("; cipher="); out(SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
+ 
+   /* we want certificate details */
+   peer=SSL_get_peer_certificate(ssl);
+   if (peer != NULL) {
+    char *str;
+ 
+    str=ONELINE_NAME(X509_get_subject_name(peer));
+    out("; subject="); out(str);
+    Free(str);
+    str=ONELINE_NAME(X509_get_issuer_name(peer));
+    out("; issuer="); out(str);
+    Free(str);
+    X509_free(peer);
+   }
+   out(";\n");
+  }
+ #endif
+ 
    zerodie();
  }
  
***************
*** 216,235 ****
  
  stralloc recip = {0};
  
  void smtp()
  {
    unsigned long code;
    int flagbother;
    int i;
!  
    if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
   
    substdio_puts(&smtpto,"HELO ");
    substdio_put(&smtpto,helohost.s,helohost.len);
    substdio_puts(&smtpto,"\r\n");
    substdio_flush(&smtpto);
    if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
!  
    substdio_puts(&smtpto,"MAIL FROM:<");
    substdio_put(&smtpto,sender.s,sender.len);
    substdio_puts(&smtpto,">\r\n");
--- 335,492 ----
  
  stralloc recip = {0};
  
+ #ifdef TLS
+ void smtp(fqdn)
+ char *fqdn;
+ #else
  void smtp()
+ #endif
  {
    unsigned long code;
    int flagbother;
    int i;
! #ifdef TLS
!   int needtlsauth = 0;
!   SSL_CTX *ctx;
!   int saveerrno, r;
! 
!   stralloc servercert = {0};
!   struct stat st;
!   if(fqdn){
!    if(!stralloc_copys(&servercert, "control/tlshosts/")) temp_nomem();
!    if(!stralloc_catb(&servercert, fqdn, str_len(fqdn))) temp_nomem();
!    if(!stralloc_catb(&servercert, ".pem", 4)) temp_nomem();
!    if(!stralloc_0(&servercert)) temp_nomem();
!    if (stat(servercert.s,&st) == 0)  needtlsauth = 1;
!   }
! #endif
! 
    if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
   
+ #ifdef TLS
+   substdio_puts(&smtpto,"EHLO ");
+ #else
    substdio_puts(&smtpto,"HELO ");
+ #endif
    substdio_put(&smtpto,helohost.s,helohost.len);
    substdio_puts(&smtpto,"\r\n");
    substdio_flush(&smtpto);
+ #ifdef TLS
+   if (smtpcode() != 250){
+    substdio_puts(&smtpto,"HELO ");
+    substdio_put(&smtpto,helohost.s,helohost.len);
+    substdio_puts(&smtpto,"\r\n");
+    substdio_flush(&smtpto);
+    if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
+   }
+ #else
    if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
! #endif
! 
! #ifdef TLS
!   i = 0; 
!   while((i += str_chr(smtptext.s+i,'\n') + 1) && (i+12 < smtptext.len) &&
!         str_diffn(smtptext.s+i+4,"STARTTLS\n",9));
!   if (i+12 < smtptext.len)
!    {
!     substdio_puts(&smtpto,"STARTTLS\r\n");
!     substdio_flush(&smtpto);
!     if (smtpcode() == 220)
!      {
!       SSL_library_init();
!       if(!(ctx=SSL_CTX_new(SSLv23_client_method())))
!        {char buf[1024];
! 
!         out("ZTLS not available: error initializing ctx: ");
!         SSL_load_error_strings();
!         out(ERR_error_string(ERR_get_error(), buf));
!         out("\n");
!         SSL_shutdown(ssl);
!         zerodie();
!       }
!       if((stat("control/clientcert.pem", &st) == 0) &&
!          ((SSL_CTX_use_RSAPrivateKey_file(ctx, "control/clientcert.pem", SSL_FILETYPE_PEM) <= 0) ||
!          (SSL_CTX_use_certificate_chain_file(ctx, "control/clientcert.pem") <= 0) ||
!          (SSL_CTX_check_private_key(ctx) <= 0)))
!         /* if there is a cert and it is bad, I fail
!            if there is no cert, I leave it to the other side to complain */
!         SSL_CTX_set_client_cert_cb(ctx, client_cert_cb);
!  
!       /*SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);*/
!       SSL_CTX_set_cipher_list(ctx,tlsclientciphers.s);
!  
!       if (needtlsauth){
!         if (!SSL_CTX_load_verify_locations(ctx, servercert.s, NULL))
!           {out("ZTLS unable to load "); out(servercert.s); out("\n");
!            zerodie();}
!         SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
!       }
!      
!       if(!(ssl=SSL_new(ctx)))
!         {char buf[1024];
! 
!          out("ZTLS not available: error initializing ssl: "); 
!          SSL_load_error_strings();
!          out(ERR_error_string(ERR_get_error(), buf));
!          out("\n");
!          SSL_shutdown(ssl);
!          zerodie();
!         }
!       SSL_set_fd(ssl,smtpfd);
! 
!       alarm(timeout);
!       r = SSL_connect(ssl); saveerrno = errno;
!       alarm(0); 
!       if (flagtimedout) 
!        {out("ZTLS not available: connect timed out\n");
!         zerodie();}
!       errno = saveerrno;
!       if (r<=0)
!         {char buf[1024];
! 
!          out("ZTLS not available: connect failed: ");
!          SSL_load_error_strings();
!          out(ERR_error_string(ERR_get_error(), buf));
!          out("\n");
!          SSL_shutdown(ssl);
!          zerodie();
!         }
!       if (needtlsauth)
!        /* should also check alternate names */
!        {char commonName[256];
! 
!         if ((r=SSL_get_verify_result(ssl)) != X509_V_OK)
!          {out("ZTLS unable to verify server with ");
!           out(servercert.s); out(": ");
!           out(X509_verify_cert_error_string(r)); out("\n");
!           zerodie();
!          }
!         X509_NAME_get_text_by_NID(X509_get_subject_name(
!                                    SSL_get_peer_certificate(ssl)),
!                                    NID_commonName, commonName, 256);
!         if (strcasecmp(fqdn,commonName)){
!          out("ZTLS connection to "); out(fqdn);
!          out(" wanted, certificate for "); out(commonName);
!          out(" received\n");
!          zerodie();}
!         }
! 
!       substdio_puts(&smtpto,"EHLO ");
!       substdio_put(&smtpto,helohost.s,helohost.len);
!       substdio_puts(&smtpto,"\r\n");
!       substdio_flush(&smtpto);
! 
!       if (smtpcode() != 250)
!        {
!         quit("ZTLS connected to "," but my name was rejected");
!        }
!      } 
!    }
!   if ((!ssl) && needtlsauth)
!    {out("ZNo TLS achieved while "); out(servercert.s); out(" exists.\n");
!     quit();}
! #endif
! 
    substdio_puts(&smtpto,"MAIL FROM:<");
    substdio_put(&smtpto,sender.s,sender.len);
    substdio_puts(&smtpto,">\r\n");
***************
*** 310,315 ****
--- 567,573 ----
  
  void getcontrols()
  {
+   int r;
    if (control_init() == -1) temp_control();
    if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control();
    if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1)
***************
*** 324,329 ****
--- 582,598 ----
      case 1:
        if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
    }
+ #ifdef TLS
+   if (control_rldef(&tlsclientciphers,"control/tlsclientciphers",0,"DEFAULT") != 1)
+     temp_control();
+   if(!stralloc_0(&tlsclientciphers)) temp_nomem();
+ #endif
+   r = control_readline(&outgoingip,"control/outgoingip");
+   if (-1 == r) { if (errno == error_nomem) temp_nomem(); temp_control(); }
+   if (0 == r && !stralloc_copys(&outgoingip, "0.0.0.0")) temp_nomem();
+   if (str_equal(outgoingip.s, "0.0.0.0"))
+     { outip.d[0]=outip.d[1]=outip.d[2]=outip.d[3]=(unsigned long) 0; }
+   else if (!ip_scan(outgoingip.s, &outip)) temp_noip();
  }
  
  void main(argc,argv)
***************
*** 338,344 ****
    int flagallaliases;
    int flagalias;
    char *relayhost;
!  
    sig_pipeignore();
    if (argc < 4) perm_usage();
    if (chdir(auto_qmail) == -1) temp_chdir();
--- 607,616 ----
    int flagallaliases;
    int flagalias;
    char *relayhost;
! 
! #ifdef TLS
!   sig_alarmcatch(sigalrm);
! #endif
    sig_pipeignore();
    if (argc < 4) perm_usage();
    if (chdir(auto_qmail) == -1) temp_chdir();
***************
*** 414,423 ****
      smtpfd = socket(AF_INET,SOCK_STREAM,0);
      if (smtpfd == -1) temp_oserr();
   
!     if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
        tcpto_err(&ip.ix[i].ip,0);
        partner = ip.ix[i].ip;
        smtp(); /* does not return */
      }
      tcpto_err(&ip.ix[i].ip,errno == error_timeout);
      close(smtpfd);
--- 686,699 ----
      smtpfd = socket(AF_INET,SOCK_STREAM,0);
      if (smtpfd == -1) temp_oserr();
   
!     if (timeoutconn(smtpfd,&ip.ix[i].ip,&outip,(unsigned int) port,timeoutconnect) == 0) {
        tcpto_err(&ip.ix[i].ip,0);
        partner = ip.ix[i].ip;
+ #ifdef TLS
+       smtp(ip.ix[i].fqdn); /* does not return */
+ #else
        smtp(); /* does not return */
+ #endif
      }
      tcpto_err(&ip.ix[i].ip,errno == error_timeout);
      close(smtpfd);
Index: qmail/qmail-rspawn.c
diff -c qmail/qmail-rspawn.c:1.1.1.1 qmail/qmail-rspawn.c:1.2
*** qmail/qmail-rspawn.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-rspawn.c	Fri Jan 13 14:19:20 2006
***************
*** 5,10 ****
--- 5,11 ----
  #include "fork.h"
  #include "error.h"
  #include "tcpto.h"
+ #include "env.h"
  
  void initialize(argc,argv)
  int argc;
***************
*** 84,90 ****
   int f;
   char *(args[5]);
  
!  args[0] = "qmail-remote";
   args[1] = r + at + 1;
   args[2] = s;
   args[3] = r;
--- 85,94 ----
   int f;
   char *(args[5]);
  
!  args[0] = env_get("QMAILREMOTE");
!  if (!args[0])
!    args[0] = "qmail-remote";
! 
   args[1] = r + at + 1;
   args[2] = s;
   args[3] = r;
Index: qmail/qmail-send.9
diff -c qmail/qmail-send.9:1.1.1.1 qmail/qmail-send.9:1.2
*** qmail/qmail-send.9:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-send.9	Sun Jan 23 16:57:31 2005
***************
*** 115,120 ****
--- 115,124 ----
  (If that bounces,
  .B qmail-send
  gives up.)
+ As a special case, if the first line of
+ .IR doublebounceto
+ is blank (contains a single linefeed), qmail-send will not queue
+ the double-bounce at all.
  .TP 5
  .I envnoathost
  Presumed domain name for addresses without @ signs.
Index: qmail/qmail-send.c
diff -c qmail/qmail-send.c:1.1.1.1 qmail/qmail-send.c:1.3
*** qmail/qmail-send.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-send.c	Sun Jan 23 16:57:31 2005
***************
*** 44,49 ****
--- 44,51 ----
  
  int lifetime = 604800;
  
+ int bouncemaxbytes = 50000;
+ 
  stralloc percenthack = {0};
  struct constmap mappercenthack;
  stralloc locals = {0};
***************
*** 683,688 ****
--- 685,692 ----
    }
   if (str_equal(sender.s,"#@[]"))
     log3("triple bounce: discarding ",fn2.s,"\n");
+  else if (!*sender.s && *doublebounceto.s == '@')
+    log3("double bounce: discarding ",fn2.s,"\n");
   else
    {
     if (qmail_open(&qqt) == -1)
***************
*** 740,748 ****
       qmail_fail(&qqt);
     else
      {
       substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf));
!      while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0)
         qmail_put(&qqt,buf,r);
       close(fd);
       if (r == -1)
         qmail_fail(&qqt);
--- 744,760 ----
       qmail_fail(&qqt);
     else
      {
+      int bytestogo = bouncemaxbytes;
+      int bytestoget = (bytestogo < sizeof buf) ? bytestogo : sizeof buf;
       substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf));
!      while (bytestoget > 0 && (r = substdio_get(&ssread,buf,bytestoget)) > 0) {
         qmail_put(&qqt,buf,r);
+        bytestogo -= bytestoget;
+        bytestoget = (bytestogo < sizeof buf) ? bytestogo : sizeof buf;
+      }
+      if (r > 0) {
+        qmail_puts(&qqt,"\n\n--- End of message stripped.\n");
+      }
       close(fd);
       if (r == -1)
         qmail_fail(&qqt);
***************
*** 1442,1447 ****
--- 1454,1460 ----
  /* this file is too long ---------------------------------------------- MAIN */
  
  int getcontrols() { if (control_init() == -1) return 0;
+  if (control_readint(&bouncemaxbytes,"control/bouncemaxbytes") == -1) return 0;   
   if (control_readint(&lifetime,"control/queuelifetime") == -1) return 0;
   if (control_readint(&concurrency[0],"control/concurrencylocal") == -1) return 0;
   if (control_readint(&concurrency[1],"control/concurrencyremote") == -1) return 0;
Index: qmail/qmail-showctl.c
diff -c qmail/qmail-showctl.c:1.1.1.1 qmail/qmail-showctl.c:1.2
*** qmail/qmail-showctl.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-showctl.c	Fri Jan 13 14:22:28 2006
***************
*** 230,235 ****
--- 230,236 ----
    do_str("localiphost",1,"localiphost","Local IP address becomes ");
    do_lst("locals","Messages for me are delivered locally.","Messages for "," are delivered locally.");
    do_str("me",0,"undefined! Uh-oh","My name is ");
+   do_str("outgoingip",0,"0.0.0.0","Outgoing IP address is ");
    do_lst("percenthack","The percent hack is not allowed.","The percent hack is allowed for user%host@",".");
    do_str("plusdomain",1,"plusdomain","Plus domain name is ");
    do_lst("qmqpservers","No QMQP servers.","QMQP server: ",".");
Index: qmail/qmail-smtpd.8
diff -c qmail/qmail-smtpd.8:1.1.1.1 qmail/qmail-smtpd.8:1.2
*** qmail/qmail-smtpd.8:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-smtpd.8	Fri May 31 10:07:36 2002
***************
*** 97,102 ****
--- 97,109 ----
  This is done before
  .IR rcpthosts .
  .TP 5
+ .I mfcheck
+ If set,
+ .B qmail-smtpd
+ tries to resolve the domain of the envelope from address, and
+ refuses mail if the domain does not resolve.  It can be
+ handy when you want to filter out spamhosts.
+ .TP 5
  .I morercpthosts
  Extra allowed RCPT domains.
  If
Index: qmail/qmail-smtpd.c
diff -c qmail/qmail-smtpd.c:1.1.1.1 qmail/qmail-smtpd.c:1.27
*** qmail/qmail-smtpd.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail-smtpd.c	Fri Oct 20 01:26:59 2006
***************
*** 1,4 ****
--- 1,7 ----
  #include "sig.h"
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <string.h>
  #include "readwrite.h"
  #include "stralloc.h"
  #include "substdio.h"
***************
*** 16,37 ****
  #include "scan.h"
  #include "byte.h"
  #include "case.h"
  #include "env.h"
  #include "now.h"
  #include "exit.h"
  #include "rcpthosts.h"
  #include "timeoutread.h"
  #include "timeoutwrite.h"
  #include "commands.h"
  
  #define MAXHOPS 100
  unsigned int databytes = 0;
! int timeout = 1200;
  
  int safewrite(fd,buf,len) int fd; char *buf; int len;
  {
    int r;
    r = timeoutwrite(timeout,fd,buf,len);
    if (r <= 0) _exit(1);
    return r;
  }
--- 19,110 ----
  #include "scan.h"
  #include "byte.h"
  #include "case.h"
+ #include "wait.h"
  #include "env.h"
  #include "now.h"
  #include "exit.h"
  #include "rcpthosts.h"
+ #ifndef TLS
  #include "timeoutread.h"
  #include "timeoutwrite.h"
+ #endif
  #include "commands.h"
+ #include "dns.h"
+ #ifdef TLS
+ #include <openssl/ssl.h>
+ SSL *ssl = NULL;
+ 
+ stralloc clientcert = {0};
+ stralloc tlsserverciphers = {0};
+ #endif
  
  #define MAXHOPS 100
+ #define USE_SMTPAUTH
+ /*
+ #define USE_OLD_GREETING
+ #define USE_NEW_GREETING
+ */
+ 
  unsigned int databytes = 0;
! unsigned int mfchk = 0;
! int timeout = 30;
! 
! #ifdef USE_SMTPAUTH
! static unsigned char authenticated=0;
! static char smtpauthlogin[65];
! static char *auth_required;
! static int smtpauth_enabled = 0;
! static char **smtpauth_argv;
! #endif
! 
! #ifdef TLS
! int flagtimedout = 0;
! void sigalrm()
! {
!  flagtimedout = 1;
! }
! int ssl_timeoutread(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
! {
!  int r; int saveerrno;
!  if (flagtimedout) { errno = error_timeout; return -1; }
!  alarm(timeout);
!  if (ssl) {
!    while(((r = SSL_read(ssl,buf,n)) <= 0)
!          && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_READ)
! 	 && !flagtimedout);
!  }else r = read(fd,buf,n);
!  saveerrno = errno;
!  alarm(0);
!  if (flagtimedout) { errno = error_timeout; return -1; }
!  errno = saveerrno;
!  return r;
! }
! int ssl_timeoutwrite(timeout,fd,buf,n) int timeout; int fd; char *buf; int n;
! {
!  int r; int saveerrno;
!  if (flagtimedout) { errno = error_timeout; return -1; }
!  alarm(timeout);
!  if (ssl) { 
!    while(((r = SSL_write(ssl,buf,n)) <= 0)
!          && (SSL_get_error(ssl, r) == SSL_ERROR_WANT_WRITE)
! 	 && !flagtimedout);
!  }else r = write(fd,buf,n);
!  saveerrno = errno;
!  alarm(0);
!  if (flagtimedout) { errno = error_timeout; return -1; }
!  errno = saveerrno;
!  return r;
! }
! #endif
  
  int safewrite(fd,buf,len) int fd; char *buf; int len;
  {
    int r;
+ #ifdef TLS
+   r = ssl_timeoutwrite(timeout,fd,buf,len);
+ #else
    r = timeoutwrite(timeout,fd,buf,len);
+ #endif
    if (r <= 0) _exit(1);
    return r;
  }
***************
*** 39,64 ****
--- 112,166 ----
  char ssoutbuf[512];
  substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
  
+ int errwrite(fd,buf,len) int fd; char *buf; int len;
+ {
+   int r;
+   r = timeoutwrite(timeout,fd,buf,len);
+   if (r <= 0) _exit(1);
+   return r;
+ }
+ 
+ char sserrbuf[512];
+ substdio sserr = SUBSTDIO_FDBUF(errwrite,2,sserrbuf,sizeof sserrbuf);
+ 
+ static stralloc err;
+ char strnum[FMT_ULONG];
+ 
  void flush() { substdio_flush(&ssout); }
  void out(s) char *s; { substdio_puts(&ssout,s); }
  
  void die_read() { _exit(1); }
  void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
  void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
+ void die_crash() { out("421 child crashed (#4.3.0)\r\n"); flush(); _exit(1); }
+ void die_fork() { out("421 unable to start checkpassword.\r\n"); flush(); _exit(1); }
  void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
  void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
+ void die_cdb() { out("421 unable to read cdb user database (#4.3.0)\r\n"); flush(); _exit(1); }
+ void die_sys() { out("421 unable to read system user database (#4.3.0)\r\n"); flush(); _exit(1); }
  void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
  
+ void err_nodomain() { out("553 sorry, your envelope sender must include a domain (#5.7.1)\r\n"); }
  void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
+ void err_hmf() { out("553 sorry, your envelope sender domain must exist (#5.7.1)\r\n"); }
+ void err_smf() { out("451 DNS temporary failure (#4.3.0)\r\n"); }
+ void err_brt() { out("553 sorry, this recipient is in my badrcptto list (#5.7.1)\r\n"); }
  void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
+ #ifdef TLS
+ void err_nogwcert() { out("553 no valid cert for gatewaying (#5.7.1)\r\n"); }
+ #endif
  void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
  void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
+ void err_relay() { out("553 we don't relay (#5.7.1)\r\n"); }
  void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
  void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
  void err_noop() { out("250 ok\r\n"); }
  void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
  void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
+ void err_auth_required() { out("553 sorry, you must authenticate first (#5.7.1)\r\n"); }
  
+ extern void realrcptto_init();
+ extern int realrcptto();
  
  stralloc greeting = {0};
  
***************
*** 81,93 ****
  char *remoteinfo;
  char *local;
  char *relayclient;
  
  stralloc helohost = {0};
  char *fakehelo; /* pointer into helohost, or 0 */
  
  void dohelo(arg) char *arg; {
!   if (!stralloc_copys(&helohost,arg)) die_nomem(); 
!   if (!stralloc_0(&helohost)) die_nomem(); 
    fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
  }
  
--- 183,219 ----
  char *remoteinfo;
  char *local;
  char *relayclient;
+ #ifdef TLS
+ char *tlsciphers;
+ #endif
+ 
+ static unsigned smtp_max_failures = 5;
+ static unsigned nr_failures = 0;
+ 
+ 
+ void stderr_prefix(const char *type)
+ {
+   if (!stralloc_copys(&err,"qmail-smtpd: pid ")) die_nomem();
+   if (!stralloc_catb(&err,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+   if (!stralloc_cats(&err," ")) die_nomem();
+   if (!stralloc_cats(&err,type)) die_nomem();
+   if (!stralloc_cats(&err," ")) die_nomem();
+ }
+ 
+ 
+ void stderr_suffix(void)
+ {
+   if (!stralloc_cats(&err,"\n")) die_nomem();
+   substdio_put(&sserr,err.s,err.len);
+   substdio_flush(&sserr);
+ }
  
  stralloc helohost = {0};
  char *fakehelo; /* pointer into helohost, or 0 */
  
  void dohelo(arg) char *arg; {
!   if (!stralloc_copys(&helohost,arg)) die_nomem();
!   if (!stralloc_0(&helohost)) die_nomem();
    fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
  }
  
***************
*** 96,107 ****
  int bmfok = 0;
  stralloc bmf = {0};
  struct constmap mapbmf;
  
  void setup()
  {
    char *x;
    unsigned long u;
!  
    if (control_init() == -1) die_control();
    if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)
      die_control();
--- 222,295 ----
  int bmfok = 0;
  stralloc bmf = {0};
  struct constmap mapbmf;
+ int brtok = 0;
+ stralloc brt = {0};
+ struct constmap mapbrt;
+ 
+ #ifdef TLS
+ static RSA *tmp_rsa_cb(ssl,export,keylength) SSL *ssl; int export; int keylength; 
+ {
+   RSA* rsa;
+   BIO* in;
+ 
+   if (!export || keylength == 512)
+    if (in=BIO_new(BIO_s_file_internal()))
+     if (BIO_read_filename(in,"control/rsa512.pem") > 0)
+      if (rsa=PEM_read_bio_RSAPrivateKey(in,NULL,NULL,NULL))
+       return rsa;
+   return (RSA_generate_key(export?keylength:512,RSA_F4,NULL,NULL));
+ }
+ 
+ static int verify_cb(int ok, X509_STORE_CTX * ctx)
+ {
+   return (1);
+ }
+ 
+ static void init_tls(int starttls)
+ {
+   SSL_CTX *ctx;
+ 
+   SSL_library_init();
+   if(!(ctx=SSL_CTX_new(SSLv23_server_method())))
+    {out("454 TLS not available: unable to initialize ctx (#4.3.0)\r\n"); 
+     return;}
+   if(!SSL_CTX_use_RSAPrivateKey_file(ctx, "control/servercert.pem", SSL_FILETYPE_PEM))
+    {out("454 TLS not available: missing RSA private key (#4.3.0)\r\n"); 
+     return;}
+   if(!SSL_CTX_use_certificate_chain_file(ctx, "control/servercert.pem"))
+    {out("454 TLS not available: missing certificate (#4.3.0)\r\n"); 
+     return;}
+   SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb);
+   SSL_CTX_set_cipher_list(ctx,tlsserverciphers.s);
+   SSL_CTX_load_verify_locations(ctx, "control/clientca.pem",NULL);
+   SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb);
+  
+   if (starttls) {
+     out("220 ready for tls\r\n"); flush();
+   }
+ 
+   if(!(ssl=SSL_new(ctx))) die_read();
+   SSL_set_fd(ssl,0);
+   alarm(timeout);
+   if(SSL_accept(ssl)<=0 || flagtimedout) die_read();
+   alarm(0);
+   // continue using safewrite -dean
+   //substdio_fdbuf(&ssout,SSL_write,ssl,ssoutbuf,sizeof(ssoutbuf));
+ 
+   stderr_prefix("tls");
+   if (!stralloc_cats(&err, SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)))) die_nomem();
+   stderr_suffix();
+ }
+ #endif
  
  void setup()
  {
    char *x;
    unsigned long u;
! #ifdef TLS
!   char *tlsciphers;
! #endif
! 
    if (control_init() == -1) die_control();
    if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)
      die_control();
***************
*** 112,121 ****
--- 300,320 ----
  
    if (rcpthosts_init() == -1) die_control();
  
+   if (control_readint(&mfchk,"control/mfcheck") == -1) die_control();
+   x = env_get("MFCHECK");
+   if (x) { scan_ulong(x,&u); mfchk = u; }
+ 
    bmfok = control_readfile(&bmf,"control/badmailfrom",0);
    if (bmfok == -1) die_control();
    if (bmfok)
      if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+ 
+   realrcptto_init();
+ 
+   brtok = control_readfile(&brt,"control/badrcptto",0);
+   if (brtok == -1) die_control();
+   if (brtok)
+     if (!constmap_init(&mapbrt,brt.s,brt.len,0)) die_nomem();
   
    if (control_readint(&databytes,"control/databytes") == -1) die_control();
    x = env_get("DATABYTES");
***************
*** 124,139 ****
   
    remoteip = env_get("TCPREMOTEIP");
    if (!remoteip) remoteip = "unknown";
!   local = env_get("TCPLOCALHOST");
!   if (!local) local = env_get("TCPLOCALIP");
    if (!local) local = "unknown";
    remotehost = env_get("TCPREMOTEHOST");
    if (!remotehost) remotehost = "unknown";
    remoteinfo = env_get("TCPREMOTEINFO");
    relayclient = env_get("RELAYCLIENT");
    dohelo(remotehost);
  }
  
  
  stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
  
--- 323,360 ----
   
    remoteip = env_get("TCPREMOTEIP");
    if (!remoteip) remoteip = "unknown";
!   local = env_get("TCPLOCALIP");
    if (!local) local = "unknown";
    remotehost = env_get("TCPREMOTEHOST");
    if (!remotehost) remotehost = "unknown";
    remoteinfo = env_get("TCPREMOTEINFO");
    relayclient = env_get("RELAYCLIENT");
+ #ifdef TLS
+   if (tlsciphers = env_get("TLSCIPHERS")){
+     if (!stralloc_copys(&tlsserverciphers,tlsciphers)) die_nomem();
+   } 
+   else {
+     if (control_rldef(&tlsserverciphers,"control/tlsserverciphers",0,"DEFAULT") != 1) 
+       die_control();
+   }
+   if (!stralloc_0(&tlsserverciphers)) die_nomem();
+   if (env_get("SMTP_TLS_FORCED")) {
+     init_tls(0);
+   }
+ #endif
+ #ifdef USE_SMTPAUTH
+   auth_required = env_get("SMTP_AUTH_REQUIRED");
+ #endif
+ 
+   if (control_readint(&smtp_max_failures,"control/smtp_max_failures") == -1) {
+     smtp_max_failures = 5;
+   }
+ 
    dohelo(remotehost);
  }
  
+ stralloc mailfrom = {0};
+ stralloc rcptto = {0};
  
  stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
  
***************
*** 146,152 ****
    struct ip_address ip;
    int flagesc;
    int flagquoted;
!  
    terminator = '>';
    i = str_chr(arg,'<');
    if (arg[i])
--- 367,373 ----
    struct ip_address ip;
    int flagesc;
    int flagquoted;
! 
    terminator = '>';
    i = str_chr(arg,'<');
    if (arg[i])
***************
*** 197,210 ****
    return 1;
  }
  
  int bmfcheck()
  {
    int j;
    if (!bmfok) return 0;
!   if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
    j = byte_rchr(addr.s,addr.len,'@');
    if (j < addr.len)
!     if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
    return 0;
  }
  
--- 418,502 ----
    return 1;
  }
  
+ 
  int bmfcheck()
  {
    int j;
    if (!bmfok) return 0;
!   if (constmap(&mapbmf,addr.s,addr.len - 1)) goto match;
!   j = byte_rchr(addr.s,addr.len,'@');
!   if (j < addr.len)
!     if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) goto match;
!   return 0;
! 
! match:
!   stderr_prefix("badmailfrom");
!   if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
!   stderr_suffix();
!   return 1;
! }
! 
! int mfnodomaincheck()
! {
!   int j;
! 
!   if (addr.len == 1) {		/* MAIL FROM:<> is allowed ... 1 is terminating \0 */
!     return 0;
!   }
!   j = byte_rchr(addr.s,addr.len,'@');
!   if (j < addr.len) {
!     return 0;
!   }
!   stderr_prefix("mfnodomain");
!   if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
!   stderr_suffix();
!   return 1;
! }
! 
! int brtcheck()
! {
!   int j;
!   if (!brtok) return 0;
!   if (constmap(&mapbrt,addr.s,addr.len - 1)) goto match;
    j = byte_rchr(addr.s,addr.len,'@');
    if (j < addr.len)
!     if (constmap(&mapbrt,addr.s + j,addr.len - j - 1)) goto match;
!   return 0;
! 
! match:
!   stderr_prefix("badrcptto");
!   if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
!   if (!stralloc_cats(&err," (from ")) die_nomem();
!   if (!stralloc_catb(&err,mailfrom.s,mailfrom.len - 1)) die_nomem();
!   if (!stralloc_cats(&err,")")) die_nomem();
!   stderr_suffix();
!   return 1;
! }
! 
! int mfcheck()
! {
!   stralloc sa = {0};
!   ipalloc ia = {0};
!   unsigned int random;
!   int j;
! 
!   if (!mfchk) return 0;
!   random = now() + (getpid() << 16);
!   j = byte_rchr(addr.s,addr.len,'@') + 1;
!   if (j < addr.len) {
!     stralloc_copys(&sa, addr.s + j);
!     dns_init(0);
!     j = dns_mxip(&ia,&sa,random);
!     if (j < 0) {
!       if (j != DNS_MEM) {
! 	stderr_prefix("mfcheck");
! 	if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
! 	if (!stralloc_cats(&err,(j==DNS_HARD)?" hard":" soft")) die_nomem();
! 	stderr_suffix();
!       }
!       return j;
!     }
!   }
    return 0;
  }
  
***************
*** 216,255 ****
    return r;
  }
  
  
  int seenmail = 0;
  int flagbarf; /* defined if seenmail */
- stralloc mailfrom = {0};
- stralloc rcptto = {0};
  
  void smtp_helo(arg) char *arg;
  {
    smtp_greet("250 "); out("\r\n");
    seenmail = 0; dohelo(arg);
  }
  void smtp_ehlo(arg) char *arg;
  {
!   smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
    seenmail = 0; dohelo(arg);
  }
  void smtp_rset()
  {
    seenmail = 0;
    out("250 flushed\r\n");
  }
  void smtp_mail(arg) char *arg;
  {
    if (!addrparse(arg)) { err_syntax(); return; }
    flagbarf = bmfcheck();
    seenmail = 1;
    if (!stralloc_copys(&rcptto,"")) die_nomem();
    if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
    if (!stralloc_0(&mailfrom)) die_nomem();
    out("250 ok\r\n");
  }
  void smtp_rcpt(arg) char *arg; {
    if (!seenmail) { err_wantmail(); return; }
    if (!addrparse(arg)) { err_syntax(); return; }
    if (flagbarf) { err_bmf(); return; }
    if (relayclient) {
      --addr.len;
--- 508,630 ----
    return r;
  }
  
+ int addrrelay()
+ {
+   int j;
+   j = addr.len;
+   while(--j >= 0)
+     if (addr.s[j] == '@') break;
+   if (j < 0) j = addr.len;
+   while(--j >= 0) {
+     if (addr.s[j] == '@') goto match;
+     if (addr.s[j] == '%') goto match;
+     if (addr.s[j] == '!') goto match;
+   }
+   return 0;
  
+ match:
+   stderr_prefix("addrrelay");
+   if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
+   if (!stralloc_cats(&err," (from ")) die_nomem();
+   if (!stralloc_catb(&err,mailfrom.s,mailfrom.len - 1)) die_nomem();
+   if (!stralloc_cats(&err,")")) die_nomem();
+   stderr_suffix();
+   return 1;
+ }
+ 
+ 
+ int esmtp = 0;
  int seenmail = 0;
  int flagbarf; /* defined if seenmail */
  
  void smtp_helo(arg) char *arg;
  {
    smtp_greet("250 "); out("\r\n");
    seenmail = 0; dohelo(arg);
+   stderr_prefix("helo");
+   if (!stralloc_cats(&err,arg)) die_nomem();
+   stderr_suffix();
  }
  void smtp_ehlo(arg) char *arg;
  {
!   smtp_greet("250-"); 
!   out("\r\n250-PIPELINING");
! #ifdef TLS
!   if (!ssl) out("\r\n250-STARTTLS");
! #endif
! #ifdef USE_SMTPAUTH
!   if (smtpauth_enabled) out("\r\n250-AUTH LOGIN PLAIN");
! #endif
!   out("\r\n250 8BITMIME\r\n");
!   esmtp = 1;
    seenmail = 0; dohelo(arg);
+   stderr_prefix("ehlo");
+   if (!stralloc_cats(&err,arg)) die_nomem();
+   stderr_suffix();
  }
  void smtp_rset()
  {
    seenmail = 0;
+   stderr_prefix("rset");
+   stderr_suffix();
    out("250 flushed\r\n");
  }
+ void test_too_many_failures(void)
+ {
+   if (nr_failures >= smtp_max_failures) {
+     stderr_prefix("toomanyfails");
+     stderr_suffix();
+     out("550 sorry, you've tried too many addresses\r\n");
+     flush();
+     _exit(0);
+     return;
+   }
+ }
+ 
  void smtp_mail(arg) char *arg;
  {
+   test_too_many_failures();
+   // assume we will fail
+   ++nr_failures;
+   if (auth_required && !authenticated) { err_auth_required(); return; }
    if (!addrparse(arg)) { err_syntax(); return; }
+   if (mfnodomaincheck()) { err_nodomain(); return; }
    flagbarf = bmfcheck();
+   switch(mfcheck()) {
+     case DNS_HARD: err_hmf(); return;
+     case DNS_SOFT: err_smf(); return;
+     case DNS_MEM: die_nomem();
+   }
+   /* remember <> is allowed, everything else let's see if it's
+    * a local domain and look for real user if so.
+    */
+   if (addr.len > 1 && !realrcptto(addr.s)) {
+     stderr_prefix("realmf");
+     if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
+     stderr_suffix();
+     out("550 sorry, that domain is local, but that mailbox does not exist. (#5.7.1)\r\n");
+     return;
+   }
    seenmail = 1;
+   if (!flagbarf) {
+     stderr_prefix("okmf");
+     if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
+     stderr_suffix();
+   }
    if (!stralloc_copys(&rcptto,"")) die_nomem();
    if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
    if (!stralloc_0(&mailfrom)) die_nomem();
+   // we didn't fail, so decrement from our assumption
+   --nr_failures;
    out("250 ok\r\n");
  }
  void smtp_rcpt(arg) char *arg; {
+   test_too_many_failures();
+   // assume we will fail
+   ++nr_failures;
    if (!seenmail) { err_wantmail(); return; }
    if (!addrparse(arg)) { err_syntax(); return; }
+   if (addrrelay()) { err_relay(); return; }
    if (flagbarf) { err_bmf(); return; }
    if (relayclient) {
      --addr.len;
***************
*** 257,266 ****
--- 632,703 ----
      if (!stralloc_0(&addr)) die_nomem();
    }
    else
+ #ifndef TLS
      if (!addrallowed()) { err_nogateway(); return; }
+ #else
+     if (!addrallowed())
+      {
+       if (ssl)
+       { STACK_OF(X509_NAME) *sk;
+         X509 *peercert;
+         stralloc tlsclients = {0};
+         struct constmap maptlsclients;
+         int r;
+ 
+         SSL_set_verify(ssl,
+                        SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
+                        verify_cb);
+         if ((sk = SSL_load_client_CA_file("control/clientca.pem")) == NULL)
+          { err_nogateway(); return; }
+         SSL_set_client_CA_list(ssl, sk);
+         if((control_readfile(&tlsclients,"control/tlsclients",0) != 1) ||
+            !constmap_init(&maptlsclients,tlsclients.s,tlsclients.len,0))
+           { err_nogateway(); return; }
+  
+         SSL_renegotiate(ssl);
+         SSL_do_handshake(ssl);
+         ssl->state = SSL_ST_ACCEPT;
+         SSL_do_handshake(ssl);
+         if ((r = SSL_get_verify_result(ssl)) != X509_V_OK)
+          {out("553 no valid cert for gatewaying: ");
+           out(X509_verify_cert_error_string(r));
+           out(" (#5.7.1)\r\n");
+           return;
+          }
+   
+         if (peercert = SSL_get_peer_certificate(ssl))
+          {char emailAddress[256];
+ 
+           X509_NAME_get_text_by_NID(X509_get_subject_name(
+                                      SSL_get_peer_certificate(ssl)),
+                                      NID_pkcs9_emailAddress, emailAddress, 256);
+           if (!stralloc_copys(&clientcert, emailAddress)) die_nomem();
+           if (!constmap(&maptlsclients,clientcert.s,clientcert.len))
+             { err_nogwcert(); return; }
+           relayclient = "";
+          }
+           else { err_nogwcert(); return; }
+        }
+       else { err_nogateway(); return; }
+      }
+ #endif
+   if (!realrcptto(addr.s)) {
+     stderr_prefix("realrcptto");
+     if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
+     stderr_suffix();
+     out("550 sorry, no mailbox here by that name. (#5.1.1)\r\n");
+     return;
+   }
+   if (!relayclient && brtcheck()) { err_brt(); return; }
+ 
+   stderr_prefix("okrcptto");
+   if (!stralloc_catb(&err,addr.s,addr.len - 1)) die_nomem();
+   stderr_suffix();
    if (!stralloc_cats(&rcptto,"T")) die_nomem();
    if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
    if (!stralloc_0(&rcptto)) die_nomem();
+   // we didn't fail, so decrement from our assumption
+   --nr_failures;
    out("250 ok\r\n");
  }
  
***************
*** 269,275 ****
--- 706,716 ----
  {
    int r;
    flush();
+ #ifdef TLS
+   r = ssl_timeoutread(timeout,fd,buf,len);
+ #else
    r = timeoutread(timeout,fd,buf,len);
+ #endif
    if (r == -1) if (errno == error_timeout) die_alarm();
    if (r <= 0) die_read();
    return r;
***************
*** 300,306 ****
    int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
    int flagmaybey; /* 1 if this line might match \r\n, if fih */
    int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
!  
    state = 1;
    *hops = 0;
    flaginheader = 1;
--- 741,747 ----
    int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
    int flagmaybey; /* 1 if this line might match \r\n, if fih */
    int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
! 
    state = 1;
    *hops = 0;
    flaginheader = 1;
***************
*** 322,338 ****
      }
      switch(state) {
        case 0:
!         if (ch == '\n') straynewline();
          if (ch == '\r') { state = 4; continue; }
          break;
        case 1: /* \r\n */
-         if (ch == '\n') straynewline();
          if (ch == '.') { state = 2; continue; }
          if (ch == '\r') { state = 4; continue; }
!         state = 0;
          break;
        case 2: /* \r\n + . */
!         if (ch == '\n') straynewline();
          if (ch == '\r') { state = 3; continue; }
          state = 0;
          break;
--- 763,778 ----
      }
      switch(state) {
        case 0:
!         if (ch == '\n') { state = 1; break; }
          if (ch == '\r') { state = 4; continue; }
          break;
        case 1: /* \r\n */
          if (ch == '.') { state = 2; continue; }
          if (ch == '\r') { state = 4; continue; }
!         if (ch != '\n') state = 0;
          break;
        case 2: /* \r\n + . */
!         if (ch == '\n') return;	/* this is what sendmail-8.8.4 does -djg */
          if (ch == '\r') { state = 3; continue; }
          state = 0;
          break;
***************
*** 355,360 ****
--- 795,807 ----
  void acceptmessage(qp) unsigned long qp;
  {
    datetime_sec when;
+ 
+   /* log the qp so we can later go back and figure out what host:ip delivered this to us */
+   /* if we die while doing this we'll end up with a duplicate message, oh well. */
+   stderr_prefix("qp");
+   if (!stralloc_catb(&err,strnum,fmt_ulong(strnum,qp))) die_nomem();
+   stderr_suffix();
+ 
    when = now();
    out("250 ok ");
    accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;
***************
*** 369,374 ****
--- 816,823 ----
    int hops;
    unsigned long qp;
    char *qqx;
+   char *errcode;
+   stralloc protocolinfo = {0};
   
    if (!seenmail) { err_wantmail(); return; }
    if (!rcptto.len) { err_wantrcpt(); return; }
***************
*** 377,384 ****
    if (qmail_open(&qqt) == -1) { err_qqt(); return; }
    qp = qmail_qp(&qqt);
    out("354 go ahead\r\n");
!  
!   received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
    blast(&hops);
    hops = (hops >= MAXHOPS);
    if (hops) qmail_fail(&qqt);
--- 826,851 ----
    if (qmail_open(&qqt) == -1) { err_qqt(); return; }
    qp = qmail_qp(&qqt);
    out("354 go ahead\r\n");
!   if (!esmtp) {
!    if (!stralloc_copys(&protocolinfo, "SMTP")) die_nomem();
!   }
!   else {
!    if (!stralloc_copys(&protocolinfo, "ESMTP")) die_nomem();
!    if (ssl && !stralloc_catb(&protocolinfo, "S", 1)) die_nomem();
!    if (authenticated && !stralloc_catb(&protocolinfo, "A", 1)) die_nomem();
!    if (ssl) {
!     if (!stralloc_catb(&protocolinfo, " (", 2)) die_nomem();
!     if (!stralloc_cats(&protocolinfo, SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)))) die_nomem();
!     if (clientcert.len) {
!       if (!stralloc_catb(&protocolinfo, " cert ", 6)) die_nomem();
!       if (!stralloc_catb(&protocolinfo, clientcert.s, clientcert.len)) die_nomem();
!     }
!     if (!stralloc_catb(&protocolinfo, ")", 1)) die_nomem();
!    }
!   }
!   if (!stralloc_0(&protocolinfo)) die_nomem();
!   received(&qqt,protocolinfo.s,local,remoteip,remotehost,remoteinfo,case_diffs(remotehost,helohost.s) ? helohost.s : 0,
!   	authenticated ? smtpauthlogin : 0);
    blast(&hops);
    hops = (hops >= MAXHOPS);
    if (hops) qmail_fail(&qqt);
***************
*** 387,415 ****
   
    qqx = qmail_close(&qqt);
    if (!*qqx) { acceptmessage(qp); return; }
!   if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
!   if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
!   if (*qqx == 'D') out("554 "); else out("451 ");
!   out(qqx + 1);
    out("\r\n");
  }
  
  struct commands smtpcommands[] = {
    { "rcpt", smtp_rcpt, 0 }
  , { "mail", smtp_mail, 0 }
  , { "data", smtp_data, flush }
  , { "quit", smtp_quit, flush }
  , { "helo", smtp_helo, flush }
  , { "ehlo", smtp_ehlo, flush }
  , { "rset", smtp_rset, 0 }
  , { "help", smtp_help, flush }
  , { "noop", err_noop, flush }
  , { "vrfy", err_vrfy, flush }
  , { 0, err_unimpl, flush }
  } ;
  
! void main()
  {
    sig_pipeignore();
    if (chdir(auto_qmail) == -1) die_control();
    setup();
--- 854,1194 ----
   
    qqx = qmail_close(&qqt);
    if (!*qqx) { acceptmessage(qp); return; }
!   if (hops) {
!    errcode = "554 too many hops, this message is looping (#5.4.6)";
!    qqx = 0;
!   }
!   else if (databytes && !bytestooverflow) {
!    errcode = "552 sorry, that message size exceeds my databytes limit (#5.3.4)";
!    qqx = 0;
!   }
!   else {
!    errcode = (*qqx == 'D') ? "554 " : "451 ";
!   }
!   out(errcode);
!   if (qqx) out(qqx + 1);
    out("\r\n");
+   stderr_prefix("fail");
+   if (!stralloc_cats(&err,errcode)) die_nomem();
+   if (qqx) if (!stralloc_cats(&err,qqx + 1)) die_nomem();
+   stderr_suffix();
+ }
+ 
+ #ifdef TLS
+ 
+ void smtp_tls(arg) char *arg; 
+ {
+   SSL_CTX *ctx;
+ 
+   if (*arg)
+    {out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n");
+     return;}
+ 
+   init_tls(1);
+ 
+   remotehost = env_get("TCPREMOTEHOST");
+   if (!remotehost) remotehost = "unknown";
+   dohelo(remotehost);
+ }
+ #endif
+ 
+ #ifdef USE_SMTPAUTH
+ static unsigned char *base64_alphabet =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ static int unbase64(ch) int ch; {
+   int i;
+   if (ch == '=') return 0;
+   for (i = 0; i < 64; i++)
+     if (ch == base64_alphabet[i])
+       return i;
+   return 0;
+ }
+ static int base64_dec_buffer(str,dst,len) const char *str;void *dst;int len;
+ {
+   int i, j, l;
+   unsigned char input[4], output[3], *result = (char *)dst;
+   if (str == 0)
+     return 0;
+   l = str_len(str);
+   if (dst == 0 || l > len)
+     return (l / 4) * 3;
+   memset(dst,0,len);
+   for (i=j=0; i<l; i +=4) {
+     input[0] = unbase64(str[i]);
+     input[1] = unbase64(str[i+1]);
+     input[2] = unbase64(str[i+2]);
+     input[3] = unbase64(str[i+3]);
+     output[0] = (input[0] << 2) | (input[1] >> 4);
+     output[1] = (input[1] << 4) | (input[2] >> 2);
+     output[2] = (input[2] << 6) | (input[3]);
+     result[j] = output[0];
+     if (str[i+1] == '=') return j+1;
+     result[j+1]=output[1];
+     if (str[i+2] == '=') return j+2;
+     result[j+2]=output[2];
+     j += 3;
+   }
+   return j;
+ }
+ static stralloc smtpauth = {0};
+ static char smtpauthpass[65];
+ static char smtpauthtimestamp[65];
+ 
+ char unique[FMT_ULONG + FMT_ULONG + 3];
+ 
+ void base64encode(stralloc *input, stralloc *output)
+ {
+ int	a=0,b=0,c=0;
+ int	i, j;
+ int	d, e, f, g;
+ 
+ 	if (input->len == 0)	return;
+ 
+ 	for (j=i=0; i< input->len ; i += 3)
+ 	{
+ 		a=input->s[i];
+ 		b= i+1 < input->len ? input->s[i+1]:0;
+ 		c= i+2 < input->len ? input->s[i+2]:0;
+ 
+ 		d=base64_alphabet[ a >> 2 ];
+ 		e=base64_alphabet[ ((a & 3 ) << 4) | (b >> 4)];
+ 		f=base64_alphabet[ ((b & 15) << 2) | (c >> 6)];
+ 		g=base64_alphabet[ c & 63 ];
+ 		if (i + 1 >= input->len) f='=';
+ 		if (i + 2 >= input->len) g='=';
+ 		stralloc_append(output,&d);
+ 		stralloc_append(output,&e);
+ 		stralloc_append(output,&f);
+ 		stralloc_append(output,&g);
+ 	}
+ }
+ 
+ static int smtpauth_getl(void) {
+   int i;
+   if (!stralloc_copys(&smtpauth, "")) return -1;
+   for (;;) {
+     if (!stralloc_readyplus(&smtpauth,1)) return -1;
+     i = substdio_get(&ssin, smtpauth.s + smtpauth.len, 1);
+     if (i != 1) return i;
+     if (smtpauth.s[smtpauth.len] == '\n') break;
+     ++smtpauth.len;
+   }
+   if (smtpauth.len > 0) if (smtpauth.s[smtpauth.len-1] == '\r') --smtpauth.len;
+   smtpauth.s[smtpauth.len] = 0;
+   return smtpauth.len;
+ }
+ 
+ static void smtpauth_authenticate(void)
+ {
+   int st, pid, fds[2];
+   
+     if (pipe(fds)) {
+       out("535 pipe failure\r\n");
+       flush();
+       _exit(0);
+     }
+     /* spawn external program
+ 
+     external program should return '0' if it was successful,
+ 
+     submit: /bin/checkpassword /bin/true
+   
+     */
+     switch ((pid=fork())) {
+       case -1: die_fork();
+       case 0: close(fds[1]);
+         fd_copy(3,fds[0]);
+         flush();
+         execvp(smtpauth_argv[1], smtpauth_argv+1);
+         die_nomem();
+     };
+     close(fds[0]);
+     write(fds[1], smtpauthlogin, str_len(smtpauthlogin)+1);
+     write(fds[1], smtpauthpass, str_len(smtpauthpass)+1);
+     if (str_len(smtpauthtimestamp))
+     {
+           write(fds[1], smtpauthtimestamp, str_len(smtpauthtimestamp)+1);
+     }
+     close(fds[1]);
+     wait_pid(&st, pid);
+ 
+     if (wait_crashed(st))
+       die_crash();
+     if (wait_exitcode(st) == 0) {
+       out("235 go ahead\r\n");
+       flush();
+       relayclient="";
+       authenticated=1;
+       stderr_prefix("auth");
+       if (!stralloc_cats(&err,smtpauthlogin)) die_nomem();
+       stderr_suffix();
+       return;
+     }
+     sleep(2);
+     out("535 auth failure\r\n"); 
+     flush(); 
+     return;
+ }
+ 
+ void smtp_auth(arg) char *arg;
+ {
+   int ret,i,toolong,start;
+   char *helper;
+ 
+   if (!smtpauth_enabled) {
+     err_unimpl();
+     flush();
+     return;
+   }
+ 
+   /* netscape 4.5 sends AUTH LOGIN <base64encodedusername>
+      microsoft outlook express sends AUTH LOGIN
+ 
+      idea is simple
+ 
+      use an external program to test authority
+      if success, set 'RELAYCLIENT'
+      otherwise, let them know nicely (hangup)
+ 
+      note, i really don't like djb's coding style even though i'm using it here.
+      i think using spaces for tabs is bad.
+                                                 -mrs.brisby@nimh.org
+   */
+   /* Here i've added support for other auth types.
+   
+   						-brush@elysium.pl	*/
+   if (!authenticated)
+   {
+     if ((ret=strncasecmp(arg,"login",5))==0)
+     {
+       while (arg && *arg && *arg != ' ') arg++;
+ 
+       /* pass over the space */
+       while (arg && *arg && *arg == ' ') arg++;
+ 
+       if (arg && *arg) {
+         /* here's the base64 encoded login */
+         base64_dec_buffer(arg, smtpauthlogin, sizeof(smtpauthlogin));
+       } else {
+         out("334 VXNlcm5hbWU6\r\n"); /* b64 <- 'Username:' */
+         flush();
+         if (smtpauth_getl() > 0)
+           base64_dec_buffer(smtpauth.s, smtpauthlogin, sizeof(smtpauthlogin));
+         else
+           die_read();
+       }
+       out("334 UGFzc3dvcmQ6\r\n"); /* b64 <- 'Password:' */
+       flush();
+       if (smtpauth_getl() > 0)
+         base64_dec_buffer(smtpauth.s, smtpauthpass, sizeof(smtpauthpass));
+       else
+         die_read();
+       smtpauthtimestamp[0]=0;
+       smtpauth_authenticate();  
+       return;
+     }
+     else if ((ret=strncasecmp(arg,"plain",5))==0)
+     {
+       static char smtpauthloginpass[200];
+ 
+       while (arg && *arg && *arg != ' ') arg++;
+ 
+       /* pass over the space */
+       while (arg && *arg && *arg == ' ') arg++;
+  
+       if (arg && *arg)
+       {
+         if(strlen(arg)*3/4 >= sizeof(smtpauthloginpass))
+         {
+           out("535 input too long\r\n");
+           flush();
+           return;
+         }
+         /* here's the base64 encoded login/password */
+         base64_dec_buffer(arg, smtpauthloginpass, sizeof(smtpauthloginpass)-1);
+       } else {
+         out("334 ok. go on.\r\n");
+         flush();
+         i=smtpauth_getl();
+         if(i <= 0)
+           die_read();
+         else if(i*3/4 >= sizeof(smtpauthloginpass))
+         {
+           out("535 input too long\r\n");
+           flush();
+           return;
+         } else base64_dec_buffer(smtpauth.s, smtpauthloginpass, sizeof(smtpauthloginpass)-1);
+       }
+       smtpauthloginpass[sizeof(smtpauthloginpass)-1]=0;
+       start=strlen(smtpauthloginpass)+1;
+       if((start >= sizeof(smtpauthloginpass)) || (strlen(smtpauthloginpass+start) >= 65))
+       {
+           out("535 malformed input\r\n");
+           flush();
+           return;
+       }
+       strcpy(smtpauthlogin,smtpauthloginpass+start);
+ 
+       start+=strlen(smtpauthlogin)+1;
+       if((start >= sizeof(smtpauthloginpass)) || (strlen(smtpauthloginpass+start) >= 65))
+       {
+           out("535 malformed input\r\n");
+           flush();
+           return;
+       }
+       strcpy(smtpauthpass,smtpauthloginpass+start);
+ 
+       smtpauthtimestamp[0]=0;
+       smtpauth_authenticate();
+       return;
+     }
+     else
+     {
+       out("504 auth type not supported\r\n"); 
+       flush();
+       return;
+     }
+   }
+   else
+   {
+       out("503 you are already authenticated\r\n"); 
+       flush(); 
+       return;
+   }
  }
+ #endif
  
  struct commands smtpcommands[] = {
    { "rcpt", smtp_rcpt, 0 }
  , { "mail", smtp_mail, 0 }
  , { "data", smtp_data, flush }
+ #ifdef USE_SMTPAUTH
+ , { "auth", smtp_auth, flush }
+ #endif
  , { "quit", smtp_quit, flush }
  , { "helo", smtp_helo, flush }
  , { "ehlo", smtp_ehlo, flush }
  , { "rset", smtp_rset, 0 }
  , { "help", smtp_help, flush }
+ #ifdef TLS
+ , { "starttls", smtp_tls, flush }
+ #endif
  , { "noop", err_noop, flush }
  , { "vrfy", err_vrfy, flush }
  , { 0, err_unimpl, flush }
  } ;
  
! int main(argc,argv) int argc; char **argv;
  {
+ #ifdef TLS
+   sig_alarmcatch(sigalrm);
+ #endif
+ #ifdef USE_SMTPAUTH
+   if (argc >= 2) {
+     smtpauth_enabled = 1;
+     smtpauth_argv = argv;
+   }
+ #endif
    sig_pipeignore();
    if (chdir(auto_qmail) == -1) die_control();
    setup();
***************
*** 418,421 ****
--- 1197,1201 ----
    out(" ESMTP\r\n");
    if (commands(&ssin,&smtpcommands) == 0) die_read();
    die_nomem();
+   return 0;
  }
Index: qmail/qmail.c
diff -c qmail/qmail.c:1.1.1.1 qmail/qmail.c:1.5
*** qmail/qmail.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/qmail.c	Sat May  6 16:37:21 2006
***************
*** 6,13 ****
  #include "fd.h"
  #include "qmail.h"
  #include "auto_qmail.h"
  
! static char *binqqargs[2] = { "bin/qmail-queue", 0 } ;
  
  int qmail_open(qq)
  struct qmail *qq;
--- 6,22 ----
  #include "fd.h"
  #include "qmail.h"
  #include "auto_qmail.h"
+ #include "env.h"
  
! static char *binqqargs[2] = { 0, 0 } ;
! 
! static void setup_qqargs()
! {
!   if(!binqqargs[0])
!     binqqargs[0] = env_get("QMAILQUEUE");
!   if(!binqqargs[0])
!     binqqargs[0] = "bin/qmail-queue";
! }
  
  int qmail_open(qq)
  struct qmail *qq;
***************
*** 15,20 ****
--- 24,31 ----
    int pim[2];
    int pie[2];
  
+   setup_qqargs();
+ 
    if (pipe(pim) == -1) return -1;
    if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }
   
***************
*** 97,102 ****
--- 108,116 ----
      case 115: /* compatibility */
      case 11: return "Denvelope address too long for qq (#5.1.3)";
      case 31: return "Dmail server permanently rejected message (#5.3.0)";
+     case 32: return "Dunable to read private key file (#4.3.0)";		// for qmail-dk
+     case 33: return "Dmessage rejected due to detected virus (#5.3.0)";
+     case 34: return "Dmessage rejected because it contains X-Spam-Status: Yes (#5.3.0)";
      case 51: return "Zqq out of memory (#4.3.0)";
      case 52: return "Zqq timeout (#4.3.0)";
      case 53: return "Zqq write error or disk full (#4.3.0)";
***************
*** 104,109 ****
--- 118,126 ----
      case 54: return "Zqq read error (#4.3.0)";
      case 55: return "Zqq unable to read configuration (#4.3.0)";
      case 56: return "Zqq trouble making network connection (#4.3.0)";
+     case 57: return "Zqq trouble waiting for qmail-queue to exit (#4.3.0)";	// for qmail-dk
+     case 58: return "Zqq unable to vfork (#4.3.0)";				// for qmail-dk
+     case 59: return "Zqq unable to create a pipe to qmail-queue (#4.3.0)";	// for qmail-dk
      case 61: return "Zqq trouble in home directory (#4.3.0)";
      case 63:
      case 64:
Index: qmail/readwrite.h
diff -c qmail/readwrite.h:1.1.1.1 qmail/readwrite.h:1.2
*** qmail/readwrite.h:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/readwrite.h	Fri Jul 21 12:07:00 2006
***************
*** 1,7 ****
  #ifndef READWRITE_H
  #define READWRITE_H
  
! extern int read();
! extern int write();
  
  #endif
--- 1,6 ----
  #ifndef READWRITE_H
  #define READWRITE_H
  
! #include <unistd.h>
  
  #endif
Index: qmail/realrcptto.c
diff -c /dev/null qmail/realrcptto.c:1.2
*** /dev/null	Fri Aug  7 11:03:19 2009
--- qmail/realrcptto.c	Tue Jul 13 22:35:15 2004
***************
*** 0 ****
--- 1,259 ----
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+ #include <pwd.h>
+ #include "auto_break.h"
+ #include "auto_usera.h"
+ #include "byte.h"
+ #include "case.h"
+ #include "cdb.h"
+ #include "constmap.h"
+ #include "error.h"
+ #include "fmt.h"
+ #include "open.h"
+ #include "str.h"
+ #include "stralloc.h"
+ #include "uint32.h"
+ #include "env.h"
+ 
+ extern void die_nomem();
+ extern void die_control();
+ extern void die_cdb();
+ extern void die_sys();
+ 
+ static stralloc envnoathost = {0};
+ static stralloc percenthack = {0};
+ static stralloc locals = {0};
+ static stralloc vdoms = {0};
+ static struct constmap mappercenthack;
+ static struct constmap maplocals;
+ static struct constmap mapvdoms;
+ 
+ static char *dash;
+ static char *extension;
+ static char *local;
+ static struct passwd *pw;
+ 
+ void realrcptto_init()
+ {
+   char *x;
+ 
+   if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1)
+     die_control();
+ 
+   if (control_readfile(&locals,"control/locals",1) != 1) die_control();
+   if (!constmap_init(&maplocals,locals.s,locals.len,0)) die_nomem();
+   switch(control_readfile(&percenthack,"control/percenthack",0)) {
+     case -1: die_control();
+     case 0: if (!constmap_init(&mappercenthack,"",0,0)) die_nomem();
+     case 1:
+       if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0))
+         die_nomem();
+   }
+   switch(control_readfile(&vdoms,"control/virtualdomains",0)) {
+     case -1: die_control();
+     case 0: if (!constmap_init(&mapvdoms,"",0,1)) die_nomem();
+     case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) die_nomem();
+   }
+ }
+ 
+ #define GETPW_USERLEN 32
+ 
+ static int userext()
+ {
+   char username[GETPW_USERLEN];
+   struct stat st;
+ 
+   extension = local + str_len(local);
+   for (;;) {
+     if (extension - local < sizeof(username))
+       if (!*extension || (*extension == *auto_break)) {
+ 	byte_copy(username,extension - local,local);
+ 	username[extension - local] = 0;
+ 	case_lowers(username);
+ 	errno = 0;
+ 	pw = getpwnam(username);
+ 	if (errno == error_txtbsy) die_sys();
+ 	if (pw)
+ 	  if (pw->pw_uid)
+ 	    if (stat(pw->pw_dir,&st) == 0) {
+ 	      if (st.st_uid == pw->pw_uid) {
+ 		dash = "";
+ 		if (*extension) { ++extension; dash = "-"; }
+ 		return 1;
+ 	      }
+ 	    }
+ 	    else
+ 	      if (error_temp(errno)) die_sys();
+       }
+     if (extension == local) return 0;
+     --extension;
+   }
+ }
+ 
+ int realrcptto(addr)
+ char *addr;
+ {
+   char *homedir;
+   static stralloc localpart = {0};
+   static stralloc lower = {0};
+   static stralloc nughde = {0};
+   static stralloc wildchars = {0};
+   static stralloc safeext = {0};
+   static stralloc qme = {0};
+ 
+   /* qmail-send:rewrite */
+   unsigned int i,at;
+   if (!stralloc_copys(&localpart,addr)) die_nomem();
+   i = byte_rchr(localpart.s,localpart.len,'@');
+   if (i == localpart.len) {
+     if (!stralloc_cats(&localpart,"@")) die_nomem();
+     if (!stralloc_cat(&localpart,&envnoathost)) die_nomem();
+   }
+   while (constmap(&mappercenthack,localpart.s + i + 1,localpart.len - i - 1)) {
+     unsigned int j = byte_rchr(localpart.s,i,'%');
+     if (j == i) break;
+     localpart.len = i;
+     i = j;
+     localpart.s[i] = '@';
+   }
+   at = byte_rchr(localpart.s,localpart.len,'@');
+   if (constmap(&maplocals,localpart.s + at + 1,localpart.len - at - 1)) {
+     localpart.len = at;
+     localpart.s[at] = '\0';
+   } else {
+     unsigned int xlen,newlen;
+     char *x;
+     for (i = 0;;++i) {
+       if (i > localpart.len) return 1;
+       if (!i || (i == at + 1) || (i == localpart.len) ||
+           ((i > at) && (localpart.s[i] == '.'))) {
+         x = constmap(&mapvdoms,localpart.s + i,localpart.len - i);
+         if (x) break;
+       }
+     }
+     if (!*x) return 1;
+     xlen = str_len(x) + 1;  /* +1 for '-' */
+     newlen = xlen + at + 1; /* +1 for \0 */
+     if (xlen < 1 || newlen - 1 < xlen || newlen < 1 ||
+         !stralloc_ready(&localpart,newlen))
+       die_nomem();
+     localpart.s[newlen - 1] = '\0';
+     byte_copyr(localpart.s + xlen,at,localpart.s);
+     localpart.s[xlen - 1] = '-';
+     byte_copy(localpart.s,xlen - 1,x);
+     localpart.len = newlen;
+   }
+ 
+   /* qmail-lspawn:nughde_get */
+   {
+     int r,fd,flagwild;
+     if (!stralloc_copys(&lower,"!")) die_nomem();
+     if (!stralloc_cats(&lower,localpart.s)) die_nomem();
+     if (!stralloc_0(&lower)) die_nomem();
+     case_lowerb(lower.s,lower.len);
+     if (!stralloc_copys(&nughde,"")) die_nomem();
+     fd = open_read("users/cdb");
+     if (fd == -1) {
+       if (errno != error_noent) die_cdb();
+     } else {
+       uint32 dlen;
+       r = cdb_seek(fd,"",0,&dlen);
+       if (r != 1) die_cdb();
+       if (!stralloc_ready(&wildchars,(unsigned int) dlen)) die_nomem();
+       wildchars.len = dlen;
+       if (cdb_bread(fd,wildchars.s,wildchars.len) == -1) die_cdb();
+       i = lower.len;
+       flagwild = 0;
+       do { /* i > 0 */
+         if (!flagwild || (i == 1) ||
+             (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1])
+              < wildchars.len)) {
+           r = cdb_seek(fd,lower.s,i,&dlen);
+           if (r == -1) die_cdb();
+           if (r == 1) {
+             char *x;
+             if (!stralloc_ready(&nughde,(unsigned int) dlen)) die_nomem();
+             nughde.len = dlen;
+             if (cdb_bread(fd,nughde.s,nughde.len) == -1) die_cdb();
+             if (flagwild)
+               if (!stralloc_cats(&nughde,localpart.s + i - 1)) die_nomem();
+             if (!stralloc_0(&nughde)) die_nomem();
+             close(fd);
+             x=nughde.s;
+             /* skip username */
+             x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+             if (x == nughde.s + nughde.len) return 1;
+             ++x;
+             /* skip uid */
+             x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+             if (x == nughde.s + nughde.len) return 1;
+             ++x;
+             /* skip gid */
+             x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+             if (x == nughde.s + nughde.len) return 1;
+             ++x;
+             /* skip homedir */
+             homedir=x;
+             x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+             if (x == nughde.s + nughde.len) return 1;
+             ++x;
+             /* skip dash */
+             dash=x;
+             x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+             if (x == nughde.s + nughde.len) return 1;
+             ++x;
+             extension=x;
+             goto got_nughde;
+           }
+         }
+         --i;
+         flagwild = 1;
+       } while (i);
+       close(fd);
+     }
+   }
+ 
+   /* qmail-getpw */
+   local = localpart.s;
+   if (!userext()) {
+     extension = local;
+     dash = "-";
+     pw = getpwnam(auto_usera);
+   }
+   if (!pw) { return 0; }
+   if (!stralloc_copys(&nughde,pw->pw_dir)) die_nomem();
+   if (!stralloc_0(&nughde)) die_nomem();
+   homedir=nughde.s;
+ 
+   got_nughde:
+ 
+   /* qmail-local:qmesearch */
+   if (!*dash) return 1;
+   if (!stralloc_copys(&safeext,extension)) die_nomem();
+   case_lowerb(safeext.s,safeext.len);
+   for (i = 0;i < safeext.len;++i)
+     if (safeext.s[i] == '.')
+       safeext.s[i] = ':';
+   {
+     struct stat st;
+     int i;
+     if (!stralloc_copys(&qme,homedir)) die_nomem();
+     if (!stralloc_cats(&qme,"/.qmail")) die_nomem();
+     if (!stralloc_cats(&qme,dash)) die_nomem();
+     if (!stralloc_cat(&qme,&safeext)) die_nomem();
+     if (!stralloc_0(&qme)) die_nomem();
+     if (stat(qme.s, &st) == 0 || errno != error_noent) return 1;
+     for (i = safeext.len;i >= 0;--i)
+       if (!i || (safeext.s[i - 1] == '-')) {
+         if (!stralloc_copys(&qme,homedir)) die_nomem();
+         if (!stralloc_cats(&qme,"/.qmail")) die_nomem();
+         if (!stralloc_cats(&qme,dash)) die_nomem();
+         if (!stralloc_catb(&qme,safeext.s,i)) die_nomem();
+         if (!stralloc_cats(&qme,"default")) die_nomem();
+         if (!stralloc_0(&qme)) die_nomem();
+         if (stat(qme.s, &st) == 0 || errno != error_noent) return 1;
+       }
+     return 0;
+   }
+ }
Index: qmail/received.c
diff -c qmail/received.c:1.1.1.1 qmail/received.c:1.2
*** qmail/received.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/received.c	Wed Dec 26 20:55:04 2001
***************
*** 37,43 ****
  /* "Received: from relay1.uu.net (HELO uunet.uu.net) (7@192.48.96.5)\n" */
  /* "  by silverton.berkeley.edu with SMTP; 26 Sep 1995 04:46:54 -0000\n" */
  
! void received(qqt,protocol,local,remoteip,remotehost,remoteinfo,helo)
  struct qmail *qqt;
  char *protocol;
  char *local;
--- 37,43 ----
  /* "Received: from relay1.uu.net (HELO uunet.uu.net) (7@192.48.96.5)\n" */
  /* "  by silverton.berkeley.edu with SMTP; 26 Sep 1995 04:46:54 -0000\n" */
  
! void received(qqt,protocol,local,remoteip,remotehost,remoteinfo,helo,authuser)
  struct qmail *qqt;
  char *protocol;
  char *local;
***************
*** 45,50 ****
--- 45,51 ----
  char *remotehost;
  char *remoteinfo;
  char *helo;
+ char *authuser;
  {
    struct datetime dt;
  
***************
*** 55,60 ****
--- 56,66 ----
      safeput(qqt,helo);
      qmail_puts(qqt,")");
    }
+   if (authuser) {
+     qmail_puts(qqt," (AUTH ");
+     safeput(qqt,authuser);
+     qmail_puts(qqt,")");
+   }
    qmail_puts(qqt," (");
    if (remoteinfo) {
      safeput(qqt,remoteinfo);
Index: qmail/remoteinfo.c
diff -c qmail/remoteinfo.c:1.1.1.1 qmail/remoteinfo.c:1.2
*** qmail/remoteinfo.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/remoteinfo.c	Fri Jan 13 14:22:28 2006
***************
*** 44,55 ****
    s = socket(AF_INET,SOCK_STREAM,0);
    if (s == -1) return 0;
   
!   byte_zero(&sin,sizeof(sin));
    sin.sin_family = AF_INET;
    byte_copy(&sin.sin_addr,4,ipl);
    sin.sin_port = 0;
!   if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; }
!   if (timeoutconn(s,ipr,113,timeout) == -1) { close(s); return 0; }
    fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY);
   
    len = 0;
--- 44,55 ----
    s = socket(AF_INET,SOCK_STREAM,0);
    if (s == -1) return 0;
   
! /*  byte_zero(&sin,sizeof(sin));
    sin.sin_family = AF_INET;
    byte_copy(&sin.sin_addr,4,ipl);
    sin.sin_port = 0;
!   if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; } */
!   if (timeoutconn(s,ipr,ipl,113,timeout) == -1) { close(s); return 0; }
    fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY);
   
    len = 0;
Index: qmail/sendmail.c
diff -c qmail/sendmail.c:1.1.1.1 qmail/sendmail.c:1.2
*** qmail/sendmail.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/sendmail.c	Sun May 11 23:06:28 2003
***************
*** 1,3 ****
--- 1,6 ----
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <fcntl.h>
  #include "sgetopt.h"
  #include "substdio.h"
  #include "subfd.h"
***************
*** 19,24 ****
--- 22,71 ----
    _exit(100);
  }
  
+ void die_pipe()
+ {
+   substdio_putsflush(subfderr,"sendmail: unable to open pipe\n");
+   _exit(111);
+ }
+ 
+ void die_fork()
+ {
+   substdio_putsflush(subfderr,"sendmail: unable to fork\n");
+   _exit(111);
+ }
+ 
+ void die_dup2()
+ {
+   substdio_putsflush(subfderr,"sendmail: unable to dup2\n");
+   _exit(111);
+ }
+ 
+ char *sploggerarg[] = { "bin/splogger", "sendmail-bs", 0 };
+ void splogger()
+ {
+   int fd[2];
+   pid_t pid;
+ 
+   if (pipe(fd)) die_pipe();
+   pid = fork();
+   if (pid == -1) die_fork();
+   if (pid == 0) {
+     close(0);
+     close(1);
+     close(2);
+     if (dup2(fd[0], 0) < 0) _exit(111);
+     if (open("/dev/null", O_WRONLY) != 1) _exit(111);
+     if (open("/dev/null", O_WRONLY) != 2) _exit(111);
+     close(fd[0]);
+     close(fd[1]);
+     execv(*sploggerarg, sploggerarg);
+     _exit(111);
+   }
+   close(fd[0]);
+   if (dup2(fd[1], 2) < 0) die_dup2();
+   close(fd[1]);
+ }
+ 
  char *smtpdarg[] = { "bin/qmail-smtpd", 0 };
  void smtpd()
  {
***************
*** 32,37 ****
--- 79,85 ----
      if (!env_put("TCPREMOTEHOST=localhost")) nomem();
      if (!env_put("TCPREMOTEINFO=sendmail-bs")) nomem();
    }
+   splogger();
    execv(*smtpdarg,smtpdarg);
    substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-smtpd\n");
    _exit(111);
Index: qmail/syncdir.c
diff -c /dev/null qmail/syncdir.c:1.1
*** /dev/null	Fri Aug  7 11:03:19 2009
--- qmail/syncdir.c	Thu Dec 27 10:08:09 2001
***************
*** 0 ****
--- 1,110 ----
+ /* syncdir -- emulate synchronous directories
+     Copyright (C) 1998 Bruce Guenter
+ 
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+ 
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+     GNU General Public License for more details.
+ 
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ 
+     You can reach me at bruce.guenter@qcc.sk.ca
+ */
+ 
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #define open XXX_open
+ #include <fcntl.h>
+ #undef open
+ #include <unistd.h>
+ #include <string.h>
+ #include <syscall.h>
+ #include <stdio.h>
+ #include <errno.h>
+ 
+ #define SYS_OPEN(FILE,FLAG,MODE) syscall(SYS_open, FILE, FLAG, MODE)
+ #define SYS_CLOSE(FD) syscall(SYS_close, FD)
+ #define SYS_LINK(OLD,NEW) syscall(SYS_link, OLD, NEW)
+ #define SYS_UNLINK(PATH) syscall(SYS_unlink, PATH)
+ #define SYS_RENAME(OLD,NEW) syscall(SYS_rename, OLD, NEW)
+ #define SYS_FSYNC(FD) syscall(SYS_fsync, FD)
+ 
+ static int fdirsync(const char* filename, unsigned length)
+ {
+   char dirname[length+1];
+   /* This could also be:
+    * char* dirname = alloca(length+1); */
+   int dirfd;
+   int retval;
+   memcpy(dirname, filename, length);
+   dirname[length] = 0;
+   if((dirfd = SYS_OPEN(dirname,O_RDONLY,0)) == -1)
+     return -1;
+   retval = (SYS_FSYNC(dirfd) == -1 && errno == EIO) ? -1 : 0;
+   SYS_CLOSE(dirfd);
+   return retval;
+ }
+ 
+ static int fdirsyncfn(const char *filename)
+ {
+    const char *slash = filename+strlen(filename)-1;
+ 
+    /* Skip over trailing slashes, which would be ignored by some
+     * operations */
+    while(slash > filename && *slash == '/')
+      --slash;
+ 
+    /* Skip back to the next slash */
+    while(slash > filename && *slash != '/')
+      --slash;
+ 
+    /* slash now either points to a '/' character, or no slash was found */
+    if(*slash == '/')
+       return fdirsync(filename,
+                       (slash == filename) ? 1 : slash-filename);
+    else
+      return fdirsync(".", 1);
+ }
+ 
+ int open(const char *file,int oflag,mode_t mode)
+ {
+   int fd = SYS_OPEN(file, oflag, mode);
+   if(fd == -1)
+     return fd;
+   if (oflag & (O_WRONLY | O_RDWR))
+     if (fdirsyncfn(file) == -1) {
+       SYS_CLOSE(fd);
+       return -1;
+     }
+   return fd;
+ }
+ 
+ int link(const char *oldpath,const char *newpath)
+ {
+    if(SYS_LINK(oldpath,newpath) == -1)
+      return -1;
+    return fdirsyncfn(newpath);
+ }
+ 
+ int unlink(const char *path)
+ {
+    if(SYS_UNLINK(path) == -1)
+      return -1;
+    return fdirsyncfn(path);
+ }
+ 
+ int rename(const char *oldpath,const char *newpath)
+ {
+    if (SYS_RENAME(oldpath,newpath) == -1)
+      return -1;
+    if (fdirsyncfn(newpath) == -1)
+      return -1;
+    return fdirsyncfn(oldpath);
+ }
Index: qmail/timeoutconn.c
diff -c qmail/timeoutconn.c:1.1.1.1 qmail/timeoutconn.c:1.2
*** qmail/timeoutconn.c:1.1.1.1	Mon Nov 26 18:20:07 2001
--- qmail/timeoutconn.c	Fri Jan 13 14:22:28 2006
***************
*** 10,18 ****
  #include "byte.h"
  #include "timeoutconn.h"
  
! int timeoutconn(s,ip,port,timeout)
  int s;
  struct ip_address *ip;
  unsigned int port;
  int timeout;
  {
--- 10,19 ----
  #include "byte.h"
  #include "timeoutconn.h"
  
! int timeoutconn(s,ip,outip,port,timeout)
  int s;
  struct ip_address *ip;
+ struct ip_address *outip;
  unsigned int port;
  int timeout;
  {
***************
*** 22,27 ****
--- 23,35 ----
    fd_set wfds;
    struct timeval tv;
   
+   /* bind() an outgoing ipaddr */
+   byte_zero(&sin,sizeof(sin));
+   byte_copy(&sin.sin_addr.s_addr,4,outip);
+   sin.sin_family = AF_INET;
+ 
+   if (-1 == bind(s,(struct sockaddr *) &sin,sizeof(sin))) return -1;
+ 
    byte_zero(&sin,sizeof(sin));
    byte_copy(&sin.sin_addr,4,ip);
    x = (char *) &sin.sin_port;
