Sophie

Sophie

distrib > Mandriva > 10.2 > x86_64 > by-pkgid > 4884389abee1d23d846ab26857cec36c > files > 9

sendmail-8.13.3-2.2.102mdk.src.rpm

diff -ru libsm/fflush.c libsm/fflush.c
--- libsm/fflush.c	Tue Jun 14 16:07:20 2005
+++ libsm/fflush.c	Fri Mar  3 14:25:00 2006
@@ -145,6 +145,7 @@
 				return SM_IO_EOF;
 			}
 			SM_IO_WR_TIMEOUT(fp, fd, *timeout);
+			t = 0;
 		}
 	}
 	return 0;
diff -ru libsm/local.h libsm/local.h
--- libsm/local.h	Tue Jun 14 16:07:20 2005
+++ libsm/local.h	Tue Feb 28 10:48:25 2006
@@ -156,7 +156,7 @@
 	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) \
 	{ \
@@ -240,7 +240,7 @@
 	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; \
 	} \
 	if (FD_SETSIZE > 0 && (fd) >= FD_SETSIZE) \
 	{ \
@@ -253,8 +253,11 @@
 	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 */ \
@@ -269,10 +272,9 @@
 	/* 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 -ru libsm/refill.c libsm/refill.c
--- libsm/refill.c	Tue Jun 14 16:07:20 2005
+++ libsm/refill.c	Tue Feb 28 10:48:25 2006
@@ -76,8 +76,11 @@
 	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 */			\
@@ -94,7 +97,7 @@
 	/* 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 -ru sendmail/collect.c sendmail/collect.c
--- sendmail/collect.c	Wed Feb 16 15:38:51 2005
+++ sendmail/collect.c	Thu Mar  2 11:09:26 2006
@@ -17,5 +17,4 @@

-static void	collecttimeout __P((int));
 static void	eatfrom __P((char *volatile, ENVELOPE *));
 static void	collect_doheader __P((ENVELOPE *));
 static SM_FILE_T *collect_dfopen __P((ENVELOPE *));
@@ -263,10 +262,6 @@
 **		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,27 +283,31 @@
 	register ENVELOPE *e;
 	bool rsetsize;
 {
-	register SM_FILE_T *volatile df;
-	volatile bool ignrdot;
-	volatile int dbto;
-	register char *volatile bp;
-	volatile int c;
-	volatile bool inputerr;
+	register SM_FILE_T *df;
+	bool ignrdot;
+	int dbto;
+	register char *bp;
+	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 ? (int) 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;
@@ -320,7 +319,6 @@
 	pbp = peekbuf;
 	istate = IS_BOL;
 	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
-	CollectProgress = false;

 	/*
 	**  Tell ARPANET to go ahead.
@@ -341,32 +343,6 @@
 	**	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;
-			if (smtpmode)
-			{
-				/*
-				**  Override e_message in usrerr() as this
-				**  is the reason for failure that should
-				**  be logged for undelivered recipients.
-				*/
-
-				e->e_message = NULL;
-			}
-			usrerr("451 4.4.1 timeout waiting for input during message collect");
-			goto readerr;
-		}
-		CollectTimeout = sm_setevent(dbto, collecttimeout, dbto);
-	}
-
 	if (rsetsize)
 		e->e_msgsize = 0;
 	for (;;)
@@ -390,9 +366,26 @@
 						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)
@@ -538,6 +533,18 @@
 					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];
@@ -581,6 +588,7 @@
 					usrerrenh(e->e_status,
 						  "552 Headers too large (%d max)",
 						  MaxHeadersLength);
+  discard:
 					mstate = MS_DISCARD;
 				}
 			}
@@ -620,6 +628,24 @@
 				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);
@@ -629,8 +655,12 @@
 				continue;
 			}

-			/* trim off trailing CRLF or NL */
 			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++;
 			*bp = '\0';
@@ -696,10 +726,6 @@
 		inputerr = true;
 	}

