summaryrefslogtreecommitdiff
path: root/debian
diff options
context:
space:
mode:
Diffstat (limited to 'debian')
-rw-r--r--debian/changelog8
-rw-r--r--debian/patches/8.12/8.12.3/z_CVE-2006-0058.patch2768
2 files changed, 2776 insertions, 0 deletions
diff --git a/debian/changelog b/debian/changelog
index 255a001..21d0882 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+sendmail (8.12.3-7.2) oldstable-security; urgency=high
+
+ * Non-maintainer upload by the Security Team
+ * Backported upstream patch to fix remote command execution
+ [debian/patches/8.12/8.12.3/z_CVE-2006-0058.patch, VU#834865]
+
+ -- Martin Schulze <joey@infodrom.org> Wed, 22 Mar 2006 23:24:46 +0100
+
sendmail (8.12.3-7.1) stable-security; urgency=high
* Non-maintainer upload by the Security Team
diff --git a/debian/patches/8.12/8.12.3/z_CVE-2006-0058.patch b/debian/patches/8.12/8.12.3/z_CVE-2006-0058.patch
new file mode 100644
index 0000000..a81a583
--- /dev/null
+++ b/debian/patches/8.12/8.12.3/z_CVE-2006-0058.patch
@@ -0,0 +1,2768 @@
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/libsm/fflush.c sendmail-8.12.3/libsm/fflush.c
+--- sendmail-8.12.3.orig/libsm/fflush.c 2001-09-11 06:04:48.000000000 +0200
++++ sendmail-8.12.3/libsm/fflush.c 2006-03-22 22:42:44.000000000 +0100
+@@ -145,6 +145,7 @@ sm_flush(fp, timeout)
+ return SM_IO_EOF;
+ }
+ SM_IO_WR_TIMEOUT(fp, fd, *timeout);
++ t = 0;
+ }
+ }
+ return 0;
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/libsm/local.h sendmail-8.12.3/libsm/local.h
+--- sendmail-8.12.3.orig/libsm/local.h 2002-02-20 03:40:24.000000000 +0100
++++ sendmail-8.12.3/libsm/local.h 2006-03-22 22:42:45.000000000 +0100
+@@ -193,7 +193,7 @@ extern const char SmFileMagic[];
+ else \
+ { \
+ (time)->tv_sec = (val) / 1000; \
+- (time)->tv_usec = ((val) - ((time)->tv_sec * 1000)) * 10; \
++ (time)->tv_usec = ((val) - ((time)->tv_sec * 1000)) * 1000; \
+ } \
+ if ((val) == SM_TIME_FOREVER) \
+ { \
+@@ -277,7 +277,7 @@ extern const char SmFileMagic[];
+ else \
+ { \
+ sm_io_to.tv_sec = (to) / 1000; \
+- sm_io_to.tv_usec = ((to) - (sm_io_to.tv_sec * 1000)) * 10; \
++ sm_io_to.tv_usec = ((to) - (sm_io_to.tv_sec * 1000)) * 1000; \
+ } \
+ FD_ZERO(&sm_io_to_mask); \
+ FD_SET((fd), &sm_io_to_mask); \
+@@ -285,8 +285,11 @@ extern const char SmFileMagic[];
+ FD_SET((fd), &sm_io_x_mask); \
+ if (gettimeofday(&sm_io_to_before, NULL) < 0) \
+ return SM_IO_EOF; \
+- sm_io_to_sel = select((fd) + 1, NULL, &sm_io_to_mask, &sm_io_x_mask, \
+- &sm_io_to); \
++ do \
++ { \
++ sm_io_to_sel = select((fd) + 1, NULL, &sm_io_to_mask, \
++ &sm_io_x_mask, &sm_io_to); \
++ } while (sm_io_to_sel < 0 && errno == EINTR); \
+ if (sm_io_to_sel < 0) \
+ { \
+ /* something went wrong, errno set */ \
+@@ -301,10 +304,9 @@ extern const char SmFileMagic[];
+ /* else loop again */ \
+ if (gettimeofday(&sm_io_to_after, NULL) < 0) \
+ return SM_IO_EOF; \
+- timersub(&sm_io_to_before, &sm_io_to_after, &sm_io_to_diff); \
+- timersub(&sm_io_to, &sm_io_to_diff, &sm_io_to); \
+- (to) -= (sm_io_to.tv_sec * 1000); \
+- (to) -= (sm_io_to.tv_usec / 10); \
++ timersub(&sm_io_to_after, &sm_io_to_before, &sm_io_to_diff); \
++ (to) -= (sm_io_to_diff.tv_sec * 1000); \
++ (to) -= (sm_io_to_diff.tv_usec / 1000); \
+ if ((to) < 0) \
+ (to) = 0; \
+ }
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/libsm/refill.c sendmail-8.12.3/libsm/refill.c
+--- sendmail-8.12.3.orig/libsm/refill.c 2001-09-11 06:04:49.000000000 +0200
++++ sendmail-8.12.3/libsm/refill.c 2006-03-22 22:42:45.000000000 +0100
+@@ -71,8 +71,11 @@ static int sm_lflush __P((SM_FILE_T *, i
+ FD_SET((fd), &sm_io_x_mask); \
+ if (gettimeofday(&sm_io_to_before, NULL) < 0) \
+ return SM_IO_EOF; \
+- (sel_ret) = select((fd) + 1, &sm_io_to_mask, NULL, \
+- &sm_io_x_mask, (to)); \
++ do \
++ { \
++ (sel_ret) = select((fd) + 1, &sm_io_to_mask, NULL, \
++ &sm_io_x_mask, (to)); \
++ } while ((sel_ret) < 0 && errno == EINTR); \
+ if ((sel_ret) < 0) \
+ { \
+ /* something went wrong, errno set */ \
+@@ -89,7 +92,7 @@ static int sm_lflush __P((SM_FILE_T *, i
+ /* calulate wall-clock time used */ \
+ if (gettimeofday(&sm_io_to_after, NULL) < 0) \
+ return SM_IO_EOF; \
+- timersub(&sm_io_to_before, &sm_io_to_after, &sm_io_to_diff); \
++ timersub(&sm_io_to_after, &sm_io_to_before, &sm_io_to_diff); \
+ timersub((to), &sm_io_to_diff, (to)); \
+ }
+
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/collect.c sendmail-8.12.3/sendmail/collect.c
+--- sendmail-8.12.3.orig/sendmail/collect.c 2002-03-15 02:32:47.000000000 +0100
++++ sendmail-8.12.3/sendmail/collect.c 2006-03-22 22:47:28.000000000 +0100
+@@ -15,7 +15,6 @@
+
+ SM_RCSID("@(#)$Id: collect.c,v 8.241 2002/03/15 01:32:47 gshapiro Exp $")
+
+-static void collecttimeout __P((time_t));
+ static void dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *));
+ static void eatfrom __P((char *volatile, ENVELOPE *));
+ static void collect_doheader __P((ENVELOPE *));
+@@ -263,10 +262,6 @@ collect_dfopen(e)
+ ** If data file cannot be created, the process is terminated.
+ */
+
+-static jmp_buf CtxCollectTimeout;
+-static bool volatile CollectProgress;
+-static SM_EVENT *volatile CollectTimeout = NULL;
+-
+ /* values for input state machine */
+ #define IS_NORM 0 /* middle of line */
+ #define IS_BOL 1 /* beginning of line */
+@@ -288,26 +283,30 @@ collect(fp, smtpmode, hdrp, e)
+ register ENVELOPE *e;
+ {
+ register SM_FILE_T *volatile df;
+- volatile bool ignrdot;
+- volatile time_t dbto;
++ bool ignrdot;
++ int dbto;
+ register char *volatile bp;
+- volatile int c;
+- volatile bool inputerr;
++ int c;
++ bool inputerr;
+ bool headeronly;
+- char *volatile buf;
+- volatile int buflen;
+- volatile int istate;
+- volatile int mstate;
+- volatile int hdrslen;
+- volatile int numhdrs;
+- volatile int afd;
+- unsigned char *volatile pbp;
++ char *buf;
++ int buflen;
++ int istate;
++ int mstate;
++ int hdrslen;
++ int numhdrs;
++ int afd;
++ unsigned char *pbp;
+ unsigned char peekbuf[8];
+ char bufbuf[MAXLINE];
+
+ df = NULL;
+ ignrdot = smtpmode ? false : IgnrDot;
+- dbto = smtpmode ? TimeOuts.to_datablock : 0;
++
++ /* timeout for I/O functions is in milliseconds */
++ dbto = smtpmode ? ((int) TimeOuts.to_datablock * 1000)
++ : SM_TIME_FOREVER;
++ sm_io_setinfo(fp, SM_IO_WHAT_TIMEOUT, &dbto);
+ c = SM_IO_EOF;
+ inputerr = false;
+ headeronly = hdrp != NULL;
+@@ -319,7 +318,6 @@ collect(fp, smtpmode, hdrp, e)
+ pbp = peekbuf;
+ istate = IS_BOL;
+ mstate = SaveFrom ? MS_HEADER : MS_UFROM;
+- CollectProgress = false;
+
+ /*
+ ** Tell ARPANET to go ahead.
+@@ -340,22 +338,6 @@ collect(fp, smtpmode, hdrp, e)
+ ** the larger picture (e.g., header versus body).
+ */
+
+- if (dbto != 0)
+- {
+- /* handle possible input timeout */
+- if (setjmp(CtxCollectTimeout) != 0)
+- {
+- if (LogLevel > 2)
+- sm_syslog(LOG_NOTICE, e->e_id,
+- "timeout waiting for input from %s during message collect",
+- CURHOSTNAME);
+- errno = 0;
+- usrerr("451 4.4.1 timeout waiting for input during message collect");
+- goto readerr;
+- }
+- CollectTimeout = sm_setevent(dbto, collecttimeout, dbto);
+- }
+-
+ e->e_msgsize = 0;
+ for (;;)
+ {
+@@ -378,9 +360,26 @@ collect(fp, smtpmode, hdrp, e)
+ sm_io_clearerr(fp);
+ continue;
+ }
++
++ /* timeout? */
++ if (c == SM_IO_EOF && errno == EAGAIN
++ && smtpmode)
++ {
++ /*
++ ** Override e_message in
++ ** usrerr() as this is the
++ ** reason for failure that
++ ** should be logged for
++ ** undelivered recipients.
++ */
++
++ e->e_message = NULL;
++ errno = 0;
++ inputerr = true;
++ goto readabort;
++ }
+ break;
+ }
+- CollectProgress = true;
+ if (TrafficLogFile != NULL && !headeronly)
+ {
+ if (istate == IS_BOL)
+@@ -523,6 +522,18 @@ bufferchar:
+ buflen *= 2;
+ else
+ buflen += MEMCHUNKSIZE;
++ if (buflen <= 0)
++ {
++ sm_syslog(LOG_NOTICE, e->e_id,
++ "header overflow from %s during message collect",
++ CURHOSTNAME);
++ errno = 0;
++ e->e_flags |= EF_CLRQUEUE;
++ e->e_status = "5.6.0";
++ usrerrenh(e->e_status,
++ "552 Headers too large");
++ goto discard;
++ }
+ buf = xalloc(buflen);
+ memmove(buf, obuf, bp - obuf);
+ bp = &buf[bp - obuf];
+@@ -566,6 +577,7 @@ bufferchar:
+ usrerrenh(e->e_status,
+ "552 Headers too large (%d max)",
+ MaxHeadersLength);
++ discard:
+ mstate = MS_DISCARD;
+ }
+ }
+@@ -605,6 +617,24 @@ nextstate:
+ sm_io_clearerr(fp);
+ errno = 0;
+ c = sm_io_getc(fp, SM_TIME_DEFAULT);
++
++ /* timeout? */
++ if (c == SM_IO_EOF && errno == EAGAIN
++ && smtpmode)
++ {
++ /*
++ ** Override e_message in
++ ** usrerr() as this is the
++ ** reason for failure that
++ ** should be logged for
++ ** undelivered recipients.
++ */
++
++ e->e_message = NULL;
++ errno = 0;
++ inputerr = true;
++ goto readabort;
++ }
+ } while (c == SM_IO_EOF && errno == EINTR);
+ if (c != SM_IO_EOF)
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
+@@ -614,6 +644,11 @@ nextstate:
+ continue;
+ }
+
++ SM_ASSERT(bp > buf);
++
++ /* guaranteed by isheader(buf) */
++ SM_ASSERT(*(bp - 1) != '\n' || bp > buf + 1);
++
+ /* trim off trailing CRLF or NL */
+ if (*--bp != '\n' || *--bp != '\r')
+ bp++;
+@@ -680,10 +715,6 @@ readerr:
+ inputerr = true;
+ }
+
+- /* reset global timer */
+- if (CollectTimeout != NULL)
+- sm_clrevent(CollectTimeout);
+-
+ if (headeronly)
+ return;
+
+@@ -761,6 +792,7 @@ readerr:
+ }
+
+ /* An EOF when running SMTP is an error */
++ readabort:
+ if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
+ {
+ char *host;
+@@ -782,13 +814,14 @@ readerr:
+ problem, host,
+ shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
+ if (sm_io_eof(fp))
+- usrerr("451 4.4.1 collect: %s on connection from %s, from=%s",
++ usrerr("421 4.4.1 collect: %s on connection from %s, from=%s",
+ problem, host,
+ shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
+ else
+- syserr("451 4.4.1 collect: %s on connection from %s, from=%s",
++ syserr("421 4.4.1 collect: %s on connection from %s, from=%s",
+ problem, host,
+ shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
++ flush_errors(true);
+
+ /* don't return an error indication */
+ e->e_to = NULL;
+@@ -862,39 +895,6 @@ readerr:
+ markstats(e, (ADDRESS *) NULL, STATS_NORMAL);
+ }
+
+-static void
+-collecttimeout(timeout)
+- time_t timeout;
+-{
+- int save_errno = errno;
+-
+- /*
+- ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+- ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+- ** DOING.
+- */
+-
+- if (CollectProgress)
+- {
+- /* reset the timeout */
+- CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout,
+- timeout);
+- CollectProgress = false;
+- }
+- else
+- {
+- /* event is done */
+- CollectTimeout = NULL;
+- }
+-
+- /* if no progress was made or problem resetting event, die now */
+- if (CollectTimeout == NULL)
+- {
+- errno = ETIMEDOUT;
+- longjmp(CtxCollectTimeout, 1);
+- }
+- errno = save_errno;
+-}
+ /*
+ ** DFERROR -- signal error on writing the data file.
+ **
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/conf.c sendmail-8.12.3/sendmail/conf.c
+--- sendmail-8.12.3.orig/sendmail/conf.c 2006-03-22 22:27:15.000000000 +0100
++++ sendmail-8.12.3/sendmail/conf.c 2006-03-22 22:42:45.000000000 +0100
+@@ -5145,8 +5145,8 @@ sm_syslog(level, id, fmt, va_alist)
+ va_dcl
+ #endif /* __STDC__ */
+ {
+- static char *buf = NULL;
+- static size_t bufsize;
++ char *buf;
++ size_t bufsize;
+ char *begin, *end;
+ int save_errno;
+ int seq = 1;
+@@ -5170,11 +5170,8 @@ sm_syslog(level, id, fmt, va_alist)
+ else
+ idlen = strlen(id) + SyslogPrefixLen;
+
+- if (buf == NULL)
+- {
+- buf = buf0;
+- bufsize = sizeof buf0;
+- }
++ buf = buf0;
++ bufsize = sizeof buf0;
+
+ for (;;)
+ {
+@@ -5216,8 +5213,8 @@ sm_syslog(level, id, fmt, va_alist)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s\n", id, newstring);
+ #endif /* LOG */
+- if (buf == buf0)
+- buf = NULL;
++ if (buf != buf0)
++ sm_free(buf);
+ errno = save_errno;
+ return;
+ }
+@@ -5281,8 +5278,8 @@ sm_syslog(level, id, fmt, va_alist)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s[%d]: %s\n", id, seq, begin);
+ #endif /* LOG */
+- if (buf == buf0)
+- buf = NULL;
++ if (buf != buf0)
++ sm_free(buf);
+ errno = save_errno;
+ }
+ /*
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/deliver.c sendmail-8.12.3/sendmail/deliver.c
+--- sendmail-8.12.3.orig/sendmail/deliver.c 2002-03-23 19:30:40.000000000 +0100
++++ sendmail-8.12.3/sendmail/deliver.c 2006-03-22 23:32:26.000000000 +0100
+@@ -3179,16 +3179,33 @@ do_transfer:
+ }
+ else if (!clever)
+ {
++ bool ok;
++
+ /*
+ ** Format and send message.
+ */
+
+- putfromline(mci, e);
+- (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
+- (*e->e_putbody)(mci, e, NULL);
++ rcode = EX_OK;
++ errno = 0;
++ ok = putfromline(mci, e);
++ if (ok)
++ ok = (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
++ if (ok)
++ ok = (*e->e_putbody)(mci, e, NULL);
++
++ /*
++ ** Ignore an I/O error that was caused by EPIPE.
++ ** Some broken mailers don't read the entire body
++ ** but just exit() thus causing an I/O error.
++ */
++
++ if (!ok && (sm_io_error(mci->mci_out) && errno == EPIPE))
++ ok = true;
+
+- /* get the exit status */
++ /* (always) get the exit status */
+ rcode = endmailer(mci, e, pv);
++ if (!ok)
++ rcode = EX_TEMPFAIL;
+ if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0')
+ {
+ /*
+@@ -4335,13 +4352,13 @@ logdelivery(m, mci, dsn, status, ctladdr
+ ** e -- the envelope.
+ **
+ ** Returns:
+-** none
++** true iff line was written successfully
+ **
+ ** Side Effects:
+ ** outputs some text to fp.
+ */
+
+-void
++bool
+ putfromline(mci, e)
+ register MCI *mci;
+ ENVELOPE *e;
+@@ -4351,7 +4368,7 @@ putfromline(mci, e)
+ char xbuf[MAXLINE];
+
+ if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
+- return;
++ return true;
+
+ mci->mci_flags |= MCIF_INHEADER;
+
+@@ -4392,8 +4409,9 @@ putfromline(mci, e)
+ }
+ }
+ expand(template, buf, sizeof buf, e);
+- putxline(buf, strlen(buf), mci, PXLF_HEADER);
++ return putxline(buf, strlen(buf), mci, PXLF_HEADER);
+ }
++
+ /*
+ ** PUTBODY -- put the body of a message.
+ **
+@@ -4404,7 +4422,7 @@ putfromline(mci, e)
+ ** not be permitted in the resulting message.
+ **
+ ** Returns:
+-** none.
++** true iff message was written successfully
+ **
+ ** Side Effects:
+ ** The message is written onto fp.
+@@ -4415,13 +4433,15 @@ putfromline(mci, e)
+ #define OS_CR 1 /* read a carriage return */
+ #define OS_INLINE 2 /* putting rest of line */
+
+-void
++bool
+ putbody(mci, e, separator)
+ register MCI *mci;
+ register ENVELOPE *e;
+ char *separator;
+ {
+ bool dead = false;
++ bool ioerr = false;
++ int save_errno;
+ char buf[MAXLINE];
+ #if MIME8TO7
+ char *boundaries[MAXMIMENESTING + 1];
+@@ -4451,10 +4471,12 @@ putbody(mci, e, separator)
+ {
+ if (bitset(MCIF_INHEADER, mci->mci_flags))
+ {
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+ }
+- putline("<<< No Message Collected >>>", mci);
++ if (!putline("<<< No Message Collected >>>", mci))
++ goto writeerr;
+ goto endofmessage;
+ }
+
+@@ -4483,26 +4505,31 @@ putbody(mci, e, separator)
+ */
+
+ /* make sure it looks like a MIME message */
+- if (hvalue("MIME-Version", e->e_header) == NULL)
+- putline("MIME-Version: 1.0", mci);
++ if (hvalue("MIME-Version", e->e_header) == NULL &&
++ !putline("MIME-Version: 1.0", mci))
++ goto writeerr;
+
+ if (hvalue("Content-Type", e->e_header) == NULL)
+ {
+ (void) sm_snprintf(buf, sizeof buf,
+ "Content-Type: text/plain; charset=%s",
+ defcharset(e));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /* now do the hard work */
+ boundaries[0] = NULL;
+ mci->mci_flags |= MCIF_INHEADER;
+- (void) mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER);
++ if (mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER) ==
++ SM_IO_EOF)
++ goto writeerr;
+ }
+ # if MIME7TO8
+ else if (bitset(MCIF_CVT7TO8, mci->mci_flags))
+ {
+- (void) mime7to8(mci, e->e_header, e);
++ if (!mime7to8(mci, e->e_header, e))
++ goto writeerr;
+ }
+ # endif /* MIME7TO8 */
+ else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0)
+@@ -4524,8 +4551,9 @@ putbody(mci, e, separator)
+ if (bitset(EF_DONT_MIME, e->e_flags))
+ SuprErrs = true;
+
+- (void) mime8to7(mci, e->e_header, e, boundaries,
+- M87F_OUTER|M87F_NO8TO7);
++ if (mime8to7(mci, e->e_header, e, boundaries,
++ M87F_OUTER|M87F_NO8TO7) == SM_IO_EOF)
++ goto writeerr;
+
+ /* restore SuprErrs */
+ SuprErrs = oldsuprerrs;
+@@ -4545,7 +4573,8 @@ putbody(mci, e, separator)
+
+ if (bitset(MCIF_INHEADER, mci->mci_flags))
+ {
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+ }
+
+@@ -4636,11 +4665,6 @@ putbody(mci, e, separator)
+ dead = true;
+ continue;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ pos++;
+ }
+ for (xp = buf; xp < bp; xp++)
+@@ -4653,11 +4677,6 @@ putbody(mci, e, separator)
+ dead = true;
+ break;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ }
+ if (dead)
+ continue;
+@@ -4668,11 +4687,6 @@ putbody(mci, e, separator)
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
+ break;
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ pos = 0;
+ }
+ else
+@@ -4702,11 +4716,6 @@ putbody(mci, e, separator)
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
+ continue;
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+
+ if (TrafficLogFile != NULL)
+ {
+@@ -4763,11 +4772,6 @@ putch:
+ dead = true;
+ continue;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ pos++;
+ continue;
+ }
+@@ -4783,11 +4787,6 @@ putch:
+ dead = true;
+ continue;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+
+ if (TrafficLogFile != NULL)
+ {
+@@ -4811,11 +4810,6 @@ putch:
+ mci->mci_mailer->m_eol)
+ == SM_IO_EOF)
+ continue;
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ pos = 0;
+ ostate = OS_HEAD;
+ }
+@@ -4833,11 +4827,6 @@ putch:
+ dead = true;
+ continue;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ pos++;
+ ostate = OS_INLINE;
+ }
+@@ -4864,11 +4853,6 @@ putch:
+ dead = true;
+ break;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ }
+ pos += bp - buf;
+ }
+@@ -4878,11 +4862,9 @@ putch:
+ (void) sm_io_fputs(TrafficLogFile,
+ SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol);
+- (void) sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
+- mci->mci_mailer->m_eol);
+-
+- /* record progress for DATA timeout */
+- DataProgress = true;
++ if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
++ mci->mci_mailer->m_eol) == SM_IO_EOF)
++ goto writeerr;
+ }
+ }
+
+@@ -4892,6 +4874,7 @@ putch:
+ qid_printqueue(e->e_dfqgrp, e->e_dfqdir),
+ DATAFL_LETTER, e->e_id);
+ ExitStat = EX_IOERR;
++ ioerr = true;
+ }
+
+ endofmessage:
+@@ -4906,23 +4889,35 @@ endofmessage:
+ ** offset to match.
+ */
+
++ save_errno = errno;
+ if (e->e_dfp != NULL)
+ (void) bfrewind(e->e_dfp);
+
+ /* some mailers want extra blank line at end of message */
+ if (!dead && bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
+ buf[0] != '\0' && buf[0] != '\n')
+- putline("", mci);
++ {
++ if (!putline("", mci))
++ goto writeerr;
++ }
+
+- (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
+- if (sm_io_error(mci->mci_out) && errno != EPIPE)
++ if (!dead &&
++ (sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF ||
++ (sm_io_error(mci->mci_out) && errno != EPIPE)))
+ {
++ save_errno = errno;
+ syserr("putbody: write error");
+ ExitStat = EX_IOERR;
++ ioerr = true;
+ }
+
+- errno = 0;
++ errno = save_errno;
++ return !dead && !ioerr;
++
++ writeerr:
++ return false;
+ }
++
+ /*
+ ** MAILFILE -- Send a message to a file.
+ **
+@@ -5447,14 +5442,14 @@ mailfile(filename, mailer, ctladdr, sffl
+ }
+ #endif /* MIME7TO8 */
+
+- putfromline(&mcibuf, e);
+- (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
+- (*e->e_putbody)(&mcibuf, e, NULL);
+- putline("\n", &mcibuf);
+- if (sm_io_flush(f, SM_TIME_DEFAULT) != 0 ||
++ if (!putfromline(&mcibuf, e) ||
++ !(*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER) ||
++ !(*e->e_putbody)(&mcibuf, e, NULL) ||
++ !putline("\n", &mcibuf) ||
++ (sm_io_flush(f, SM_TIME_DEFAULT) != 0 ||
+ (SuperSafe != SAFE_NO &&
+ fsync(sm_io_getinfo(f, SM_IO_WHAT_FD, NULL)) < 0) ||
+- sm_io_error(f))
++ sm_io_error(f)))
+ {
+ setstat(EX_IOERR);
+ #if !NOFTRUNCATE
+@@ -6011,66 +6006,19 @@ ssl_retry:
+ if ((result = SSL_connect(clt_ssl)) <= 0)
+ {
+ int i;
+- bool timedout;
+- time_t left;
+- time_t now = curtime();
+- struct timeval tv;
+-
+- /* what to do in this case? */
+- i = SSL_get_error(clt_ssl, result);
++ int ssl_err;
+
+- /*
+- ** For SSL_ERROR_WANT_{READ,WRITE}:
+- ** There is not a complete SSL record available yet
+- ** or there is only a partial SSL record removed from
+- ** the network (socket) buffer into the SSL buffer.
+- ** The SSL_connect will only succeed when a full
+- ** SSL record is available (assuming a "real" error
+- ** doesn't happen). To handle when a "real" error
+- ** does happen the select is set for exceptions too.
+- ** The connection may be re-negotiated during this time
+- ** so both read and write "want errors" need to be handled.
+- ** A select() exception loops back so that a proper SSL
+- ** error message can be gotten.
+- */
++ ssl_err = SSL_get_error(clt_ssl, result);
++ i = tls_retry(clt_ssl, rfd, wfd, tlsstart,
++ TimeOuts.to_starttls, ssl_err, "client");
++ if (i > 0)
++ goto ssl_retry;
+
+- left = TimeOuts.to_starttls - (now - tlsstart);
+- timedout = left <= 0;
+- if (!timedout)
+- {
+- tv.tv_sec = left;
+- tv.tv_usec = 0;
+- }
+-
+- if (!timedout && i == SSL_ERROR_WANT_READ)
+- {
+- fd_set ssl_maskr, ssl_maskx;
+-
+- FD_ZERO(&ssl_maskr);
+- FD_SET(rfd, &ssl_maskr);
+- FD_ZERO(&ssl_maskx);
+- FD_SET(rfd, &ssl_maskx);
+- if (select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx, &tv)
+- > 0)
+- goto ssl_retry;
+- }
+- if (!timedout && i == SSL_ERROR_WANT_WRITE)
+- {
+- fd_set ssl_maskw, ssl_maskx;
+-
+- FD_ZERO(&ssl_maskw);
+- FD_SET(wfd, &ssl_maskw);
+- FD_ZERO(&ssl_maskx);
+- FD_SET(rfd, &ssl_maskx);
+- if (select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx, &tv)
+- > 0)
+- goto ssl_retry;
+- }
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_ERR, e->e_id,
+- "STARTTLS=client, error: connect failed=%d, SSL_error=%d, timedout=%d",
+- result, i, (int) timedout);
++ "STARTTLS=client, error: connect failed=%d, SSL_error=%d, errno=%d",
++ result, i, errno);
+ if (LogLevel > 8)
+ tlslogerr("client");
+ }
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/headers.c sendmail-8.12.3/sendmail/headers.c
+--- sendmail-8.12.3.orig/sendmail/headers.c 2006-03-22 22:27:15.000000000 +0100
++++ sendmail-8.12.3/sendmail/headers.c 2006-03-22 22:59:58.000000000 +0100
+@@ -17,7 +17,7 @@ SM_RCSID("@(#)$Id: headers.c,v 8.266 200
+
+ static size_t fix_mime_header __P((char *));
+ static int priencode __P((char *));
+-static void put_vanilla_header __P((HDR *, char *, MCI *));
++static bool put_vanilla_header __P((HDR *, char *, MCI *));
+
+ /*
+ ** SETUPHEADERS -- initialize headers in symbol table
+@@ -849,7 +849,6 @@ logsender(e, msgid)
+ char *name;
+ register char *sbp;
+ register char *p;
+- int l;
+ char hbuf[MAXNAME + 1];
+ char sbuf[MAXLINE + 1];
+ char mbuf[MAXNAME + 1];
+@@ -858,6 +857,8 @@ logsender(e, msgid)
+ /* XXX do we still need this? sm_syslog() replaces control chars */
+ if (msgid != NULL)
+ {
++ size_t l;
++
+ l = strlen(msgid);
+ if (l > sizeof mbuf - 1)
+ l = sizeof mbuf - 1;
+@@ -1401,13 +1402,13 @@ crackaddr(addr, e)
+ ** flags -- MIME conversion flags.
+ **
+ ** Returns:
+-** none.
++** success
+ **
+ ** Side Effects:
+ ** none.
+ */
+
+-void
++bool
+ putheader(mci, hdr, e, flags)
+ register MCI *mci;
+ HDR *hdr;
+@@ -1527,7 +1528,8 @@ putheader(mci, hdr, e, flags)
+ {
+ if (tTd(34, 11))
+ sm_dprintf("\n");
+- put_vanilla_header(h, p, mci);
++ if (!put_vanilla_header(h, p, mci))
++ goto writeerr;
+ continue;
+ }
+
+@@ -1586,7 +1588,8 @@ putheader(mci, hdr, e, flags)
+ /* no other recipient headers: truncate value */
+ (void) sm_strlcpyn(obuf, sizeof obuf, 2,
+ h->h_field, ":");
+- putline(obuf, mci);
++ if (!putline(obuf, mci))
++ goto writeerr;
+ }
+ continue;
+ }
+@@ -1605,7 +1608,8 @@ putheader(mci, hdr, e, flags)
+ }
+ else
+ {
+- put_vanilla_header(h, p, mci);
++ if (!put_vanilla_header(h, p, mci))
++ goto writeerr;
+ }
+ }
+
+@@ -1622,18 +1626,25 @@ putheader(mci, hdr, e, flags)
+ !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
+ hvalue("MIME-Version", e->e_header) == NULL)
+ {
+- putline("MIME-Version: 1.0", mci);
++ if (!putline("MIME-Version: 1.0", mci))
++ goto writeerr;
+ if (hvalue("Content-Type", e->e_header) == NULL)
+ {
+ (void) sm_snprintf(obuf, sizeof obuf,
+ "Content-Type: text/plain; charset=%s",
+ defcharset(e));
+- putline(obuf, mci);
++ if (!putline(obuf, mci))
++ goto writeerr;
+ }
+- if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
+- putline("Content-Transfer-Encoding: 8bit", mci);
++ if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
++ && !putline("Content-Transfer-Encoding: 8bit", mci))
++ goto writeerr;
+ }
+ #endif /* MIME8TO7 */
++ return true;
++
++ writeerr:
++ return false;
+ }
+ /*
+ ** PUT_VANILLA_HEADER -- output a fairly ordinary header
+@@ -1644,10 +1655,10 @@ putheader(mci, hdr, e, flags)
+ ** mci -- the connection info for output
+ **
+ ** Returns:
+-** none.
++** success
+ */
+
+-static void
++static bool
+ put_vanilla_header(h, v, mci)
+ HDR *h;
+ char *v;
+@@ -1672,7 +1683,8 @@ put_vanilla_header(h, v, mci)
+ l = SPACELEFT(obuf, obp) - 1;
+
+ (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
+- putxline(obuf, strlen(obuf), mci, putflags);
++ if (!putxline(obuf, strlen(obuf), mci, putflags))
++ goto writeerr;
+ v += l + 1;
+ obp = obuf;
+ if (*v != ' ' && *v != '\t')
+@@ -1680,7 +1692,10 @@ put_vanilla_header(h, v, mci)
+ }
+ (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
+ (int) (SPACELEFT(obuf, obp) - 1), v);
+- putxline(obuf, strlen(obuf), mci, putflags);
++ return putxline(obuf, strlen(obuf), mci, putflags);
++
++ writeerr:
++ return false;
+ }
+ /*
+ ** COMMAIZE -- output a header field, making a comma-translated list.
+@@ -1693,13 +1708,13 @@ put_vanilla_header(h, v, mci)
+ ** e -- the envelope containing the message.
+ **
+ ** Returns:
+-** none.
++** success
+ **
+ ** Side Effects:
+ ** outputs "p" to file "fp".
+ */
+
+-void
++bool
+ commaize(h, p, oldstyle, mci, e)
+ register HDR *h;
+ register char *p;
+@@ -1817,13 +1832,6 @@ commaize(h, p, oldstyle, mci, e)
+ }
+ name = denlstring(name, false, true);
+
+- /*
+- ** record data progress so DNS timeouts
+- ** don't cause DATA timeouts
+- */
+-
+- DataProgress = true;
+-
+ /* output the name with nice formatting */
+ opos += strlen(name);
+ if (!firstone)
+@@ -1831,7 +1839,8 @@ commaize(h, p, oldstyle, mci, e)
+ if (opos > omax && !firstone)
+ {
+ (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
+- putxline(obuf, strlen(obuf), mci, putflags);
++ if (!putxline(obuf, strlen(obuf), mci, putflags))
++ goto writeerr;
+ obp = obuf;
+ (void) sm_strlcpy(obp, " ", sizeof obp);
+ opos = strlen(obp);
+@@ -1849,8 +1858,14 @@ commaize(h, p, oldstyle, mci, e)
+ firstone = false;
+ *p = savechar;
+ }
+- *obp = '\0';
+- putxline(obuf, strlen(obuf), mci, putflags);
++ if (obp < &obuf[sizeof obuf])
++ *obp = '\0';
++ else
++ obuf[sizeof obuf - 1] = '\0';
++ return putxline(obuf, strlen(obuf), mci, putflags);
++
++ writeerr:
++ return false;
+ }
+ /*
+ ** COPYHEADER -- copy header list
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/mime.c sendmail-8.12.3/sendmail/mime.c
+--- sendmail-8.12.3.orig/sendmail/mime.c 2002-03-13 08:28:05.000000000 +0100
++++ sendmail-8.12.3/sendmail/mime.c 2006-03-22 23:06:09.000000000 +0100
+@@ -81,6 +81,7 @@ static bool MapNLtoCRLF;
+ ** MBT_FINAL -- the final boundary
+ ** MBT_INTERMED -- an intermediate boundary
+ ** MBT_NOTSEP -- an end of file
++** SM_IO_EOF -- I/O error occurred
+ */
+
+ struct args
+@@ -293,7 +294,8 @@ mime8to7(mci, header, e, boundaries, fla
+ mci->mci_flags |= MCIF_INMIME;
+
+ /* skip the early "comment" prologue */
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+ bt = MBT_FINAL;
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+@@ -302,8 +304,9 @@ mime8to7(mci, header, e, boundaries, fla
+ bt = mimeboundary(buf, boundaries);
+ if (bt != MBT_NOTSEP)
+ break;
+- putxline(buf, strlen(buf), mci,
+- PXLF_MAPFROM|PXLF_STRIP8BIT);
++ if (!putxline(buf, strlen(buf), mci,
++ PXLF_MAPFROM|PXLF_STRIP8BIT))
++ goto writeerr;
+ if (tTd(43, 99))
+ sm_dprintf(" ...%s", buf);
+ }
+@@ -314,19 +317,24 @@ mime8to7(mci, header, e, boundaries, fla
+ auto HDR *hdr = NULL;
+
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "--", bbuf);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ if (tTd(43, 35))
+ sm_dprintf(" ...%s\n", buf);
+ collect(e->e_dfp, false, &hdr, e);
+ if (tTd(43, 101))
+ putline("+++after collect", mci);
+- putheader(mci, hdr, e, flags);
++ if (!putheader(mci, hdr, e, flags))
++ goto writeerr;
+ if (tTd(43, 101))
+ putline("+++after putheader", mci);
+ bt = mime8to7(mci, hdr, e, boundaries, flags);
++ if (bt == SM_IO_EOF)
++ goto writeerr;
+ }
+ (void) sm_strlcpyn(buf, sizeof buf, 3, "--", bbuf, "--");
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ if (tTd(43, 35))
+ sm_dprintf(" ...%s\n", buf);
+ boundaries[i] = NULL;
+@@ -339,8 +347,9 @@ mime8to7(mci, header, e, boundaries, fla
+ bt = mimeboundary(buf, boundaries);
+ if (bt != MBT_NOTSEP)
+ break;
+- putxline(buf, strlen(buf), mci,
+- PXLF_MAPFROM|PXLF_STRIP8BIT);
++ if (!putxline(buf, strlen(buf), mci,
++ PXLF_MAPFROM|PXLF_STRIP8BIT))
++ goto writeerr;
+ if (tTd(43, 99))
+ sm_dprintf(" ...%s", buf);
+ }
+@@ -368,17 +377,20 @@ mime8to7(mci, header, e, boundaries, fla
+ {
+ auto HDR *hdr = NULL;
+
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+
+ mci->mci_flags |= MCIF_INMIME;
+ collect(e->e_dfp, false, &hdr, e);
+ if (tTd(43, 101))
+ putline("+++after collect", mci);
+- putheader(mci, hdr, e, flags);
++ if (!putheader(mci, hdr, e, flags))
++ goto writeerr;
+ if (tTd(43, 101))
+ putline("+++after putheader", mci);
+ if (hvalue("MIME-Version", hdr) == NULL)
+- putline("MIME-Version: 1.0", mci);
++ if (!putline("MIME-Version: 1.0", mci))
++ goto writeerr;
+ bt = mime8to7(mci, hdr, e, boundaries, flags);
+ mci->mci_flags &= ~MCIF_INMIME;
+ return bt;
+@@ -474,11 +486,13 @@ mime8to7(mci, header, e, boundaries, fla
+
+ (void) sm_snprintf(buf, sizeof buf,
+ "Content-Transfer-Encoding: %.200s", cte);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ if (tTd(43, 36))
+ sm_dprintf(" ...%s\n", buf);
+ }
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+ != NULL)
+@@ -486,7 +500,8 @@ mime8to7(mci, header, e, boundaries, fla
+ bt = mimeboundary(buf, boundaries);
+ if (bt != MBT_NOTSEP)
+ break;
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ if (sm_io_eof(e->e_dfp))
+ bt = MBT_FINAL;
+@@ -499,12 +514,13 @@ mime8to7(mci, header, e, boundaries, fla
+
+ if (tTd(43, 36))
+ sm_dprintf(" ...Content-Transfer-Encoding: base64\n");
+- putline("Content-Transfer-Encoding: base64", mci);
++ if (!putline("Content-Transfer-Encoding: base64", mci))
++ goto writeerr;
+ (void) sm_snprintf(buf, sizeof buf,
+ "X-MIME-Autoconverted: from 8bit to base64 by %s id %s",
+ MyHostName, e->e_id);
+- putline(buf, mci);
+- putline("", mci);
++ if (!putline(buf, mci) || !putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+ while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) !=
+ SM_IO_EOF)
+@@ -512,7 +528,8 @@ mime8to7(mci, header, e, boundaries, fla
+ if (linelen > 71)
+ {
+ *bp = '\0';
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ linelen = 0;
+ bp = buf;
+ }
+@@ -542,7 +559,8 @@ mime8to7(mci, header, e, boundaries, fla
+ *bp++ = Base64Code[c2 & 0x3f];
+ }
+ *bp = '\0';
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ else
+ {
+@@ -565,12 +583,14 @@ mime8to7(mci, header, e, boundaries, fla
+
+ if (tTd(43, 36))
+ sm_dprintf(" ...Content-Transfer-Encoding: quoted-printable\n");
+- putline("Content-Transfer-Encoding: quoted-printable", mci);
++ if (!putline("Content-Transfer-Encoding: quoted-printable",
++ mci))
++ goto writeerr;
+ (void) sm_snprintf(buf, sizeof buf,
+ "X-MIME-Autoconverted: from 8bit to quoted-printable by %s id %s",
+ MyHostName, e->e_id);
+- putline(buf, mci);
+- putline("", mci);
++ if (!putline(buf, mci) || !putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+ fromstate = 0;
+ c2 = '\n';
+@@ -592,7 +612,8 @@ mime8to7(mci, header, e, boundaries, fla
+ *bp++ = Base16Code['.' & 0x0f];
+ }
+ *bp = '\0';
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ linelen = fromstate = 0;
+ bp = buf;
+ c2 = c1;
+@@ -621,7 +642,8 @@ mime8to7(mci, header, e, boundaries, fla
+ c2 = '\n';
+ *bp++ = '=';
+ *bp = '\0';
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ linelen = fromstate = 0;
+ bp = buf;
+ if (c2 == '.')
+@@ -659,13 +681,17 @@ mime8to7(mci, header, e, boundaries, fla
+ if (linelen > 0 || boundaries[0] != NULL)
+ {
+ *bp = '\0';
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ }
+ if (tTd(43, 3))
+ sm_dprintf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]);
+ return bt;
++
++ writeerr:
++ return SM_IO_EOF;
+ }
+ /*
+ ** MIME_GETCHAR -- get a character for MIME processing
+@@ -948,7 +974,7 @@ static int mime_fromqp __P((unsigned cha
+ ** e -- envelope.
+ **
+ ** Returns:
+-** none.
++** true iff body was written successfully
+ */
+
+ static char index_64[128] =
+@@ -965,7 +991,7 @@ static char index_64[128] =
+
+ # define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+
+-void
++bool
+ mime7to8(mci, header, e)
+ register MCI *mci;
+ HDR *header;
+@@ -998,25 +1024,31 @@ mime7to8(mci, header, e)
+ {
+ (void) sm_snprintf(buf, sizeof buf,
+ "Content-Transfer-Encoding: %s", p);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+ while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf)
+ != NULL)
+- putline(buf, mci);
+- return;
++ {
++ if (!putline(buf, mci))
++ goto writeerr;
++ }
++ return true;
+ }
+ cataddr(pvp, NULL, buf, sizeof buf, '\0');
+ cte = sm_rpool_strdup_x(e->e_rpool, buf);
+
+ mci->mci_flags |= MCIF_INHEADER;
+- putline("Content-Transfer-Encoding: 8bit", mci);
++ if (!putline("Content-Transfer-Encoding: 8bit", mci))
++ goto writeerr;
+ (void) sm_snprintf(buf, sizeof buf,
+ "X-MIME-Autoconverted: from %.200s to 8bit by %s id %s",
+ cte, MyHostName, e->e_id);
+- putline(buf, mci);
+- putline("", mci);
++ if (!putline(buf, mci) || !putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+
+ /*
+@@ -1130,8 +1162,11 @@ again:
+ continue;
+
+ if (fbufp - fbuf > 0)
+- putxline((char *) fbuf, fbufp - fbuf - 1, mci,
+- pxflags);
++ {
++ if (!putxline((char *) fbuf, fbufp - fbuf - 1,
++ mci, pxflags))
++ goto writeerr;
++ }
+ fbufp = fbuf;
+ if (off >= 0 && buf[off] != '\0')
+ {
+@@ -1147,7 +1182,8 @@ again:
+ if (fbufp > fbuf)
+ {
+ *fbufp = '\0';
+- putxline((char *) fbuf, fbufp - fbuf, mci, pxflags);
++ if (!putxline((char *) fbuf, fbufp - fbuf, mci, pxflags))
++ goto writeerr;
+ }
+
+ /*
+@@ -1157,10 +1193,15 @@ again:
+ ** but so is auto-converting MIME in the first place.
+ */
+
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+
+ if (tTd(43, 3))
+ sm_dprintf("\t\t\tmime7to8 => %s to 8bit done\n", cte);
++ return true;
++
++ writeerr:
++ return false;
+ }
+ /*
+ ** The following is based on Borenstein's "codes.c" module, with simplifying
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/parseaddr.c sendmail-8.12.3/sendmail/parseaddr.c
+--- sendmail-8.12.3.orig/sendmail/parseaddr.c 2006-03-22 22:27:15.000000000 +0100
++++ sendmail-8.12.3/sendmail/parseaddr.c 2006-03-22 22:42:45.000000000 +0100
+@@ -1330,7 +1330,7 @@ rewrite(pvp, ruleset, reclevel, e, maxat
+ /* $&x replacement */
+ char *mval = macvalue(rp[1], e);
+ char **xpvp;
+- int trsize = 0;
++ size_t trsize = 0;
+ static size_t pvpb1_size = 0;
+ static char **pvpb1 = NULL;
+ char pvpbuf[PSBUFSIZE];
+@@ -1345,7 +1345,7 @@ rewrite(pvp, ruleset, reclevel, e, maxat
+ /* save the remainder of the input */
+ for (xpvp = pvp; *xpvp != NULL; xpvp++)
+ trsize += sizeof *xpvp;
+- if ((size_t) trsize > pvpb1_size)
++ if (trsize > pvpb1_size)
+ {
+ if (pvpb1 != NULL)
+ sm_free(pvpb1);
+@@ -1400,7 +1400,7 @@ rewrite(pvp, ruleset, reclevel, e, maxat
+ {
+ char **hbrvp;
+ char **xpvp;
+- int trsize;
++ size_t trsize;
+ char *replac;
+ int endtoken;
+ STAB *map;
+@@ -1489,7 +1489,7 @@ rewrite(pvp, ruleset, reclevel, e, maxat
+ *++arg_rvp = NULL;
+
+ /* save the remainder of the input string */
+- trsize = (int) (avp - rvp + 1) * sizeof *rvp;
++ trsize = (avp - rvp + 1) * sizeof *rvp;
+ memmove((char *) pvpb1, (char *) rvp, trsize);
+
+ /* look it up */
+@@ -2924,7 +2924,7 @@ rscheck(rwset, p1, p2, e, rmcomm, cnt, l
+ char *logid;
+ {
+ char *volatile buf;
+- int bufsize;
++ size_t bufsize;
+ int saveexitstat;
+ int volatile rstat = EX_OK;
+ char **pvp;
+@@ -3138,7 +3138,7 @@ rscap(rwset, p1, p2, e, pvp, pvpbuf, siz
+ int size;
+ {
+ char *volatile buf;
+- int bufsize;
++ size_t bufsize;
+ int volatile rstat = EX_OK;
+ int rsno;
+ bool saveQuickAbort = QuickAbort;
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/savemail.c sendmail-8.12.3/sendmail/savemail.c
+--- sendmail-8.12.3.orig/sendmail/savemail.c 2001-12-28 23:32:19.000000000 +0100
++++ sendmail-8.12.3/sendmail/savemail.c 2006-03-22 22:42:45.000000000 +0100
+@@ -15,7 +15,7 @@
+
+ SM_RCSID("@(#)$Id: savemail.c,v 8.297 2001/12/28 22:32:19 ca Exp $")
+
+-static void errbody __P((MCI *, ENVELOPE *, char *));
++static bool errbody __P((MCI *, ENVELOPE *, char *));
+ static bool pruneroute __P((char *));
+
+ /*
+@@ -426,12 +426,13 @@ savemail(e, sendbody)
+ p = macvalue('g', e);
+ macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
+
+- putfromline(&mcibuf, e);
+- (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
+- (*e->e_putbody)(&mcibuf, e, NULL);
+- putline("\n", &mcibuf); /* XXX EOL from FileMailer? */
+- (void) sm_io_flush(fp, SM_TIME_DEFAULT);
+- if (sm_io_error(fp) ||
++ if (!putfromline(&mcibuf, e) ||
++ !(*e->e_puthdr)(&mcibuf, e->e_header, e,
++ M87F_OUTER) ||
++ !(*e->e_putbody)(&mcibuf, e, NULL) ||
++ !putline("\n", &mcibuf) ||
++ sm_io_flush(fp, SM_TIME_DEFAULT) == SM_IO_EOF ||
++ sm_io_error(fp) ||
+ sm_io_close(fp, SM_TIME_DEFAULT) < 0)
+ state = ESM_PANIC;
+ else
+@@ -744,14 +745,14 @@ returntosender(msg, returnq, flags, e)
+ ** separator -- any possible MIME separator (unused).
+ **
+ ** Returns:
+-** none
++** success
+ **
+ ** Side Effects:
+ ** Outputs the body of an error message.
+ */
+
+ /* ARGSUSED2 */
+-static void
++static bool
+ errbody(mci, e, separator)
+ register MCI *mci;
+ register ENVELOPE *e;
+@@ -769,14 +770,16 @@ errbody(mci, e, separator)
+
+ if (bitset(MCIF_INHEADER, mci->mci_flags))
+ {
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+ mci->mci_flags &= ~MCIF_INHEADER;
+ }
+ if (e->e_parent == NULL)
+ {
+ syserr("errbody: null parent");
+- putline(" ----- Original message lost -----\n", mci);
+- return;
++ if (!putline(" ----- Original message lost -----\n", mci))
++ goto writeerr;
++ return true;
+ }
+
+ /*
+@@ -785,11 +788,12 @@ errbody(mci, e, separator)
+
+ if (e->e_msgboundary != NULL)
+ {
+- putline("This is a MIME-encapsulated message", mci);
+- putline("", mci);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "--", e->e_msgboundary);
+- putline(buf, mci);
+- putline("", mci);
++ if (!putline("This is a MIME-encapsulated message", mci) ||
++ !putline("", mci) ||
++ !putline(buf, mci) ||
++ !putline("", mci))
++ goto writeerr;
+ }
+
+ /*
+@@ -811,31 +815,36 @@ errbody(mci, e, separator)
+ if (!pm_notify && q == NULL &&
+ !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
+ {
+- putline(" **********************************************",
+- mci);
+- putline(" ** THIS IS A WARNING MESSAGE ONLY **",
+- mci);
+- putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **",
+- mci);
+- putline(" **********************************************",
+- mci);
+- putline("", mci);
++ if (!putline(" **********************************************",
++ mci) ||
++ !putline(" ** THIS IS A WARNING MESSAGE ONLY **",
++ mci) ||
++ !putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **",
++ mci) ||
++ !putline(" **********************************************",
++ mci) ||
++ !putline("", mci))
++ goto writeerr;
+ }
+ (void) sm_snprintf(buf, sizeof buf,
+ "The original message was received at %s",
+ arpadate(ctime(&e->e_parent->e_ctime)));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ expand("from \201_", buf, sizeof buf, e->e_parent);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+
+ /* include id in postmaster copies */
+ if (pm_notify && e->e_parent->e_id != NULL)
+ {
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "with id ",
+ e->e_parent->e_id);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+
+ /*
+ ** Output error message header (if specified and available).
+@@ -861,17 +870,19 @@ errbody(mci, e, separator)
+ {
+ translate_dollars(buf);
+ expand(buf, buf, sizeof buf, e);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ (void) sm_io_close(xfile, SM_TIME_DEFAULT);
+- putline("\n", mci);
++ if (!putline("\n", mci))
++ goto writeerr;
+ }
+ }
+ else
+ {
+ expand(ErrMsgFile, buf, sizeof buf, e);
+- putline(buf, mci);
+- putline("", mci);
++ if (!putline(buf, mci) || !putline("", mci))
++ goto writeerr;
+ }
+ }
+
+@@ -889,21 +900,24 @@ errbody(mci, e, separator)
+
+ if (printheader)
+ {
+- putline(" ----- The following addresses had permanent fatal errors -----",
+- mci);
++ if (!putline(" ----- The following addresses had permanent fatal errors -----",
++ mci))
++ goto writeerr;
+ printheader = false;
+ }
+
+ (void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
+ sizeof buf);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ if (q->q_rstatus != NULL)
+ {
+ (void) sm_snprintf(buf, sizeof buf,
+ " (reason: %s)",
+ shortenstring(exitstat(q->q_rstatus),
+ MAXSHORTSTR));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ if (q->q_alias != NULL)
+ {
+@@ -911,11 +925,12 @@ errbody(mci, e, separator)
+ " (expanded from: %s)",
+ shortenstring(q->q_alias->q_paddr,
+ MAXSHORTSTR));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ }
+- if (!printheader)
+- putline("", mci);
++ if (!printheader && !putline("", mci))
++ goto writeerr;
+
+ /* transient non-fatal errors */
+ printheader = true;
+@@ -929,25 +944,28 @@ errbody(mci, e, separator)
+
+ if (printheader)
+ {
+- putline(" ----- The following addresses had transient non-fatal errors -----",
+- mci);
++ if (!putline(" ----- The following addresses had transient non-fatal errors -----",
++ mci))
++ goto writeerr;
+ printheader = false;
+ }
+
+ (void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
+ sizeof buf);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ if (q->q_alias != NULL)
+ {
+ (void) sm_snprintf(buf, sizeof buf,
+ " (expanded from: %s)",
+ shortenstring(q->q_alias->q_paddr,
+ MAXSHORTSTR));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ }
+- if (!printheader)
+- putline("", mci);
++ if (!printheader && !putline("", mci))
++ goto writeerr;
+
+ /* successful delivery notifications */
+ printheader = true;
+@@ -980,25 +998,28 @@ errbody(mci, e, separator)
+
+ if (printheader)
+ {
+- putline(" ----- The following addresses had successful delivery notifications -----",
+- mci);
++ if (!putline(" ----- The following addresses had successful delivery notifications -----",
++ mci))
++ goto writeerr;
+ printheader = false;
+ }
+
+ (void) sm_snprintf(buf, sizeof buf, "%s (%s)",
+ shortenstring(q->q_paddr, MAXSHORTSTR), p);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ if (q->q_alias != NULL)
+ {
+ (void) sm_snprintf(buf, sizeof buf,
+ " (expanded from: %s)",
+ shortenstring(q->q_alias->q_paddr,
+ MAXSHORTSTR));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ }
+- if (!printheader)
+- putline("", mci);
++ if (!printheader && !putline("", mci))
++ goto writeerr;
+
+ /*
+ ** Output transcript of errors
+@@ -1007,8 +1028,9 @@ errbody(mci, e, separator)
+ (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
+ if (e->e_parent->e_xfp == NULL)
+ {
+- putline(" ----- Transcript of session is unavailable -----\n",
+- mci);
++ if (!putline(" ----- Transcript of session is unavailable -----\n",
++ mci))
++ goto writeerr;
+ }
+ else
+ {
+@@ -1019,11 +1041,12 @@ errbody(mci, e, separator)
+ while (sm_io_fgets(e->e_parent->e_xfp, SM_TIME_DEFAULT, buf,
+ sizeof buf) != NULL)
+ {
+- if (printheader)
+- putline(" ----- Transcript of session follows -----\n",
+- mci);
++ if (printheader && !putline(" ----- Transcript of session follows -----\n",
++ mci))
++ goto writeerr;
+ printheader = false;
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ }
+ errno = 0;
+@@ -1035,11 +1058,12 @@ errbody(mci, e, separator)
+
+ if (e->e_msgboundary != NULL)
+ {
+- putline("", mci);
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "--", e->e_msgboundary);
+- putline(buf, mci);
+- putline("Content-Type: message/delivery-status", mci);
+- putline("", mci);
++ if (!putline("", mci) ||
++ !putline(buf, mci) ||
++ !putline("Content-Type: message/delivery-status", mci) ||
++ !putline("", mci))
++ goto writeerr;
+
+ /*
+ ** Output per-message information.
+@@ -1051,13 +1075,15 @@ errbody(mci, e, separator)
+ (void) sm_snprintf(buf, sizeof buf,
+ "Original-Envelope-Id: %.800s",
+ xuntextify(e->e_parent->e_envid));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /* Reporting-MTA: is us (required) */
+ (void) sm_snprintf(buf, sizeof buf,
+ "Reporting-MTA: dns; %.800s", MyHostName);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+
+ /* DSN-Gateway: not relevant since we are not translating */
+
+@@ -1071,13 +1097,15 @@ errbody(mci, e, separator)
+ (void) sm_snprintf(buf, sizeof buf,
+ "Received-From-MTA: %s; %.800s",
+ p, RealHostName);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /* Arrival-Date: -- when it arrived here */
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Arrival-Date: ",
+ arpadate(ctime(&e->e_parent->e_ctime)));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+
+ /* Deliver-By-Date: -- when it should have been delivered */
+ if (IS_DLVR_BY(e->e_parent))
+@@ -1088,7 +1116,8 @@ errbody(mci, e, separator)
+ (void) sm_strlcpyn(buf, sizeof buf, 2,
+ "Deliver-By-Date: ",
+ arpadate(ctime(&dbyd)));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /*
+@@ -1131,7 +1160,8 @@ errbody(mci, e, separator)
+ else
+ continue;
+
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+
+ /* Original-Recipient: -- passed from on high */
+ if (q->q_orcpt != NULL)
+@@ -1139,7 +1169,8 @@ errbody(mci, e, separator)
+ (void) sm_snprintf(buf, sizeof buf,
+ "Original-Recipient: %.800s",
+ q->q_orcpt);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /* Figure out actual recipient */
+@@ -1188,7 +1219,8 @@ errbody(mci, e, separator)
+ (void) sm_snprintf(buf, sizeof buf,
+ "Final-Recipient: %s",
+ q->q_finalrcpt);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /* X-Actual-Recipient: -- the real problem address */
+@@ -1199,13 +1231,15 @@ errbody(mci, e, separator)
+ (void) sm_snprintf(buf, sizeof buf,
+ "X-Actual-Recipient: %s",
+ actual);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /* Action: -- what happened? */
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Action: ",
+ action);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+
+ /* Status: -- what _really_ happened? */
+ if (q->q_status != NULL)
+@@ -1217,7 +1251,8 @@ errbody(mci, e, separator)
+ else
+ p = "2.0.0";
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Status: ", p);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+
+ /* Remote-MTA: -- who was I talking to? */
+ if (q->q_statmta != NULL)
+@@ -1231,7 +1266,8 @@ errbody(mci, e, separator)
+ p = &buf[strlen(buf) - 1];
+ if (*p == '.')
+ *p = '\0';
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /* Diagnostic-Code: -- actual result from other end */
+@@ -1243,7 +1279,8 @@ errbody(mci, e, separator)
+ (void) sm_snprintf(buf, sizeof buf,
+ "Diagnostic-Code: %s; %.800s",
+ p, q->q_rstatus);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+
+ /* Last-Attempt-Date: -- fine granularity */
+@@ -1252,7 +1289,8 @@ errbody(mci, e, separator)
+ (void) sm_strlcpyn(buf, sizeof buf, 2,
+ "Last-Attempt-Date: ",
+ arpadate(ctime(&q->q_statdate)));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+
+ /* Will-Retry-Until: -- for delayed messages only */
+ if (QS_IS_QUEUEUP(q->q_state))
+@@ -1264,7 +1302,8 @@ errbody(mci, e, separator)
+ (void) sm_strlcpyn(buf, sizeof buf, 2,
+ "Will-Retry-Until: ",
+ arpadate(ctime(&xdate)));
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ }
+ }
+@@ -1274,7 +1313,8 @@ errbody(mci, e, separator)
+ ** Output text of original message
+ */
+
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+ if (bitset(EF_HAS_DF, e->e_parent->e_flags))
+ {
+ sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
+@@ -1282,21 +1322,27 @@ errbody(mci, e, separator)
+
+ if (e->e_msgboundary == NULL)
+ {
+- if (sendbody)
+- putline(" ----- Original message follows -----\n", mci);
+- else
+- putline(" ----- Message header follows -----\n", mci);
++ if (!putline(
++ sendbody
++ ? " ----- Original message follows -----\n"
++ : " ----- Message header follows -----\n",
++ mci))
++ {
++ goto writeerr;
++ }
+ }
+ else
+ {
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "--",
+ e->e_msgboundary);
+
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ (void) sm_strlcpyn(buf, sizeof buf, 2, "Content-Type: ",
+ sendbody ? "message/rfc822"
+ : "text/rfc822-headers");
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+
+ p = hvalue("Content-Transfer-Encoding",
+ e->e_parent->e_header);
+@@ -1310,43 +1356,62 @@ errbody(mci, e, separator)
+ (void) sm_snprintf(buf, sizeof buf,
+ "Content-Transfer-Encoding: %s",
+ p);
+- putline(buf, mci);
++ if (!putline(buf, mci))
++ goto writeerr;
+ }
+ }
+- putline("", mci);
++ if (!putline("", mci))
++ goto writeerr;
+ save_errno = errno;
+- putheader(mci, e->e_parent->e_header, e->e_parent, M87F_OUTER);
++ if (!putheader(mci, e->e_parent->e_header, e->e_parent,
++ M87F_OUTER))
++ goto writeerr;
+ errno = save_errno;
+ if (sendbody)
+- putbody(mci, e->e_parent, e->e_msgboundary);
++ {
++ if (!putbody(mci, e->e_parent, e->e_msgboundary))
++ goto writeerr;
++ }
+ else if (e->e_msgboundary == NULL)
+ {
+- putline("", mci);
+- putline(" ----- Message body suppressed -----", mci);
++ if (!putline("", mci) ||
++ !putline(" ----- Message body suppressed -----",
++ mci))
++ {
++ goto writeerr;
++ }
+ }
+ }
+ else if (e->e_msgboundary == NULL)
+ {
+- putline(" ----- No message was collected -----\n", mci);
++ if (!putline(" ----- No message was collected -----\n", mci))
++ goto writeerr;
+ }
+
+ if (e->e_msgboundary != NULL)
+ {
+- putline("", mci);
+ (void) sm_strlcpyn(buf, sizeof buf, 3, "--", e->e_msgboundary,
+ "--");
+- putline(buf, mci);
++ if (!putline("", mci) || !putline(buf, mci))
++ goto writeerr;
+ }
+- putline("", mci);
+- (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
++ if (!putline("", mci) ||
++ sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF)
++ goto writeerr;
+
+ /*
+ ** Cleanup and exit
+ */
+
+ if (errno != 0)
++ {
++ writeerr:
+ syserr("errbody: I/O error");
++ return false;
++ }
++ return true;
+ }
++
+ /*
+ ** SMTPTODSN -- convert SMTP to DSN status code
+ **
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/sendmail.h sendmail-8.12.3/sendmail/sendmail.h
+--- sendmail-8.12.3.orig/sendmail/sendmail.h 2006-03-22 22:27:15.000000000 +0100
++++ sendmail-8.12.3/sendmail/sendmail.h 2006-03-22 22:42:45.000000000 +0100
+@@ -780,12 +780,12 @@ extern struct hdrinfo HdrInfo[];
+ /* functions */
+ extern void addheader __P((char *, char *, int, ENVELOPE *));
+ extern unsigned long chompheader __P((char *, int, HDR **, ENVELOPE *));
+-extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *));
++extern bool commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *));
+ extern HDR *copyheader __P((HDR *, SM_RPOOL_T *));
+ extern void eatheader __P((ENVELOPE *, bool, bool));
+ extern char *hvalue __P((char *, HDR *));
+ extern bool isheader __P((char *));
+-extern void putfromline __P((MCI *, ENVELOPE *));
++extern bool putfromline __P((MCI *, ENVELOPE *));
+ extern void setupheaders __P((void));
+
+ /*
+@@ -840,9 +840,9 @@ struct envelope
+ short e_sendmode; /* message send mode */
+ short e_errormode; /* error return mode */
+ short e_timeoutclass; /* message timeout class */
+- void (*e_puthdr)__P((MCI *, HDR *, ENVELOPE *, int));
++ bool (*e_puthdr)__P((MCI *, HDR *, ENVELOPE *, int));
+ /* function to put header of message */
+- void (*e_putbody)__P((MCI *, ENVELOPE *, char *));
++ bool (*e_putbody)__P((MCI *, ENVELOPE *, char *));
+ /* function to put body of message */
+ ENVELOPE *e_parent; /* the message this one encloses */
+ ENVELOPE *e_sibling; /* the next envelope of interest */
+@@ -940,8 +940,8 @@ extern void clearenvelope __P((ENVELOPE
+ extern void dropenvelope __P((ENVELOPE *, bool, bool));
+ extern ENVELOPE *newenvelope __P((ENVELOPE *, ENVELOPE *, SM_RPOOL_T *));
+ extern void printenvflags __P((ENVELOPE *));
+-extern void putbody __P((MCI *, ENVELOPE *, char *));
+-extern void putheader __P((MCI *, HDR *, ENVELOPE *, int));
++extern bool putbody __P((MCI *, ENVELOPE *, char *));
++extern bool putheader __P((MCI *, HDR *, ENVELOPE *, int));
+
+ /*
+ ** Message priority classes.
+@@ -1558,7 +1558,7 @@ EXTERN unsigned long PrivacyFlags; /* pr
+ #define M87F_NO8TO7 0x0004 /* don't do 8->7 bit conversions */
+
+ /* functions */
+-extern void mime7to8 __P((MCI *, HDR *, ENVELOPE *));
++extern bool mime7to8 __P((MCI *, HDR *, ENVELOPE *));
+ extern int mime8to7 __P((MCI *, HDR *, ENVELOPE *, char **, int));
+
+ /*
+@@ -2087,7 +2087,6 @@ EXTERN bool ColonOkInAddr; /* single col
+ #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
+ EXTERN bool ConfigFileRead; /* configuration file has been read */
+ #endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
+-EXTERN bool volatile DataProgress; /* have we sent anything since last check */
+ EXTERN bool DisConnected; /* running with OutChannel redirect to transcript file */
+ EXTERN bool DontExpandCnames; /* do not $[...$] expand CNAMEs */
+ EXTERN bool DontInitGroups; /* avoid initgroups() because of NIS cost */
+@@ -2444,8 +2443,8 @@ extern void printopenfds __P((bool));
+ extern void printqueue __P((void));
+ extern void printrules __P((void));
+ extern pid_t prog_open __P((char **, int *, ENVELOPE *));
+-extern void putline __P((char *, MCI *));
+-extern void putxline __P((char *, size_t, MCI *, int));
++extern bool putline __P((char *, MCI *));
++extern bool putxline __P((char *, size_t, MCI *, int));
+ extern void queueup_macros __P((int, SM_FILE_T *, ENVELOPE *));
+ extern void readcf __P((char *, bool, ENVELOPE *));
+ extern SIGFUNC_DECL reapchild __P((int));
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/sfsasl.c sendmail-8.12.3/sendmail/sfsasl.c
+--- sendmail-8.12.3.orig/sendmail/sfsasl.c 2002-02-22 05:41:28.000000000 +0100
++++ sendmail-8.12.3/sendmail/sfsasl.c 2006-03-22 23:53:19.000000000 +0100
+@@ -482,6 +482,125 @@ tls_close(fp)
+ # define MAX_TLS_IOS 4
+
+ /*
++** TLS_RETRY -- check whether a failed SSL operation can be retried
++**
++** Parameters:
++** ssl -- TLS structure
++** rfd -- read fd
++** wfd -- write fd
++** tlsstart -- start time of TLS operation
++** timeout -- timeout for TLS operation
++** err -- SSL error
++** where -- description of operation
++**
++** Results:
++** >0 on success
++** 0 on timeout
++** <0 on error
++*/
++
++int
++tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where)
++ SSL *ssl;
++ int rfd;
++ int wfd;
++ time_t tlsstart;
++ int timeout;
++ int err;
++ const char *where;
++{
++ int ret;
++ time_t left;
++ time_t now = curtime();
++ struct timeval tv;
++
++ ret = -1;
++
++ /*
++ ** For SSL_ERROR_WANT_{READ,WRITE}:
++ ** There is not a complete SSL record available yet
++ ** or there is only a partial SSL record removed from
++ ** the network (socket) buffer into the SSL buffer.
++ ** The SSL_connect will only succeed when a full
++ ** SSL record is available (assuming a "real" error
++ ** doesn't happen). To handle when a "real" error
++ ** does happen the select is set for exceptions too.
++ ** The connection may be re-negotiated during this time
++ ** so both read and write "want errors" need to be handled.
++ ** A select() exception loops back so that a proper SSL
++ ** error message can be gotten.
++ */
++
++ left = timeout - (now - tlsstart);
++ if (left <= 0)
++ return 0; /* timeout */
++ tv.tv_sec = left;
++ tv.tv_usec = 0;
++
++ if (LogLevel > 14)
++ {
++ sm_syslog(LOG_INFO, NOQID,
++ "STARTTLS=%s, info: fds=%d/%d, err=%d",
++ where, rfd, wfd, err);
++ }
++
++ if (FD_SETSIZE > 0 &&
++ ((err == SSL_ERROR_WANT_READ && rfd >= FD_SETSIZE) ||
++ (err == SSL_ERROR_WANT_WRITE && wfd >= FD_SETSIZE)))
++ {
++ if (LogLevel > 5)
++ {
++ sm_syslog(LOG_ERR, NOQID,
++ "STARTTLS=%s, error: fd %d/%d too large",
++ where, rfd, wfd);
++ if (LogLevel > 8)
++ tlslogerr(where);
++ }
++ errno = EINVAL;
++ }
++ else if (err == SSL_ERROR_WANT_READ)
++ {
++ fd_set ssl_maskr, ssl_maskx;
++
++ FD_ZERO(&ssl_maskr);
++ FD_SET(rfd, &ssl_maskr);
++ FD_ZERO(&ssl_maskx);
++ FD_SET(rfd, &ssl_maskx);
++ do
++ {
++ ret = select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx,
++ &tv);
++ } while (ret < 0 && errno == EINTR);
++ if (ret < 0 && errno > 0)
++ ret = -errno;
++ }
++ else if (err == SSL_ERROR_WANT_WRITE)
++ {
++ fd_set ssl_maskw, ssl_maskx;
++
++ FD_ZERO(&ssl_maskw);
++ FD_SET(wfd, &ssl_maskw);
++ FD_ZERO(&ssl_maskx);
++ FD_SET(rfd, &ssl_maskx);
++ do
++ {
++ ret = select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx,
++ &tv);
++ } while (ret < 0 && errno == EINTR);
++ if (ret < 0 && errno > 0)
++ ret = -errno;
++ }
++ return ret;
++}
++
++/* errno to force refill() etc to stop (see IS_IO_ERROR()) */
++#ifdef ETIMEDOUT
++# define SM_ERR_TIMEOUT ETIMEDOUT
++#else /* ETIMEDOUT */
++# define SM_ERR_TIMEOUT EIO
++#endif /* ETIMEDOUT */
++
++/*
+ ** TLS_READ -- read secured information for the caller
+ **
+ ** Parameters:
+@@ -502,38 +621,42 @@ tls_read(fp, buf, size)
+ char *buf;
+ size_t size;
+ {
+- int r;
+- static int again = MAX_TLS_IOS;
++ int r, rfd, wfd, try, ssl_err;
+ struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
++ time_t tlsstart;
+ char *err;
+
++ try = 99;
++ err = NULL;
++ tlsstart = curtime();
++
++ retry:
+ r = SSL_read(so->con, (char *) buf, size);
+
+ if (r > 0)
+- {
+- again = MAX_TLS_IOS;
+ return r;
+- }
+
+ err = NULL;
+- switch (SSL_get_error(so->con, r))
++ switch (ssl_err = SSL_get_error(so->con, r))
+ {
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_ZERO_RETURN:
+- again = MAX_TLS_IOS;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+- if (--again <= 0)
+- err = "read W BLOCK";
+- else
+- errno = EAGAIN;
+- break;
++ err = "read W BLOCK";
++ /* FALLTHROUGH */
+ case SSL_ERROR_WANT_READ:
+- if (--again <= 0)
++ if (err == NULL)
+ err = "read R BLOCK";
+- else
+- errno = EAGAIN;
++ rfd = SSL_get_rfd(so->con);
++ wfd = SSL_get_wfd(so->con);
++ try = tls_retry(so->con, rfd, wfd, tlsstart,
++ TimeOuts.to_datablock, ssl_err, "read");
++ if (try > 0)
++ goto retry;
++ errno = SM_ERR_TIMEOUT;
+ break;
++
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ err = "write X BLOCK";
+ break;
+@@ -556,7 +679,6 @@ tls_read(fp, buf, size)
+ int save_errno;
+
+ save_errno = (errno == 0) ? EIO : errno;
+- again = MAX_TLS_IOS;
+ if (LogLevel > 7)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: read error=%s (%d)", err, r);
+@@ -586,36 +708,39 @@ tls_write(fp, buf, size)
+ const char *buf;
+ size_t size;
+ {
+- int r;
+- static int again = MAX_TLS_IOS;
++ int r, rfd, wfd, try, ssl_err;
+ struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
++ time_t tlsstart;
+ char *err;
+
++ try = 99;
++ err = NULL;
++ tlsstart = curtime();
++
++ retry:
+ r = SSL_write(so->con, (char *) buf, size);
+
+ if (r > 0)
+- {
+- again = MAX_TLS_IOS;
+ return r;
+- }
+ err = NULL;
+- switch (SSL_get_error(so->con, r))
++ switch (ssl_err = SSL_get_error(so->con, r))
+ {
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_ZERO_RETURN:
+- again = MAX_TLS_IOS;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+- if (--again <= 0)
+- err = "write W BLOCK";
+- else
+- errno = EAGAIN;
+- break;
++ err = "read W BLOCK";
++ /* FALLTHROUGH */
+ case SSL_ERROR_WANT_READ:
+- if (--again <= 0)
+- err = "write R BLOCK";
+- else
+- errno = EAGAIN;
++ if (err == NULL)
++ err = "read R BLOCK";
++ rfd = SSL_get_rfd(so->con);
++ wfd = SSL_get_wfd(so->con);
++ try = tls_retry(so->con, rfd, wfd, tlsstart,
++ DATA_PROGRESS_TIMEOUT, ssl_err, "write");
++ if (try > 0)
++ goto retry;
++ errno = SM_ERR_TIMEOUT;
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ err = "write X BLOCK";
+@@ -642,7 +767,6 @@ tls_write(fp, buf, size)
+ int save_errno;
+
+ save_errno = (errno == 0) ? EIO : errno;
+- again = MAX_TLS_IOS;
+ if (LogLevel > 7)
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS: write error=%s (%d)", err, r);
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/sfsasl.h sendmail-8.12.3/sendmail/sfsasl.h
+--- sendmail-8.12.3.orig/sendmail/sfsasl.h 2000-09-19 23:30:49.000000000 +0200
++++ sendmail-8.12.3/sendmail/sfsasl.h 2006-03-22 22:42:45.000000000 +0100
+@@ -17,6 +17,8 @@ extern int sfdcsasl __P((SM_FILE_T **, S
+ #endif /* SASL */
+
+ # if STARTTLS
++extern int tls_retry __P((SSL *, int, int, time_t, int, int,
++ const char *));
+ extern int sfdctls __P((SM_FILE_T **, SM_FILE_T **, SSL *));
+ # endif /* STARTTLS */
+
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/srvrsmtp.c sendmail-8.12.3/sendmail/srvrsmtp.c
+--- sendmail-8.12.3.orig/sendmail/srvrsmtp.c 2002-04-02 05:51:02.000000000 +0200
++++ sendmail-8.12.3/sendmail/srvrsmtp.c 2006-03-23 00:01:40.000000000 +0100
+@@ -1374,70 +1374,20 @@ smtp(nullserver, d_flags, e)
+ if ((r = SSL_ACC(srv_ssl)) <= 0)
+ {
+ int i;
+- bool timedout;
+- time_t left;
+- time_t now = curtime();
+- struct timeval tv;
++ int ssl_err;
+
+- /* what to do in this case? */
+- i = SSL_get_error(srv_ssl, r);
++ ssl_err = SSL_get_error(srv_ssl, r);
++ i = tls_retry(srv_ssl, rfd, wfd, tlsstart,
++ TimeOuts.to_starttls, ssl_err,
++ "server");
++ if (i > 0)
++ goto ssl_retry;
+
+- /*
+- ** For SSL_ERROR_WANT_{READ,WRITE}:
+- ** There is no SSL record available yet
+- ** or there is only a partial SSL record
+- ** removed from the network (socket) buffer
+- ** into the SSL buffer. The SSL_accept will
+- ** only succeed when a full SSL record is
+- ** available (assuming a "real" error
+- ** doesn't happen). To handle when a "real"
+- ** error does happen the select is set for
+- ** exceptions too.
+- ** The connection may be re-negotiated
+- ** during this time so both read and write
+- ** "want errors" need to be handled.
+- ** A select() exception loops back so that
+- ** a proper SSL error message can be gotten.
+- */
+-
+- left = TimeOuts.to_starttls - (now - tlsstart);
+- timedout = left <= 0;
+- if (!timedout)
+- {
+- tv.tv_sec = left;
+- tv.tv_usec = 0;
+- }
+-
+- /* XXX what about SSL_pending() ? */
+- if (!timedout && i == SSL_ERROR_WANT_READ)
+- {
+- fd_set ssl_maskr, ssl_maskx;
+-
+- FD_ZERO(&ssl_maskr);
+- FD_SET(rfd, &ssl_maskr);
+- FD_ZERO(&ssl_maskx);
+- FD_SET(rfd, &ssl_maskx);
+- if (select(rfd + 1, &ssl_maskr, NULL,
+- &ssl_maskx, &tv) > 0)
+- goto ssl_retry;
+- }
+- if (!timedout && i == SSL_ERROR_WANT_WRITE)
+- {
+- fd_set ssl_maskw, ssl_maskx;
+-
+- FD_ZERO(&ssl_maskw);
+- FD_SET(wfd, &ssl_maskw);
+- FD_ZERO(&ssl_maskx);
+- FD_SET(rfd, &ssl_maskx);
+- if (select(wfd + 1, NULL, &ssl_maskw,
+- &ssl_maskx, &tv) > 0)
+- goto ssl_retry;
+- }
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+- "STARTTLS=server, error: accept failed=%d, SSL_error=%d, timedout=%d",
+- r, i, (int) timedout);
++ "STARTTLS=server, error: accept failed=%d, SSL_error=%d, errno=%d",
++ r, i, errno);
+ if (LogLevel > 8)
+ tlslogerr("server");
+ }
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/usersmtp.c sendmail-8.12.3/sendmail/usersmtp.c
+--- sendmail-8.12.3.orig/sendmail/usersmtp.c 2002-04-03 02:23:25.000000000 +0200
++++ sendmail-8.12.3/sendmail/usersmtp.c 2006-03-22 22:42:45.000000000 +0100
+@@ -19,7 +19,6 @@ SM_RCSID("@(#)$Id: usersmtp.c,v 8.431 20
+
+
+ extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int, bool));
+-static void datatimeout __P((void));
+ static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
+ static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
+ static int smtprcptstat __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
+@@ -2227,9 +2226,6 @@ smtprcptstat(to, m, mci, e)
+ ** exit status corresponding to DATA command.
+ */
+
+-static jmp_buf CtxDataTimeout;
+-static SM_EVENT *volatile DataTimeout = NULL;
+-
+ int
+ smtpdata(m, mci, e, ctladdr, xstart)
+ MAILER *m;
+@@ -2241,7 +2237,7 @@ smtpdata(m, mci, e, ctladdr, xstart)
+ register int r;
+ int rstat;
+ int xstat;
+- time_t timeout;
++ int timeout;
+ char *enhsc;
+
+ /*
+@@ -2351,43 +2347,22 @@ smtpdata(m, mci, e, ctladdr, xstart)
+ ** factor. The main thing is that it should not be infinite.
+ */
+
+- if (setjmp(CtxDataTimeout) != 0)
+- {
+- mci->mci_errno = errno;
+- mci->mci_state = MCIS_ERROR;
+- mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
+-
+- /*
+- ** If putbody() couldn't finish due to a timeout,
+- ** rewind it here in the timeout handler. See
+- ** comments at the end of putbody() for reasoning.
+- */
+-
+- if (e->e_dfp != NULL)
+- (void) bfrewind(e->e_dfp);
+-
+- errno = mci->mci_errno;
+- syserr("451 4.4.1 timeout writing message to %s", CurHostName);
+- smtpquit(m, mci, e);
+- return EX_TEMPFAIL;
+- }
+-
+ if (tTd(18, 101))
+ {
+ /* simulate a DATA timeout */
+- timeout = 1;
++ timeout = 10;
+ }
+ else
+- timeout = DATA_PROGRESS_TIMEOUT;
+-
+- DataTimeout = sm_setevent(timeout, datatimeout, 0);
++ timeout = DATA_PROGRESS_TIMEOUT * 1000;
++ sm_io_setinfo(mci->mci_out, SM_IO_WHAT_TIMEOUT, &timeout);
+
+
+ /*
+ ** Output the actual message.
+ */
+
+- (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
++ if (!(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER))
++ goto writeerr;
+
+ if (tTd(18, 101))
+ {
+@@ -2395,14 +2370,13 @@ smtpdata(m, mci, e, ctladdr, xstart)
+ (void) sleep(2);
+ }
+
+- (*e->e_putbody)(mci, e, NULL);
++ if (!(*e->e_putbody)(mci, e, NULL))
++ goto writeerr;
+
+ /*
+ ** Cleanup after sending message.
+ */
+
+- if (DataTimeout != NULL)
+- sm_clrevent(DataTimeout);
+
+ #if PIPELINING
+ }
+@@ -2442,7 +2416,9 @@ smtpdata(m, mci, e, ctladdr, xstart)
+ }
+
+ /* terminate the message */
+- (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s", m->m_eol);
++ if (sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s", m->m_eol) ==
++ SM_IO_EOF)
++ goto writeerr;
+ if (TrafficLogFile != NULL)
+ (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
+ "%05d >>> .\n", (int) CurrentPid);
+@@ -2492,50 +2468,27 @@ smtpdata(m, mci, e, ctladdr, xstart)
+ shortenstring(SmtpReplyBuffer, 403));
+ }
+ return rstat;
+-}
+
+-static void
+-datatimeout()
+-{
+- int save_errno = errno;
++ writeerr:
++ mci->mci_errno = errno;
++ mci->mci_state = MCIS_ERROR;
++ mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
+
+ /*
+- ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+- ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+- ** DOING.
++ ** If putbody() couldn't finish due to a timeout,
++ ** rewind it here in the timeout handler. See
++ ** comments at the end of putbody() for reasoning.
+ */
+
+- if (DataProgress)
+- {
+- time_t timeout;
+-
+- /* check back again later */
+- if (tTd(18, 101))
+- {
+- /* simulate a DATA timeout */
+- timeout = 1;
+- }
+- else
+- timeout = DATA_PROGRESS_TIMEOUT;
+-
+- /* reset the timeout */
+- DataTimeout = sm_sigsafe_setevent(timeout, datatimeout, 0);
+- DataProgress = false;
+- }
+- else
+- {
+- /* event is done */
+- DataTimeout = NULL;
+- }
++ if (e->e_dfp != NULL)
++ (void) bfrewind(e->e_dfp);
+
+- /* if no progress was made or problem resetting event, die now */
+- if (DataTimeout == NULL)
+- {
+- errno = ETIMEDOUT;
+- longjmp(CtxDataTimeout, 1);
+- }
+- errno = save_errno;
++ errno = mci->mci_errno;
++ syserr("451 4.4.1 timeout writing message to %s", CurHostName);
++ smtpquit(m, mci, e);
++ return EX_TEMPFAIL;
+ }
++
+ /*
+ ** SMTPGETSTAT -- get status code from DATA in LMTP
+ **
+diff -u -p -Nr --exclude CVS sendmail-8.12.3.orig/sendmail/util.c sendmail-8.12.3/sendmail/util.c
+--- sendmail-8.12.3.orig/sendmail/util.c 2002-04-04 23:32:15.000000000 +0200
++++ sendmail-8.12.3/sendmail/util.c 2006-03-22 22:42:45.000000000 +0100
+@@ -878,18 +878,18 @@ fixcrlf(line, stripnl)
+ ** mci -- the mailer connection information.
+ **
+ ** Returns:
+-** none
++** true iff line was written successfully
+ **
+ ** Side Effects:
+ ** output of l to mci->mci_out.
+ */
+
+-void
++bool
+ putline(l, mci)
+ register char *l;
+ register MCI *mci;
+ {
+- putxline(l, strlen(l), mci, PXLF_MAPFROM);
++ return putxline(l, strlen(l), mci, PXLF_MAPFROM);
+ }
+ /*
+ ** PUTXLINE -- putline with flags bits.
+@@ -908,13 +908,13 @@ putline(l, mci)
+ ** PXLF_NOADDEOL -- don't add an EOL if one wasn't present.
+ **
+ ** Returns:
+-** none
++** true iff line was written successfully
+ **
+ ** Side Effects:
+ ** output of l to mci->mci_out.
+ */
+
+-void
++bool
+ putxline(l, len, mci, pxflags)
+ register char *l;
+ size_t len;
+@@ -966,11 +966,6 @@ putxline(l, len, mci, pxflags)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ '.') == SM_IO_EOF)
+ dead = true;
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ if (TrafficLogFile != NULL)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT, '.');
+@@ -983,11 +978,6 @@ putxline(l, len, mci, pxflags)
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ '>') == SM_IO_EOF)
+ dead = true;
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ if (TrafficLogFile != NULL)
+ (void) sm_io_putc(TrafficLogFile,
+ SM_TIME_DEFAULT,
+@@ -999,16 +989,11 @@ putxline(l, len, mci, pxflags)
+ while (l < q)
+ {
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+- (unsigned char) *l++) == SM_IO_EOF)
++ (unsigned char) *l++) == SM_IO_EOF)
+ {
+ dead = true;
+ break;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ }
+ if (dead)
+ break;
+@@ -1024,11 +1009,6 @@ putxline(l, len, mci, pxflags)
+ dead = true;
+ break;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ if (TrafficLogFile != NULL)
+ {
+ for (l = l_base; l < q; l++)
+@@ -1052,11 +1032,9 @@ putxline(l, len, mci, pxflags)
+ {
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '.') ==
+ SM_IO_EOF)
+- break;
+- else
+ {
+- /* record progress for DATA timeout */
+- DataProgress = true;
++ dead = true;
++ break;
+ }
+ if (TrafficLogFile != NULL)
+ (void) sm_io_putc(TrafficLogFile,
+@@ -1069,11 +1047,9 @@ putxline(l, len, mci, pxflags)
+ {
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '>') ==
+ SM_IO_EOF)
+- break;
+- else
+ {
+- /* record progress for DATA timeout */
+- DataProgress = true;
++ dead = true;
++ break;
+ }
+ if (TrafficLogFile != NULL)
+ (void) sm_io_putc(TrafficLogFile,
+@@ -1091,11 +1067,6 @@ putxline(l, len, mci, pxflags)
+ dead = true;
+ break;
+ }
+- else
+- {
+- /* record progress for DATA timeout */
+- DataProgress = true;
+- }
+ }
+ if (dead)
+ break;
+@@ -1106,11 +1077,9 @@ putxline(l, len, mci, pxflags)
+ if ((!bitset(PXLF_NOADDEOL, pxflags) || !noeol) &&
+ sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT,
+ mci->mci_mailer->m_eol) == SM_IO_EOF)
+- break;
+- else
+ {
+- /* record progress for DATA timeout */
+- DataProgress = true;
++ dead = true;
++ break;
+ }
+ if (l < end && *l == '\n')
+ {
+@@ -1119,11 +1088,9 @@ putxline(l, len, mci, pxflags)
+ {
+ if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT,
+ ' ') == SM_IO_EOF)
+- break;
+- else
+ {
+- /* record progress for DATA timeout */
+- DataProgress = true;
++ dead = true;
++ break;
+ }
+
+ if (TrafficLogFile != NULL)
+@@ -1132,10 +1099,10 @@ putxline(l, len, mci, pxflags)
+ }
+ }
+
+- /* record progress for DATA timeout */
+- DataProgress = true;
+ } while (l < end);
++ return !dead;
+ }
++
+ /*
+ ** XUNLINK -- unlink a file, doing logging as appropriate.
+ **