diff options
Diffstat (limited to 'contrib/sendmail/src/srvrsmtp.c')
-rw-r--r-- | contrib/sendmail/src/srvrsmtp.c | 251 |
1 files changed, 149 insertions, 102 deletions
diff --git a/contrib/sendmail/src/srvrsmtp.c b/contrib/sendmail/src/srvrsmtp.c index bfa2872..e5cfdcf 100644 --- a/contrib/sendmail/src/srvrsmtp.c +++ b/contrib/sendmail/src/srvrsmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers. + * Copyright (c) 1998-2006 Sendmail, Inc. and its suppliers. * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 @@ -17,9 +17,9 @@ # include <libmilter/mfdef.h> #endif /* MILTER */ -SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.906 2005/03/16 00:36:09 ca Exp $") +SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.922 2006/02/28 00:42:13 ca Exp $") -#include <sys/time.h> +#include <sm/time.h> #include <sm/fdset.h> #if SASL || STARTTLS @@ -36,6 +36,9 @@ static SSL_CTX *srv_ctx = NULL; /* TLS server context */ static SSL *srv_ssl = NULL; /* per connection context */ static bool tls_ok_srv = false; +#if _FFR_DM_ONE +static bool NotFirstDelivery = false; +#endif /* _FFR_DM_ONE */ extern void tls_set_verify __P((SSL_CTX *, SSL *, bool)); # define TLS_VERIFY_CLIENT() tls_set_verify(srv_ctx, srv_ssl, \ @@ -221,9 +224,6 @@ static char *CurSmtpClient; /* who's at the other end of channel */ #ifndef MAXBADCOMMANDS # define MAXBADCOMMANDS 25 /* maximum number of bad commands */ #endif /* ! MAXBADCOMMANDS */ -#ifndef MAXNOOPCOMMANDS -# define MAXNOOPCOMMANDS 20 /* max "noise" commands before slowdown */ -#endif /* ! MAXNOOPCOMMANDS */ #ifndef MAXHELOCOMMANDS # define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */ #endif /* ! MAXHELOCOMMANDS */ @@ -292,6 +292,24 @@ static bool smtp_data __P((SMTP_T *, ENVELOPE *)); \ switch (state) \ { \ + case SMFIR_SHUTDOWN: \ + if (MilterLogLevel > 3) \ + { \ + sm_syslog(LOG_INFO, e->e_id, \ + "Milter: %s=%s, reject=421, errormode=4", \ + str, addr); \ + LogUsrErrs = false; \ + } \ + { \ + bool tsave = QuickAbort; \ + \ + QuickAbort = false; \ + usrerr("421 4.3.0 closing connection"); \ + QuickAbort = tsave; \ + e->e_sendqueue = NULL; \ + goto doquit; \ + } \ + break; \ case SMFIR_REPLYCODE: \ if (MilterLogLevel > 3) \ { \ @@ -300,7 +318,8 @@ static bool smtp_data __P((SMTP_T *, ENVELOPE *)); str, addr, response); \ LogUsrErrs = false; \ } \ - if (strncmp(response, "421 ", 4) == 0) \ + if (strncmp(response, "421 ", 4) == 0 \ + || strncmp(response, "421-", 4) == 0) \ { \ bool tsave = QuickAbort; \ \ @@ -504,7 +523,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); @@ -810,6 +828,19 @@ smtp(nullserver, d_flags, e) tempfail = true; smtp.sm_milterize = false; break; + + case SMFIR_SHUTDOWN: + if (MilterLogLevel > 3) + sm_syslog(LOG_INFO, e->e_id, + "Milter: initialization failed, closing connection"); + tempfail = true; + smtp.sm_milterize = false; + message("421 4.7.0 %s closing connection", + MyHostName); + + /* arrange to ignore send list */ + e->e_sendqueue = NULL; + goto doquit; } } @@ -896,6 +927,9 @@ smtp(nullserver, d_flags, e) int fd; fd_set readfds; struct timeval timeout; +#if _FFR_LOG_GREET_PAUSE + struct timeval bp, ep, tp; /* {begin,end,total}pause */ +#endif /* _FFR_LOG_GREET_PAUSE */ /* pause for a moment */ timeout.tv_sec = msecs / 1000; @@ -912,16 +946,32 @@ smtp(nullserver, d_flags, e) fd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); FD_ZERO(&readfds); SM_FD_SET(fd, &readfds); +#if _FFR_LOG_GREET_PAUSE + gettimeofday(&bp, NULL); +#endif /* _FFR_LOG_GREET_PAUSE */ if (select(fd + 1, FDSET_CAST &readfds, NULL, NULL, &timeout) > 0 && FD_ISSET(fd, &readfds)) { +#if _FFR_LOG_GREET_PAUSE + gettimeofday(&ep, NULL); + timersub(&ep, &bp, &tp); +#endif /* _FFR_LOG_GREET_PAUSE */ greetcode = "554"; nullserver = "Command rejected"; sm_syslog(LOG_INFO, e->e_id, +#if _FFR_LOG_GREET_PAUSE + "rejecting commands from %s [%s] after %d seconds due to pre-greeting traffic", +#else /* _FFR_LOG_GREET_PAUSE */ "rejecting commands from %s [%s] due to pre-greeting traffic", +#endif /* _FFR_LOG_GREET_PAUSE */ peerhostname, - anynet_ntoa(&RealHostAddr)); + anynet_ntoa(&RealHostAddr) +#if _FFR_LOG_GREET_PAUSE + , (int) tp.tv_sec + + (tp.tv_usec >= 500000 ? 1 : 0) +#endif /* _FFR_LOG_GREET_PAUSE */ + ); } } } @@ -1693,97 +1743,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; @@ -1798,9 +1777,6 @@ tlsfail: 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, @@ -1998,10 +1974,8 @@ tlsfail: q = "accepting invalid domain name"; } - if (gothello) - { + if (gothello || smtp.sm_gotmail) CLEAR_STATE(cmdbuf); - } #if MILTER if (smtp.sm_milterlist && smtp.sm_milterize && @@ -2039,6 +2013,19 @@ tlsfail: tempfail = true; smtp.sm_milterize = false; break; + + case SMFIR_SHUTDOWN: + if (MilterLogLevel > 3) + sm_syslog(LOG_INFO, e->e_id, + "Milter: Milter: helo=%s, reject=421 4.7.0 %s closing connection", + p, MyHostName); + tempfail = true; + smtp.sm_milterize = false; + message("421 4.7.0 %s closing connection", + MyHostName); + /* arrange to ignore send list */ + e->e_sendqueue = NULL; + goto doquit; } if (response != NULL) sm_free(response); @@ -2475,7 +2462,11 @@ tlsfail: goto rcpt_done; } - if (e->e_sendmode != SM_DELIVER) + if (e->e_sendmode != SM_DELIVER +#if _FFR_DM_ONE + && (NotFirstDelivery || SM_DM_ONE != e->e_sendmode) +#endif /* _FFR_DM_ONE */ + ) e->e_flags |= EF_VRFYONLY; #if MILTER @@ -2900,7 +2891,7 @@ tlsfail: case CMDNOOP: /* noop -- do nothing */ DELAY_CONN("NOOP"); - STOP_IF_ATTACK(checksmtpattack(&n_noop, MAXNOOPCOMMANDS, + STOP_IF_ATTACK(checksmtpattack(&n_noop, MaxNOOPCommands, true, "NOOP", e)); message("250 2.0.0 OK"); break; @@ -2974,6 +2965,9 @@ doquit: finis(true, true, ExitStat); /* NOTREACHED */ + /* just to avoid bogus warning from some compilers */ + exit(EX_OSERR); + case CMDVERB: /* set verbose mode */ DELAY_CONN("VERB"); if (!bitset(SRV_OFFER_EXPN, features) || @@ -2983,7 +2977,7 @@ doquit: message("502 5.7.0 Verbose unavailable"); break; } - STOP_IF_ATTACK(checksmtpattack(&n_noop, MAXNOOPCOMMANDS, + STOP_IF_ATTACK(checksmtpattack(&n_noop, MaxNOOPCommands, true, "VERB", e)); Verbose = 1; set_delivery_mode(SM_DELIVER, e); @@ -3044,7 +3038,8 @@ doquit: MILTER_REPLY("unknown"); if (state == SMFIR_REPLYCODE || state == SMFIR_REJECT || - state == SMFIR_TEMPFAIL) + state == SMFIR_TEMPFAIL || + state == SMFIR_SHUTDOWN) { /* MILTER_REPLY already gave an error */ break; @@ -3111,6 +3106,7 @@ smtp_data(smtp, e) char *id; char *oldid; char buf[32]; + bool rv = true; SmtpPhase = "server DATA"; if (!smtp->sm_gotmail) @@ -3149,7 +3145,8 @@ smtp_data(smtp, e) LogUsrErrs = false; } usrerr(response); - if (strncmp(response, "421 ", 4) == 0) + if (strncmp(response, "421 ", 4) == 0 + || strncmp(response, "421-", 4) == 0) { e->e_sendqueue = NULL; return false; @@ -3183,6 +3180,18 @@ smtp_data(smtp, e) } usrerr(MSG_TEMPFAIL); return true; + + case SMFIR_SHUTDOWN: + if (MilterLogLevel > 3) + { + sm_syslog(LOG_INFO, e->e_id, + "Milter: cmd=data, reject=421 4.7.0 %s closing connection", + MyHostName); + LogUsrErrs = false; + } + usrerr("421 4.7.0 %s closing connection", MyHostName); + e->e_sendqueue = NULL; + return false; } LogUsrErrs = savelogusrerrs; if (response != NULL) @@ -3273,6 +3282,16 @@ smtp_data(smtp, e) milteraccept = false; usrerr(MSG_TEMPFAIL); break; + + case SMFIR_SHUTDOWN: + if (MilterLogLevel > 3) + sm_syslog(LOG_INFO, e->e_id, + "Milter: data, reject=421 4.7.0 %s closing connection", + MyHostName); + milteraccept = false; + usrerr("421 4.7.0 %s closing connection", MyHostName); + rv = false; + break; } if (response != NULL) sm_free(response); @@ -3451,8 +3470,26 @@ smtp_data(smtp, e) } else { + int mode; + /* send to all recipients */ - sendall(ee, SM_DEFAULT); + mode = SM_DEFAULT; +#if _FFR_DM_ONE + if (SM_DM_ONE == e->e_sendmode) + { + if (NotFirstDelivery) + { + mode = SM_QUEUE; + e->e_sendmode = SM_QUEUE; + } + else + { + mode = SM_FORK; + NotFirstDelivery = true; + } + } +#endif /* _FFR_DM_ONE */ + sendall(ee, mode); } ee->e_to = NULL; } @@ -3462,6 +3499,16 @@ smtp_data(smtp, e) CurEnv->e_id = id; /* issue success message */ +#if _FFR_MSG_ACCEPT + if (MessageAccept != NULL && *MessageAccept != '\0') + { + char msg[MAXLINE]; + + expand(MessageAccept, msg, sizeof msg, e); + message("250 2.0.0 %s", msg); + } + else +#endif /* _FFR_MSG_ACCEPT */ message("250 2.0.0 %s Message accepted for delivery", id); CurEnv->e_id = oldid; @@ -3566,7 +3613,7 @@ smtp_data(smtp, e) macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), e->e_quarmsg); } - return true; + return rv; } /* ** LOGUNDELRCPTS -- log undelivered (or all) recipients. |