-	/* reset global timer */
-	if (CollectTimeout != NULL)
-		sm_clrevent(CollectTimeout);
-
 	if (headeronly)
 		return;

@@ -786,6 +812,7 @@
 	}

 	/* An EOF when running SMTP is an error */
+  readabort:
 	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
 	{
 		char *host;
@@ -808,13 +835,14 @@
 				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;
@@ -907,39 +935,6 @@
 	}
 }

-static void
-collecttimeout(timeout)
-	int 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 -ru sendmail/conf.c sendmail/conf.c
--- sendmail/conf.c	Mon Jul 25 22:45:38 2005
+++ sendmail/conf.c	Thu Feb 23 18:21:53 2006
@@ -5330,8 +5362,8 @@
 	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;
@@ -5355,11 +5387,8 @@
 	else
 		idlen = strlen(id) + SyslogPrefixLen;

-	if (buf == NULL)
-	{
-		buf = buf0;
-		bufsize = sizeof buf0;
-	}
+	buf = buf0;
+	bufsize = sizeof buf0;

 	for (;;)
 	{
@@ -5401,8 +5430,8 @@
 			(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;
 	}
@@ -5466,8 +5495,8 @@
 		(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 -ru sendmail/deliver.c sendmail/deliver.c
--- sendmail/deliver.c	Wed Aug 24 10:58:33 2005
+++ sendmail/deliver.c	Wed Mar  1 17:37:39 2006
@@ -3257,16 +3260,33 @@
 	}
 	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);

-		/* get the exit status */
+		/*
+		**  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;
+
+		/* (always) get the exit status */
 		rcode = endmailer(mci, e, pv);
+		if (!ok)
+			rcode = EX_TEMPFAIL;
 		if (rcode == EX_TEMPFAIL && SmtpError[0] == '\0')
 		{
 			/*
@@ -4430,13 +4450,13 @@
 **		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;
@@ -4446,7 +4466,7 @@
 	char xbuf[MAXLINE];

 	if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
-		return;
+		return true;

 	mci->mci_flags |= MCIF_INHEADER;

@@ -4487,8 +4507,9 @@
 		}
 	}
 	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.
 **
@@ -4499,7 +4520,7 @@
 **			not be permitted in the resulting message.
 **
 **	Returns:
-**		none.
+**		true iff message was written successfully
 **
 **	Side Effects:
 **		The message is written onto fp.
@@ -4510,13 +4531,15 @@
 #define OSTATE_CR	1	/* read a carriage return */
 #define OSTATE_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];
@@ -4546,10 +4569,12 @@
 	{
 		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;
 	}

@@ -4578,26 +4607,31 @@
 		*/

 		/* 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)
@@ -4619,8 +4653,9 @@
 		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;
@@ -4640,7 +4675,8 @@

 		if (bitset(MCIF_INHEADER, mci->mci_flags))
 		{
-			putline("", mci);
+			if (!putline("", mci))
+				goto writeerr;
 			mci->mci_flags &= ~MCIF_INHEADER;
 		}

@@ -4731,11 +4767,6 @@
 						dead = true;
 						continue;
 					}
-					else
-					{
-						/* record progress for DATA timeout */
-						DataProgress = true;
-					}
 					pos++;
 				}
 				for (xp = buf; xp < bp; xp++)
@@ -4748,11 +4779,6 @@
 						dead = true;
 						break;
 					}
-					else
-					{
-						/* record progress for DATA timeout */
-						DataProgress = true;
-					}
 				}
 				if (dead)
 					continue;
@@ -4763,11 +4789,6 @@
 							mci->mci_mailer->m_eol)
 							== SM_IO_EOF)
 						break;
-					else
-					{
-						/* record progress for DATA timeout */
-						DataProgress = true;
-					}
 					pos = 0;
 				}
 				else
@@ -4801,11 +4822,6 @@
 							mci->mci_mailer->m_eol)
 							== SM_IO_EOF)
 						continue;
