diff options
author | Martin Schulze <joey@infodrom.org> | 2006-03-22 23:24:46 +0100 |
---|---|---|
committer | Andreas Beckmann <debian@abeckmann.de> | 2012-10-01 19:58:43 +0200 |
commit | 8761847e87565e67b3e25d8cc0196772dc8acc6d (patch) | |
tree | af99c44a2de25945e4233c05a2680cbe0aff7a8f | |
parent | ae03fe5d926a63cab418207f760d62a947957123 (diff) | |
download | sendmail-debian/8.12.3-7.2.tar.gz |
Imported Debian patch 8.12.3-7.2debian/8.12.3-7.2
-rw-r--r-- | debian/changelog | 8 | ||||
-rw-r--r-- | debian/patches/8.12/8.12.3/z_CVE-2006-0058.patch | 2768 |
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. + ** |