Apply by doing: cd /usr/src patch -p0 < 012_sendmail.patch And then rebuild and install sendmail: cd gnu/usr.sbin/sendmail make obj make depend make make install Index: gnu/usr.sbin/sendmail/libsm/fflush.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsm/fflush.c,v retrieving revision 1.2 diff -u -p -r1.2 fflush.c --- gnu/usr.sbin/sendmail/libsm/fflush.c 1 Oct 2001 17:18:29 -0000 1.2 +++ gnu/usr.sbin/sendmail/libsm/fflush.c 24 Mar 2006 00:50:46 -0000 @@ -145,6 +145,7 @@ sm_flush(fp, timeout) return SM_IO_EOF; } SM_IO_WR_TIMEOUT(fp, fd, *timeout); + t = 0; } } return 0; Index: gnu/usr.sbin/sendmail/libsm/local.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsm/local.h,v retrieving revision 1.6 diff -u -p -r1.6 local.h --- gnu/usr.sbin/sendmail/libsm/local.h 24 Jun 2004 03:59:26 -0000 1.6 +++ gnu/usr.sbin/sendmail/libsm/local.h 24 Mar 2006 00:50:46 -0000 @@ -192,7 +192,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) \ { \ @@ -276,7 +276,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; \ } \ if (FD_SETSIZE > 0 && (fd) >= FD_SETSIZE) \ { \ @@ -289,8 +289,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 */ \ @@ -305,10 +308,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; \ } Index: gnu/usr.sbin/sendmail/libsm/refill.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/libsm/refill.c,v retrieving revision 1.4 diff -u -p -r1.4 refill.c --- gnu/usr.sbin/sendmail/libsm/refill.c 24 Jun 2004 03:59:26 -0000 1.4 +++ gnu/usr.sbin/sendmail/libsm/refill.c 24 Mar 2006 00:50:46 -0000 @@ -76,8 +76,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 */ \ @@ -94,7 +97,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)); \ } Index: gnu/usr.sbin/sendmail/sendmail/collect.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/collect.c,v retrieving revision 1.18 diff -u -p -r1.18 collect.c --- gnu/usr.sbin/sendmail/sendmail/collect.c 16 Dec 2004 00:21:30 -0000 1.18 +++ gnu/usr.sbin/sendmail/sendmail/collect.c 24 Mar 2006 00:50:47 -0000 @@ -15,7 +15,6 @@ SM_RCSID("@(#)$Sendmail: collect.c,v 8.260 2004/11/30 23:29:15 ca Exp $") -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 @@ 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,27 +283,31 @@ collect(fp, smtpmode, hdrp, e, rsetsize) 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 @@ collect(fp, smtpmode, hdrp, e, rsetsize) pbp = peekbuf; istate = IS_BOL; mstate = SaveFrom ? MS_HEADER : MS_UFROM; - CollectProgress = false; /* ** Tell ARPANET to go ahead. @@ -341,32 +339,6 @@ collect(fp, smtpmode, hdrp, e, rsetsize) ** 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 +362,26 @@ collect(fp, smtpmode, hdrp, e, rsetsize) 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 +527,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]; @@ -581,6 +582,7 @@ bufferchar: usrerrenh(e->e_status, "552 Headers too large (%d max)", MaxHeadersLength); + discard: mstate = MS_DISCARD; } } @@ -620,6 +622,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); @@ -629,8 +649,12 @@ nextstate: 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 +720,6 @@ readerr: inputerr = true; } - /* reset global timer */ - if (CollectTimeout != NULL) - sm_clrevent(CollectTimeout); - if (headeronly) return; @@ -785,6 +805,7 @@ readerr: } /* An EOF when running SMTP is an error */ + readabort: if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) { char *host; @@ -807,13 +828,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; @@ -906,39 +928,6 @@ readerr: } } -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. ** Index: gnu/usr.sbin/sendmail/sendmail/conf.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/conf.c,v retrieving revision 1.25 diff -u -p -r1.25 conf.c --- gnu/usr.sbin/sendmail/sendmail/conf.c 12 Jan 2005 18:15:46 -0000 1.25 +++ gnu/usr.sbin/sendmail/sendmail/conf.c 24 Mar 2006 00:50:49 -0000 @@ -5300,8 +5300,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; @@ -5325,11 +5325,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 (;;) { @@ -5371,8 +5368,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; } @@ -5436,8 +5433,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; } /* Index: gnu/usr.sbin/sendmail/sendmail/deliver.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/deliver.c,v retrieving revision 1.25 diff -u -p -r1.25 deliver.c --- gnu/usr.sbin/sendmail/sendmail/deliver.c 12 Jan 2005 18:15:46 -0000 1.25 +++ gnu/usr.sbin/sendmail/sendmail/deliver.c 24 Mar 2006 00:50:51 -0000 @@ -3257,16 +3257,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') { /* @@ -4420,13 +4437,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; @@ -4436,7 +4453,7 @@ putfromline(mci, e) char xbuf[MAXLINE]; if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) - return; + return true; mci->mci_flags |= MCIF_INHEADER; @@ -4477,8 +4494,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. ** @@ -4489,7 +4507,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. @@ -4500,13 +4518,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]; @@ -4536,10 +4556,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; } @@ -4568,26 +4590,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) @@ -4609,8 +4636,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; @@ -4630,7 +4658,8 @@ putbody(mci, e, separator) if (bitset(MCIF_INHEADER, mci->mci_flags)) { - putline("", mci); + if (!putline("", mci)) + goto writeerr; mci->mci_flags &= ~MCIF_INHEADER; } @@ -4721,11 +4750,6 @@ putbody(mci, e, separator) dead = true; continue; } - else - { - /* record progress for DATA timeout */ - DataProgress = true; - } pos++; } for (xp = buf; xp < bp; xp++) @@ -4738,11 +4762,6 @@ putbody(mci, e, separator) dead = true; break; } - else - { - /* record progress for DATA timeout */ - DataProgress = true; - } } if (dead) continue; @@ -4753,11 +4772,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 @@ -4791,11 +4805,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) { @@ -4857,11 +4866,6 @@ putch: dead = true; continue; } - else - { - /* record progress for DATA timeout */ - DataProgress = true; - } pos++; continue; } @@ -4877,11 +4881,6 @@ putch: dead = true; continue; } - else - { - /* record progress for DATA timeout */ - DataProgress = true; - } if (TrafficLogFile != NULL) { @@ -4907,11 +4906,6 @@ putch: mci->mci_mailer->m_eol) == SM_IO_EOF) continue; - else - { - /* record progress for DATA timeout */ - DataProgress = true; - } pos = 0; ostate = OS_HEAD; } @@ -4929,11 +4923,6 @@ putch: dead = true; continue; } - else - { - /* record progress for DATA timeout */ - DataProgress = true; - } pos++; ostate = OS_INLINE; } @@ -4960,11 +4949,6 @@ putch: dead = true; break; } - else - { - /* record progress for DATA timeout */ - DataProgress = true; - } } pos += bp - buf; } @@ -4974,11 +4958,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; } } @@ -4988,6 +4970,7 @@ putch: qid_printqueue(e->e_dfqgrp, e->e_dfqdir), DATAFL_LETTER, e->e_id); ExitStat = EX_IOERR; + ioerr = true; } endofmessage: @@ -5002,23 +4985,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. ** @@ -5549,14 +5544,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 @@ -6114,86 +6109,23 @@ starttls(m, mci, e) 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; Index: gnu/usr.sbin/sendmail/sendmail/headers.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/headers.c,v retrieving revision 1.17 diff -u -p -r1.17 headers.c --- gnu/usr.sbin/sendmail/sendmail/headers.c 16 Dec 2004 00:21:30 -0000 1.17 +++ gnu/usr.sbin/sendmail/sendmail/headers.c 24 Mar 2006 00:50:51 -0000 @@ -18,7 +18,7 @@ SM_RCSID("@(#)$Sendmail: headers.c,v 8.2 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 @@ 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]; @@ -1002,6 +1001,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; @@ -1541,13 +1542,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; @@ -1682,7 +1683,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; } @@ -1741,7 +1743,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; } @@ -1760,7 +1763,8 @@ putheader(mci, hdr, e, flags) } else { - put_vanilla_header(h, p, mci); + if (!put_vanilla_header(h, p, mci)) + goto writeerr; } } @@ -1777,18 +1781,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 @@ -1799,10 +1810,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; @@ -1833,7 +1844,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') @@ -1843,7 +1855,10 @@ put_vanilla_header(h, v, mci) /* 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 @@ 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; @@ -2001,13 +2016,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) @@ -2015,7 +2023,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 obuf); opos = strlen(obp); @@ -2037,8 +2046,12 @@ commaize(h, p, oldstyle, mci, e) *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 ** Index: gnu/usr.sbin/sendmail/sendmail/mime.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/mime.c,v retrieving revision 1.10 diff -u -p -r1.10 mime.c --- gnu/usr.sbin/sendmail/sendmail/mime.c 16 Dec 2004 00:21:31 -0000 1.10 +++ gnu/usr.sbin/sendmail/sendmail/mime.c 24 Mar 2006 00:50:52 -0000 @@ -86,6 +86,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 @@ -298,7 +299,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) @@ -307,8 +309,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); } @@ -319,19 +322,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, 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 @@ 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); } @@ -373,18 +382,21 @@ 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, 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 @@ 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) @@ -492,7 +506,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; @@ -505,12 +520,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) @@ -518,7 +534,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; } @@ -548,7 +565,8 @@ mime8to7(mci, header, e, boundaries, fla *bp++ = Base64Code[c2 & 0x3f]; } *bp = '\0'; - putline(buf, mci); + if (!putline(buf, mci)) + goto writeerr; } else { @@ -571,12 +589,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'; @@ -598,7 +618,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; @@ -627,7 +648,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 == '.') @@ -665,13 +687,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 @@ -958,7 +984,7 @@ static int mime_fromqp __P((unsigned cha ** e -- envelope. ** ** Returns: -** none. +** true iff body was written successfully */ static char index_64[128] = @@ -975,7 +1001,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; @@ -1008,25 +1034,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; /* @@ -1090,7 +1122,8 @@ mime7to8(mci, header, e) 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 @@ 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') { @@ -1144,7 +1180,8 @@ again: 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 @@ 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 Index: gnu/usr.sbin/sendmail/sendmail/parseaddr.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/parseaddr.c,v retrieving revision 1.20 diff -u -p -r1.20 parseaddr.c --- gnu/usr.sbin/sendmail/sendmail/parseaddr.c 16 Dec 2004 00:21:31 -0000 1.20 +++ gnu/usr.sbin/sendmail/sendmail/parseaddr.c 24 Mar 2006 00:50:53 -0000 @@ -1337,7 +1337,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]; @@ -1352,7 +1352,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); @@ -1407,7 +1407,7 @@ rewrite(pvp, ruleset, reclevel, e, maxat { char **hbrvp; char **xpvp; - int trsize; + size_t trsize; char *replac; int endtoken; STAB *map; @@ -1509,7 +1509,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 */ @@ -2936,7 +2936,7 @@ rscheck(rwset, p1, p2, e, flags, logl, h char *logid; { char *volatile buf; - int bufsize; + size_t bufsize; int saveexitstat; int volatile rstat = EX_OK; char **pvp; @@ -3150,7 +3150,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; Index: gnu/usr.sbin/sendmail/sendmail/savemail.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/savemail.c,v retrieving revision 1.12 diff -u -p -r1.12 savemail.c --- gnu/usr.sbin/sendmail/sendmail/savemail.c 16 Dec 2004 00:21:31 -0000 1.12 +++ gnu/usr.sbin/sendmail/sendmail/savemail.c 24 Mar 2006 00:50:53 -0000 @@ -15,7 +15,7 @@ SM_RCSID("@(#)$Sendmail: savemail.c,v 8.304 2004/10/06 21:36:06 ca Exp $") -static void errbody __P((MCI *, ENVELOPE *, char *)); +static bool errbody __P((MCI *, ENVELOPE *, char *)); static bool pruneroute __P((char *)); /* @@ -432,12 +432,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 @@ -732,14 +733,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; @@ -757,14 +758,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; } /* @@ -773,11 +776,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; } /* @@ -799,31 +803,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). @@ -849,17 +858,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; } } @@ -877,21 +888,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) { @@ -899,11 +913,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; @@ -917,25 +932,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; @@ -968,25 +986,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 @@ -995,8 +1016,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 { @@ -1007,11 +1029,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; @@ -1023,11 +1046,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. @@ -1039,13 +1063,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 */ @@ -1059,13 +1085,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)) @@ -1076,7 +1104,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; } /* @@ -1119,7 +1148,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) @@ -1127,7 +1157,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 */ @@ -1176,7 +1207,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 */ @@ -1190,13 +1222,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) @@ -1208,7 +1242,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) @@ -1222,7 +1257,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 */ @@ -1234,7 +1270,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 */ @@ -1243,7 +1280,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)) @@ -1255,7 +1293,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; } } } @@ -1265,7 +1304,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) && @@ -1273,21 +1313,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); @@ -1301,43 +1347,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 ** Index: gnu/usr.sbin/sendmail/sendmail/sendmail.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/sendmail.h,v retrieving revision 1.23 diff -u -p -r1.23 sendmail.h --- gnu/usr.sbin/sendmail/sendmail/sendmail.h 16 Dec 2004 00:21:31 -0000 1.23 +++ gnu/usr.sbin/sendmail/sendmail/sendmail.h 24 Mar 2006 00:50:54 -0000 @@ -808,13 +808,13 @@ 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 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)); /* @@ -869,9 +869,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 */ @@ -964,8 +964,8 @@ extern void dropenvelope __P((ENVELOPE * 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. @@ -1649,7 +1649,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)); /* @@ -2144,7 +2144,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 */ @@ -2518,8 +2517,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)); Index: gnu/usr.sbin/sendmail/sendmail/sfsasl.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/sfsasl.c,v retrieving revision 1.17 diff -u -p -r1.17 sfsasl.c --- gnu/usr.sbin/sendmail/sendmail/sfsasl.c 12 Jan 2005 18:15:46 -0000 1.17 +++ gnu/usr.sbin/sendmail/sendmail/sfsasl.c 24 Mar 2006 00:50:55 -0000 @@ -541,6 +541,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: @@ -561,38 +680,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; @@ -625,15 +748,22 @@ tls_read(fp, buf, size) 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; @@ -660,36 +790,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"; @@ -722,15 +855,22 @@ tls_write(fp, buf, size) 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; Index: gnu/usr.sbin/sendmail/sendmail/sfsasl.h =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/sfsasl.h,v retrieving revision 1.4 diff -u -p -r1.4 sfsasl.h --- gnu/usr.sbin/sendmail/sendmail/sfsasl.h 11 Sep 2001 19:02:50 -0000 1.4 +++ gnu/usr.sbin/sendmail/sendmail/sfsasl.h 24 Mar 2006 00:50:55 -0000 @@ -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 */ Index: gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c,v retrieving revision 1.22 diff -u -p -r1.22 srvrsmtp.c --- gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c 16 Dec 2004 00:21:31 -0000 1.22 +++ gnu/usr.sbin/sendmail/sendmail/srvrsmtp.c 24 Mar 2006 00:50:56 -0000 @@ -503,7 +503,6 @@ smtp(nullserver, d_flags, e) #endif /* SASL */ int r; #if STARTTLS - int fdfl; int rfd, wfd; volatile bool tls_active = false; volatile bool smtps = bitnset(D_SMTPS, d_flags); @@ -1693,97 +1692,26 @@ smtp(nullserver, d_flags, e) # 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; + int i, 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; - } - - 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; - - 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; @@ -1797,9 +1725,6 @@ tlsfail: e->e_sendqueue = NULL; 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, Index: gnu/usr.sbin/sendmail/sendmail/usersmtp.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/usersmtp.c,v retrieving revision 1.18 diff -u -p -r1.18 usersmtp.c --- gnu/usr.sbin/sendmail/sendmail/usersmtp.c 12 Jan 2005 18:15:46 -0000 1.18 +++ gnu/usr.sbin/sendmail/sendmail/usersmtp.c 24 Mar 2006 00:50:57 -0000 @@ -18,7 +18,6 @@ SM_RCSID("@(#)$Sendmail: usersmtp.c,v 8. #include -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 *)); @@ -2492,9 +2491,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; @@ -2630,43 +2626,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)) { @@ -2674,14 +2649,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 } @@ -2721,7 +2695,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); @@ -2772,51 +2748,27 @@ smtpdata(m, mci, e, ctladdr, xstart) 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 ** Index: gnu/usr.sbin/sendmail/sendmail/util.c =================================================================== RCS file: /cvs/src/gnu/usr.sbin/sendmail/sendmail/util.c,v retrieving revision 1.17 diff -u -p -r1.17 util.c --- gnu/usr.sbin/sendmail/sendmail/util.c 16 Dec 2004 00:21:31 -0000 1.17 +++ gnu/usr.sbin/sendmail/sendmail/util.c 24 Mar 2006 00:50:57 -0000 @@ -456,6 +456,8 @@ xalloc(sz) { register char *p; + SM_REQUIRE(sz >= 0); + /* some systems can't handle size zero mallocs */ if (sz <= 0) sz = 1; @@ -970,18 +972,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. @@ -1000,13 +1002,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; @@ -1058,11 +1060,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, '.'); @@ -1075,11 +1072,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, @@ -1091,16 +1083,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; @@ -1116,11 +1103,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++) @@ -1144,11 +1126,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, @@ -1161,11 +1141,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, @@ -1183,11 +1161,6 @@ putxline(l, len, mci, pxflags) dead = true; break; } - else - { - /* record progress for DATA timeout */ - DataProgress = true; - } } if (dead) break; @@ -1198,11 +1171,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') { @@ -1211,11 +1182,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) @@ -1224,10 +1193,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. ** @@ -2433,6 +2402,7 @@ str2prt(s) *h++ = 'r'; break; default: + SM_ASSERT(l >= 2); (void) sm_snprintf(h, l, "%03o", (unsigned int)((unsigned char) c));