-					else
-					{
-						/* record progress for DATA timeout */
-						DataProgress = true;
-					}

 					if (TrafficLogFile != NULL)
 					{
@@ -4867,11 +4883,6 @@
 							dead = true;
 							continue;
 						}
-						else
-						{
-							/* record progress for DATA timeout */
-							DataProgress = true;
-						}
 						pos++;
 						continue;
 					}
@@ -4887,11 +4898,6 @@
 						dead = true;
 						continue;
 					}
-					else
-					{
-						/* record progress for DATA timeout */
-						DataProgress = true;
-					}

 					if (TrafficLogFile != NULL)
 					{
@@ -4917,11 +4923,6 @@
 							mci->mci_mailer->m_eol)
 							== SM_IO_EOF)
 						continue;
-					else
-					{
-						/* record progress for DATA timeout */
-						DataProgress = true;
-					}
 					pos = 0;
 					ostate = OSTATE_HEAD;
 				}
@@ -4939,11 +4940,6 @@
 						dead = true;
 						continue;
 					}
-					else
-					{
-						/* record progress for DATA timeout */
-						DataProgress = true;
-					}
 					pos++;
 					ostate = OSTATE_INLINE;
 				}
@@ -4970,11 +4966,6 @@
 					dead = true;
 					break;
 				}
-				else
-				{
-					/* record progress for DATA timeout */
-					DataProgress = true;
-				}
 			}
 			pos += bp - buf;
 		}
@@ -4984,11 +4975,9 @@
 				(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;
 		}
 	}

@@ -4998,6 +4987,7 @@
 		       qid_printqueue(e->e_dfqgrp, e->e_dfqdir),
 		       DATAFL_LETTER, e->e_id);
 		ExitStat = EX_IOERR;
+		ioerr = true;
 	}

 endofmessage:
@@ -5012,23 +5002,35 @@
 	**  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.
 **
@@ -5559,14 +5561,14 @@
 		}
 #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
@@ -6128,86 +6134,23 @@
 ssl_retry:
 	if ((result = SSL_connect(clt_ssl)) <= 0)
 	{
-		int i;
-		bool timedout;
-		time_t left;
-		time_t now = curtime();
-		struct timeval tv;
+		int i, ssl_err;

-		/* what to do in this case? */
-		i = SSL_get_error(clt_ssl, result);
+		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;

-		/*
-		**  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 = TimeOuts.to_starttls - (now - tlsstart);
-		timedout = left <= 0;
-		if (!timedout)
-		{
-			tv.tv_sec = left;
-			tv.tv_usec = 0;
-		}
-
-		if (!timedout && FD_SETSIZE > 0 &&
-		    (rfd >= FD_SETSIZE ||
-		     (i == SSL_ERROR_WANT_WRITE && wfd >= FD_SETSIZE)))
-		{
-			if (LogLevel > 5)
-			{
-				sm_syslog(LOG_ERR, e->e_id,
-					  "STARTTLS=client, error: fd %d/%d too large",
-					  rfd, wfd);
-			if (LogLevel > 8)
-				tlslogerr("client");
-			}
-			errno = EINVAL;
-			goto tlsfail;
-		}
-		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, errno=%d",
-				  result, i, (int) timedout, errno);
+			sm_syslog(LOG_WARNING, NOQID,
+				  "STARTTLS=client, error: connect failed=%d, SSL_error=%d, errno=%d, retry=%d",
+				  result, ssl_err, errno, i);
 			if (LogLevel > 8)
 				tlslogerr("client");
 		}
-tlsfail:
+
 		SSL_free(clt_ssl);
 		clt_ssl = NULL;
 		return EX_SOFTWARE;
diff -ru sendmail/headers.c sendmail/headers.c
--- sendmail/headers.c	Fri Dec  3 10:29:51 2004
+++ sendmail/headers.c	Fri Feb 24 18:16:52 2006
@@ -17,8 +17,8 @@

 static HDR	*allocheader __P((char *, char *, int, SM_RPOOL_T *));
 static size_t	fix_mime_header __P((HDR *, ENVELOPE *));
 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
@@ -993,7 +993,6 @@
 	char *name;
 	register char *sbp;
 	register char *p;
-	int l;
 	char hbuf[MAXNAME + 1];
 	char sbuf[MAXLINE + 1];
 	char mbuf[MAXNAME + 1];
@@ -1002,6 +1001,8 @@
 	/* 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;
@@ -1541,13 +1542,13 @@
 **		flags -- MIME conversion flags.
 **
 **	Returns:
-**		none.
+**		success
 **
 **	Side Effects:
 **		none.
 */

-void
+bool
 putheader(mci, hdr, e, flags)
 	register MCI *mci;
 	HDR *hdr;
@@ -1682,7 +1683,8 @@
 		{
 			if (tTd(34, 11))
 				sm_dprintf("\n");
-			put_vanilla_header(h, p, mci);
+			if (!put_vanilla_header(h, p, mci))
+				goto writeerr;
 			continue;
 		}

@@ -1741,7 +1743,8 @@
 				/* 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;
 		}
@@ -1760,7 +1763,8 @@
 		}
 		else
 		{
-			put_vanilla_header(h, p, mci);
+			if (!put_vanilla_header(h, p, mci))
+				goto writeerr;
 		}
 	}

@@ -1777,18 +1781,25 @@
 	    !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
@@ -1799,10 +1810,10 @@
 **		mci -- the connection info for output
 **
 **	Returns:
-**		none.
+**		success
 */

-static void
+static bool
 put_vanilla_header(h, v, mci)
 	HDR *h;
 	char *v;
@@ -1833,7 +1844,8 @@
 			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')
@@ -1843,7 +1855,10 @@
 	/* XXX This is broken for SPACELEFT()==0 */
 	(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.
@@ -1856,13 +1871,13 @@
 **		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;
@@ -2001,13 +2016,6 @@
 		}
 		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)
@@ -2015,7 +2023,8 @@
 		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 obuf);
 			opos = strlen(obp);
@@ -2037,8 +2046,12 @@
 		*obp = '\0';
 	else
 		obuf[sizeof obuf - 1] = '\0';
-	putxline(obuf, strlen(obuf), mci, putflags);
+	return putxline(obuf, strlen(obuf), mci, putflags);
+
+  writeerr:
+	return false;
 }
+
 /*
 **  COPYHEADER -- copy header list
 **
diff -ru sendmail/mime.c sendmail/mime.c
--- sendmail/mime.c	Thu Sep  2 14:37:26 2004
+++ sendmail/mime.c	Wed Mar  1 10:07:45 2006
@@ -86,6 +86,7 @@
 **		  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
@@ -298,7 +299,8 @@
 		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)
@@ -307,8 +309,9 @@
 			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);
 		}
@@ -319,19 +322,24 @@
 			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, false);
 			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;
@@ -344,8 +352,9 @@
 			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);
 		}
@@ -373,18 +382,21 @@
 		{
 			auto HDR *hdr = NULL;

-			putline("", mci);
+			if (!putline("", mci))
+				goto writeerr;

 			mci->mci_flags |= MCIF_INMIME;
 			collect(e->e_dfp, false, &hdr, e, false);
 			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 &&
-			    !bitset(M87F_NO8TO7, flags))
-				putline("MIME-Version: 1.0", mci);
+			    !bitset(M87F_NO8TO7, flags) &&
+			    !putline("MIME-Version: 1.0", mci))
+				goto writeerr;
 			bt = mime8to7(mci, hdr, e, boundaries, flags);
 			mci->mci_flags &= ~MCIF_INMIME;
 			return bt;
@@ -480,11 +492,13 @@

 			(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)
@@ -492,7 +506,8 @@
 			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;
@@ -505,12 +520,13 @@

 		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)
@@ -518,7 +534,8 @@
 			if (linelen > 71)
 			{
 				*bp = '\0';
-				putline(buf, mci);
+				if (!putline(buf, mci))
+					goto writeerr;
 				linelen = 0;
 				bp = buf;
 			}
@@ -548,7 +565,8 @@
 			*bp++ = Base64Code[c2 & 0x3f];
 		}
 		*bp = '\0';
-		putline(buf, mci);
+		if (!putline(buf, mci))
+			goto writeerr;
 	}
 	else
 	{
@@ -571,12 +589,14 @@

 		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';
@@ -598,7 +618,8 @@
 					*bp++ = Base16Code['.' & 0x0f];
 				}
 				*bp = '\0';
-				putline(buf, mci);
+				if (!putline(buf, mci))
+					goto writeerr;
 				linelen = fromstate = 0;
 				bp = buf;
 				c2 = c1;
@@ -627,7 +648,8 @@
 					c2 = '\n';
 				*bp++ = '=';
 				*bp = '\0';
-				putline(buf, mci);
+				if (!putline(buf, mci))
+					goto writeerr;
 				linelen = fromstate = 0;
 				bp = buf;
 				if (c2 == '.')
@@ -665,13 +687,17 @@
 		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
@@ -958,7 +984,7 @@
 **		e -- envelope.
 **
 **	Returns:
-**		none.
+**		true iff body was written successfully
 */

 static char index_64[128] =
@@ -975,7 +1001,7 @@

 # define CHAR64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])

-void
+bool
 mime7to8(mci, header, e)
 	register MCI *mci;
 	HDR *header;
@@ -1008,25 +1034,31 @@
 		{
 			(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;

 	/*
@@ -1090,7 +1122,8 @@
 		if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE])	\
 		{							\
 			CHK_EOL;					\
-			putxline((char *) fbuf, fbufp - fbuf, mci, pxflags); \
+			if (!putxline((char *) fbuf, fbufp - fbuf, mci, pxflags)) \
+				goto writeerr;				\
 			pxflags &= ~PXLF_NOADDEOL;			\
 			fbufp = fbuf;					\
 		}	\
@@ -1127,8 +1160,11 @@
 				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')
 			{
@@ -1144,7 +1180,8 @@
 	if (fbufp > fbuf)
 	{
 		*fbufp = '\0';
-		putxline((char *) fbuf, fbufp - fbuf, mci, pxflags);
+		if (!putxline((char *) fbuf, fbufp - fbuf, mci, pxflags))
+			goto writeerr;
 	}

 	/*
@@ -1154,10 +1191,15 @@
 	**  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 -ru sendmail/parseaddr.c sendmail/parseaddr.c
--- sendmail/parseaddr.c	Fri Feb  4 14:01:45 2005
+++ sendmail/parseaddr.c	Wed Feb  1 11:46:11 2006
@@ -1337,7 +1337,7 @@
 					/* $&{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];
@@ -1352,7 +1352,7 @@
 					/* 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);
@@ -1407,7 +1407,7 @@
 		{
 			char **hbrvp;
 			char **xpvp;
-			int trsize;
+			size_t trsize;
 			char *replac;
 			int endtoken;
 			STAB *map;
@@ -1509,7 +1509,7 @@
 				*++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 */
@@ -2949,7 +2949,7 @@
 	char *logid;
 {
 	char *volatile buf;
-	int bufsize;
+	size_t bufsize;
 	int saveexitstat;
 	int volatile rstat = EX_OK;
 	char **pvp;
@@ -3163,7 +3163,7 @@
 	int size;
 {
 	char *volatile buf;
-	int bufsize;
+	size_t bufsize;
 	int volatile rstat = EX_OK;
 	int rsno;
 	bool saveQuickAbort = QuickAbort;
diff -ru sendmail/savemail.c sendmail/savemail.c
--- sendmail/savemail.c	Wed Oct  6 14:36:06 2004
+++ sendmail/savemail.c	Fri Feb 24 18:16:53 2006
@@ -17,5 +17,5 @@

-static void	errbody __P((MCI *, ENVELOPE *, char *));
+static bool	errbody __P((MCI *, ENVELOPE *, char *));
 static bool	pruneroute __P((char *));

 /*
@@ -432,12 +432,13 @@
 			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
@@ -732,14 +733,14 @@
 **		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;
@@ -757,14 +758,16 @@

 	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;
 	}

 	/*
@@ -773,11 +776,12 @@

 	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;
 	}

 	/*
@@ -799,31 +803,36 @@
 	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).
@@ -849,17 +858,19 @@
 				{
 					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;
 		}
 	}

@@ -877,21 +888,24 @@

 		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)
 		{
@@ -899,11 +913,12 @@
 				"    (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;
@@ -917,25 +932,28 @@

 		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;
@@ -968,25 +986,28 @@

 		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
@@ -995,8 +1016,9 @@
 	(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
 	{
@@ -1007,11 +1029,12 @@
 		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;
@@ -1023,11 +1046,12 @@

 	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.
@@ -1039,13 +1063,15 @@
 			(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 */

@@ -1059,13 +1085,15 @@
 			(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))
@@ -1076,7 +1104,8 @@
 			(void) sm_strlcpyn(buf, sizeof buf, 2,
 					"Deliver-By-Date: ",
 					arpadate(ctime(&dbyd)));
-			putline(buf, mci);
+			if (!putline(buf, mci))
+				goto writeerr;
 		}

 		/*
@@ -1119,7 +1148,8 @@
 			else
 				continue;

-			putline("", mci);
+			if (!putline("", mci))
+				goto writeerr;

 			/* Original-Recipient: -- passed from on high */
 			if (q->q_orcpt != NULL)
@@ -1127,7 +1157,8 @@
 				(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 */
@@ -1176,7 +1207,8 @@
 				(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 */
@@ -1190,13 +1222,15 @@
 				(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)
@@ -1208,7 +1242,8 @@
 			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)
@@ -1222,7 +1257,8 @@
 				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 */
@@ -1234,7 +1270,8 @@
 				(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 */
@@ -1243,7 +1280,8 @@
 			(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))
@@ -1255,7 +1293,8 @@
 				(void) sm_strlcpyn(buf, sizeof buf, 2,
 					 "Will-Retry-Until: ",
 					 arpadate(ctime(&xdate)));
-				putline(buf, mci);
+				if (!putline(buf, mci))
+					goto writeerr;
 			}
 		}
 	}
@@ -1265,7 +1304,8 @@
 	**  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) &&
@@ -1273,21 +1313,27 @@

 		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);
@@ -1301,43 +1347,62 @@
 				(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 -ru sendmail/sendmail.h sendmail/sendmail.h
--- sendmail/sendmail.h	Thu Jun 23 16:11:22 2005
+++ sendmail/sendmail.h	Mon Feb 27 09:49:09 2006
@@ -809,13 +809,13 @@
 /* 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 void	insheader __P((int, char *, char *, int, ENVELOPE *));
 extern bool	isheader __P((char *));
-extern void	putfromline __P((MCI *, ENVELOPE *));
+extern bool	putfromline __P((MCI *, ENVELOPE *));
 extern void	setupheaders __P((void));

 /*
@@ -870,9 +870,9 @@
 	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 */
@@ -965,8 +965,8 @@
 extern ENVELOPE	*newenvelope __P((ENVELOPE *, ENVELOPE *, SM_RPOOL_T *));
 extern void	clrsessenvelope __P((ENVELOPE *));
 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.
@@ -1651,7 +1654,7 @@
 #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));

 /*
@@ -2153,7 +2153,6 @@
 #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 */
@@ -2520,8 +2537,8 @@
 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 -ru sendmail/sfsasl.c sendmail/sfsasl.c
--- sendmail/sfsasl.c	Wed Apr  6 16:39:03 2005
+++ sendmail/sfsasl.c	Thu Mar  2 11:18:27 2006
@@ -549,6 +549,125 @@
 # 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:
@@ -569,38 +688,42 @@
 	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;
@@ -633,15 +756,22 @@
 		int save_errno;

 		save_errno = (errno == 0) ? EIO : errno;
-		again = MAX_TLS_IOS;
-		if (LogLevel > 9)
+		if (try == 0 && save_errno == SM_ERR_TIMEOUT)
+		{
+			if (LogLevel > 7)
+				sm_syslog(LOG_WARNING, NOQID,
+					  "STARTTLS: read error=timeout");
+		}
+		else if (LogLevel > 8)
 			sm_syslog(LOG_WARNING, NOQID,
-				  "STARTTLS: read error=%s (%d), errno=%d, get_error=%s",
+				  "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
 				  err, r, errno,
-				  ERR_error_string(ERR_get_error(), NULL));
+				  ERR_error_string(ERR_get_error(), NULL), try,
+				  ssl_err);
 		else if (LogLevel > 7)
 			sm_syslog(LOG_WARNING, NOQID,
-				  "STARTTLS: read error=%s (%d)", err, r);
+				  "STARTTLS: read error=%s (%d), retry=%d, ssl_err=%d",
+				  err, r, errno, try, ssl_err);
 		errno = save_errno;
 	}
 	return r;
@@ -668,36 +798,39 @@
 	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";
@@ -730,15 +863,22 @@
 		int save_errno;

 		save_errno = (errno == 0) ? EIO : errno;
-		again = MAX_TLS_IOS;
-		if (LogLevel > 9)
+		if (try == 0 && save_errno == SM_ERR_TIMEOUT)
+		{
+			if (LogLevel > 7)
+				sm_syslog(LOG_WARNING, NOQID,
+					  "STARTTLS: write error=timeout");
+		}
+		else if (LogLevel > 8)
 			sm_syslog(LOG_WARNING, NOQID,
-				  "STARTTLS: write error=%s (%d), errno=%d, get_error=%s",
+				  "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
 				  err, r, errno,
-				  ERR_error_string(ERR_get_error(), NULL));
+				  ERR_error_string(ERR_get_error(), NULL), try,
+				  ssl_err);
 		else if (LogLevel > 7)
 			sm_syslog(LOG_WARNING, NOQID,
-				  "STARTTLS: write error=%s (%d)", err, r);
+				  "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d",
+				  err, r, errno, try, ssl_err);
 		errno = save_errno;
 	}
 	return r;
diff -ru sendmail/sfsasl.h sendmail/sfsasl.h
--- sendmail/sfsasl.h	Tue Sep 19 14:30:49 2000
+++ sendmail/sfsasl.h	Mon Feb 27 11:53:37 2006
@@ -17,6 +17,8 @@
 #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 -ru sendmail/srvrsmtp.c sendmail/srvrsmtp.c
--- sendmail/srvrsmtp.c	Tue Jun 14 16:33:21 2005
+++ sendmail/srvrsmtp.c	Mon Feb 27 16:42:13 2006
@@ -505,7 +523,6 @@
 #endif /* SASL */
 	int r;
 #if STARTTLS
-	int fdfl;
 	int rfd, wfd;
 	volatile bool tls_active = false;
 	volatile bool smtps = bitnset(D_SMTPS, d_flags);
@@ -1713,97 +1743,26 @@
 #  define SSL_ACC(s)	SSL_accept(s)

 			tlsstart = curtime();
-			fdfl = fcntl(rfd, F_GETFL);
-			if (fdfl != -1)
-				fcntl(rfd, F_SETFL, fdfl|O_NONBLOCK);
   ssl_retry:
 			if ((r = SSL_ACC(srv_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(srv_ssl, r);
-
-				/*
-				**  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;
-				}
+				int i, ssl_err;

-				if (!timedout && FD_SETSIZE > 0 &&
-				    (rfd >= FD_SETSIZE ||
-				     (i == SSL_ERROR_WANT_WRITE &&
-				      wfd >= FD_SETSIZE)))
-				{
-					if (LogLevel > 5)
-					{
-						sm_syslog(LOG_ERR, NOQID,
-							  "STARTTLS=server, error: fd %d/%d too large",
-							  rfd, wfd);
-						if (LogLevel > 8)
-							tlslogerr("server");
-					}
-					goto tlsfail;
-				}
-
-				/* 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;
+				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;

-					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, errno=%d",
-						  r, i, (int) timedout, errno);
+						  "STARTTLS=server, error: accept failed=%d, SSL_error=%d, errno=%d, retry=%d",
+						  r, ssl_err, errno, i);
 					if (LogLevel > 8)
 						tlslogerr("server");
 				}
-tlsfail:
 				tls_ok_srv = false;
 				SSL_free(srv_ssl);
 				srv_ssl = NULL;
@@ -1818,9 +1777,6 @@
 				goto doquit;
 			}

-			if (fdfl != -1)
-				fcntl(rfd, F_SETFL, fdfl);
-
 			/* ignore return code for now, it's in {verify} */
 			(void) tls_get_info(srv_ssl, true,
 					    CurSmtpClient,
diff -ru sendmail/usersmtp.c sendmail/usersmtp.c
--- sendmail/usersmtp.c	Tue Mar 15 16:36:09 2005
+++ sendmail/usersmtp.c	Fri Feb 24 18:16:53 2006
@@ -18,8 +18,7 @@

 #include <sysexits.h>


-static void	datatimeout __P((int));
 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 *));
@@ -2491,9 +2489,6 @@
 **		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;
@@ -2629,43 +2624,22 @@
 	**  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))
 	{
@@ -2673,14 +2647,13 @@
 		(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
 	}
@@ -2720,7 +2693,9 @@
 	}

 	/* 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);
@@ -2771,51 +2746,27 @@
 			  shortenstring(SmtpReplyBuffer, 403));
 	}
 	return rstat;
-}

-static void
-datatimeout(ignore)
-	int ignore;
-{
-	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 -ru sendmail/util.c sendmail/util.c
--- sendmail/util.c	Mon Aug  2 11:50:59 2004
+++ sendmail/util.c	Wed Mar  1 10:07:45 2006
@@ -456,6 +456,8 @@
 {
 	register char *p;

+	SM_REQUIRE(sz >= 0);
+
 	/* some systems can't handle size zero mallocs */
 	if (sz <= 0)
 		sz = 1;
@@ -970,18 +972,18 @@
 **		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.
@@ -1000,13 +1002,13 @@
 **		    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;
@@ -1058,11 +1060,6 @@
 				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, '.');
@@ -1075,11 +1072,6 @@
 				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,
@@ -1091,16 +1083,11 @@
 			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;
@@ -1116,11 +1103,6 @@
 				dead = true;
 				break;
 			}
-			else
-			{
-				/* record progress for DATA timeout */
-				DataProgress = true;
-			}
 			if (TrafficLogFile != NULL)
 			{
 				for (l = l_base; l < q; l++)
@@ -1144,11 +1126,9 @@
 		{
 			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,
@@ -1161,11 +1141,9 @@
 		{
 			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,
@@ -1183,11 +1161,6 @@
 				dead = true;
 				break;
 			}
-			else
-			{
-				/* record progress for DATA timeout */
-				DataProgress = true;
-			}
 		}
 		if (dead)
 			break;
@@ -1198,11 +1171,9 @@
 		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')
 		{
@@ -1211,11 +1182,9 @@
 			{
 				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)
@@ -1224,10 +1193,10 @@
 			}
 		}

-		/* record progress for DATA timeout */
-		DataProgress = true;
 	} while (l < end);
+	return !dead;
 }
+
 /*
 **  XUNLINK -- unlink a file, doing logging as appropriate.
 **
@@ -2433,6 +2405,7 @@
 				*h++ = 'r';
 				break;
 			  default:
+				SM_ASSERT(l >= 2);
 				(void) sm_snprintf(h, l, "%03o",
 					(unsigned int)((unsigned char) c));