summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/src/srvrsmtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sendmail/src/srvrsmtp.c')
-rw-r--r--contrib/sendmail/src/srvrsmtp.c663
1 files changed, 429 insertions, 234 deletions
diff --git a/contrib/sendmail/src/srvrsmtp.c b/contrib/sendmail/src/srvrsmtp.c
index d95b5a5..1f067b1 100644
--- a/contrib/sendmail/src/srvrsmtp.c
+++ b/contrib/sendmail/src/srvrsmtp.c
@@ -17,7 +17,7 @@
# include <libmilter/mfdef.h>
#endif /* MILTER */
-SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.924.2.5 2006/07/07 16:29:39 ca Exp $")
+SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.960 2007/02/07 20:18:47 ca Exp $")
#include <sm/time.h>
#include <sm/fdset.h>
@@ -36,15 +36,15 @@ 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, \
bitset(SRV_VRFY_CLT, features))
#endif /* STARTTLS */
+#if _FFR_DM_ONE
+static bool NotFirstDelivery = false;
+#endif /* _FFR_DM_ONE */
+
/* server features */
#define SRV_NONE 0x0000 /* none... */
#define SRV_OFFER_TLS 0x0001 /* offer STARTTLS */
@@ -70,10 +70,7 @@ static unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int));
#define STOP_ATTACK ((time_t) -1)
static time_t checksmtpattack __P((volatile unsigned int *, unsigned int,
bool, char *, ENVELOPE *));
-static void mail_esmtp_args __P((char *, char *, ENVELOPE *, unsigned int));
static void printvrfyaddr __P((ADDRESS *, bool, bool));
-static void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *,
- unsigned int));
static char *skipword __P((char *volatile, char *));
static void setup_smtpd_io __P((void));
@@ -115,7 +112,7 @@ extern ENVELOPE BlankEnvelope;
do \
{ \
char buf[16]; \
- (void) sm_snprintf(buf, sizeof buf, "%d", \
+ (void) sm_snprintf(buf, sizeof(buf), "%d", \
BadRcptThrottle > 0 && n_badrcpts > BadRcptThrottle \
? n_badrcpts - 1 : n_badrcpts); \
macdefine(&e->e_macro, A_TEMP, macid("{nbadrcpts}"), buf); \
@@ -125,6 +122,88 @@ extern ENVELOPE BlankEnvelope;
(s)++
/*
+** PARSE_ESMTP_ARGS -- parse EMSTP arguments (for MAIL, RCPT)
+**
+** Parameters:
+** e -- the envelope
+** addr_st -- address (RCPT only)
+** p -- read buffer
+** delimptr -- current position in read buffer
+** which -- MAIL/RCPT
+** args -- arguments (output)
+** esmtp_args -- function to process a single ESMTP argument
+**
+** Returns:
+** none
+*/
+
+void
+parse_esmtp_args(e, addr_st, p, delimptr, which, args, esmtp_args)
+ ENVELOPE *e;
+ ADDRESS *addr_st;
+ char *p;
+ char *delimptr;
+ char *which;
+ char *args[];
+ esmtp_args_F esmtp_args;
+{
+ int argno;
+
+ argno = 0;
+ if (args != NULL)
+ args[argno++] = p;
+ p = delimptr;
+ while (p != NULL && *p != '\0')
+ {
+ char *kp;
+ char *vp = NULL;
+ char *equal = NULL;
+
+ /* locate the beginning of the keyword */
+ SKIP_SPACE(p);
+ if (*p == '\0')
+ break;
+ kp = p;
+
+ /* skip to the value portion */
+ while ((isascii(*p) && isalnum(*p)) || *p == '-')
+ p++;
+ if (*p == '=')
+ {
+ equal = p;
+ *p++ = '\0';
+ vp = p;
+
+ /* skip to the end of the value */
+ while (*p != '\0' && *p != ' ' &&
+ !(isascii(*p) && iscntrl(*p)) &&
+ *p != '=')
+ p++;
+ }
+
+ if (*p != '\0')
+ *p++ = '\0';
+
+ if (tTd(19, 1))
+ sm_dprintf("%s: got arg %s=\"%s\"\n", which, kp,
+ vp == NULL ? "<null>" : vp);
+
+ esmtp_args(addr_st, kp, vp, e);
+ if (equal != NULL)
+ *equal = '=';
+ if (args != NULL)
+ args[argno] = kp;
+ argno++;
+ if (argno >= MAXSMTPARGS - 1)
+ usrerr("501 5.5.4 Too many parameters");
+ if (Errors > 0)
+ break;
+ }
+ if (args != NULL)
+ args[argno] = NULL;
+}
+
+/*
** SMTP -- run the SMTP protocol.
**
** Parameters:
@@ -291,6 +370,7 @@ static bool smtp_data __P((SMTP_T *, ENVELOPE *));
{ \
int savelogusrerrs = LogUsrErrs; \
\
+ milter_cmd_fail = true; \
switch (state) \
{ \
case SMFIR_SHUTDOWN: \
@@ -351,6 +431,7 @@ static bool smtp_data __P((SMTP_T *, ENVELOPE *));
"Milter: %s=%s, discard", \
str, addr); \
e->e_flags |= EF_DISCARD; \
+ milter_cmd_fail = false; \
break; \
\
case SMFIR_TEMPFAIL: \
@@ -363,6 +444,9 @@ static bool smtp_data __P((SMTP_T *, ENVELOPE *));
} \
usrerr(MSG_TEMPFAIL); \
break; \
+ default: \
+ milter_cmd_fail = false; \
+ break; \
} \
LogUsrErrs = savelogusrerrs; \
if (response != NULL) \
@@ -402,6 +486,7 @@ do \
sm_rpool_free(e->e_rpool); \
e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL)); \
CurEnv = e; \
+ e->e_features = features; \
\
/* put back discard bit */ \
if (smtp.sm_discard) \
@@ -448,6 +533,7 @@ do \
qid_printname(e), CurSmtpClient, inp); \
}
+static bool SevenBitInput_Saved; /* saved version of SevenBitInput */
void
smtp(nullserver, d_flags, e)
@@ -473,11 +559,8 @@ smtp(nullserver, d_flags, e)
volatile unsigned int n_etrn = 0; /* count of ETRN */
volatile unsigned int n_noop = 0; /* count of NOOP/VERB/etc */
volatile unsigned int n_helo = 0; /* count of HELO/EHLO */
- volatile int save_sevenbitinput;
bool ok;
-#if _FFR_BLOCK_PROXIES
volatile bool first;
-#endif /* _FFR_BLOCK_PROXIES */
volatile bool tempfail = false;
volatile time_t wt; /* timeout after too many commands */
volatile time_t previous; /* time after checksmtpattack() */
@@ -488,9 +571,11 @@ smtp(nullserver, d_flags, e)
char *greetcode = "220";
char *hostname; /* my hostname ($j) */
QUEUE_CHAR *new;
- int argno;
char *args[MAXSMTPARGS];
- char inp[MAXLINE];
+ char inp[MAXINPLINE];
+#if MAXINPLINE < MAXLINE
+ ERROR _MAXINPLINE must NOT be less than _MAXLINE: MAXINPLINE < MAXLINE
+#endif /* MAXINPLINE < MAXLINE */
char cmdbuf[MAXLINE];
#if SASL
sasl_conn_t *conn;
@@ -502,7 +587,7 @@ smtp(nullserver, d_flags, e)
char *user;
char *in, *out2;
# if SASL >= 20000
- char *auth_id;
+ char *auth_id = NULL;
const char *out;
sasl_ssf_t ext_ssf;
char localip[60], remoteip[60];
@@ -521,6 +606,7 @@ smtp(nullserver, d_flags, e)
char *mechlist;
volatile unsigned int n_mechs;
unsigned int len;
+#else /* SASL */
#endif /* SASL */
int r;
#if STARTTLS
@@ -538,12 +624,22 @@ smtp(nullserver, d_flags, e)
# endif /* _FFR_NO_PIPE */
#endif /* PIPELINING */
volatile time_t log_delay = (time_t) 0;
+#if MILTER
+ volatile bool milter_cmd_done, milter_cmd_safe;
+ volatile bool milter_rcpt_added, milter_cmd_fail;
+ ADDRESS addr_st;
+# define p_addr_st &addr_st
+#else /* MILTER */
+# define p_addr_st NULL
+#endif /* MILTER */
+ size_t inplen;
- save_sevenbitinput = SevenBitInput;
+ SevenBitInput_Saved = SevenBitInput;
smtp.sm_nrcpts = 0;
#if MILTER
smtp.sm_milterize = (nullserver == NULL);
smtp.sm_milterlist = false;
+ addr = NULL;
#endif /* MILTER */
/* setup I/O fd correctly for the SMTP server */
@@ -641,6 +737,7 @@ smtp(nullserver, d_flags, e)
goto doquit;
}
+ e->e_features = features;
hostname = macvalue('j', e);
#if SASL
if (AuthRealm == NULL)
@@ -704,7 +801,7 @@ smtp(nullserver, d_flags, e)
&addrsize) == 0)
{
if (iptostring(&saddr_r, addrsize,
- remoteip, sizeof remoteip))
+ remoteip, sizeof(remoteip)))
{
sasl_setprop(conn, SASL_IPREMOTEPORT,
remoteip);
@@ -718,7 +815,7 @@ smtp(nullserver, d_flags, e)
{
if (iptostring(&saddr_l, addrsize,
localip,
- sizeof localip))
+ sizeof(localip)))
{
sasl_setprop(conn,
SASL_IPLOCALPORT,
@@ -764,7 +861,7 @@ smtp(nullserver, d_flags, e)
# endif /* 0 */
/* set properties */
- (void) memset(&ssp, '\0', sizeof ssp);
+ (void) memset(&ssp, '\0', sizeof(ssp));
/* XXX should these be options settable via .cf ? */
/* ssp.min_ssf = 0; is default due to memset() */
@@ -852,7 +949,9 @@ smtp(nullserver, d_flags, e)
char *response;
q = macvalue(macid("{client_name}"), e);
- SM_ASSERT(q != NULL);
+ SM_ASSERT(q != NULL || OpMode == MD_SMTP);
+ if (q == NULL)
+ q = "localhost";
response = milter_connect(q, RealHostAddr, e, &state);
switch (state)
{
@@ -907,7 +1006,7 @@ smtp(nullserver, d_flags, e)
#if STARTTLS
!smtps &&
#endif /* STARTTLS */
- *greetcode == '2')
+ *greetcode == '2' && nullserver == NULL)
{
time_t msecs = 0;
char **pvp;
@@ -929,9 +1028,8 @@ 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 */
+ int eoftest;
/* pause for a moment */
timeout.tv_sec = msecs / 1000;
@@ -948,31 +1046,25 @@ 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))
+ FD_ISSET(fd, &readfds) &&
+ (eoftest = sm_io_getc(InChannel, SM_TIME_DEFAULT))
+ != SM_IO_EOF)
{
-#if _FFR_LOG_GREET_PAUSE
+ sm_io_ungetc(InChannel, SM_TIME_DEFAULT,
+ eoftest);
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 */
+ "rejecting commands from %s [%s] due to pre-greeting traffic after %d seconds",
peerhostname,
- anynet_ntoa(&RealHostAddr)
-#if _FFR_LOG_GREET_PAUSE
- , (int) tp.tv_sec +
+ anynet_ntoa(&RealHostAddr),
+ (int) tp.tv_sec +
(tp.tv_usec >= 500000 ? 1 : 0)
-#endif /* _FFR_LOG_GREET_PAUSE */
);
}
}
@@ -992,10 +1084,10 @@ smtp(nullserver, d_flags, e)
/* output the first line, inserting "ESMTP" as second word */
if (*greetcode == '5')
- (void) sm_snprintf(inp, sizeof inp, "%s not accepting messages",
- hostname);
+ (void) sm_snprintf(inp, sizeof(inp),
+ "%s not accepting messages", hostname);
else
- expand(SmtpGreeting, inp, sizeof inp, e);
+ expand(SmtpGreeting, inp, sizeof(inp), e);
p = strchr(inp, '\n');
if (p != NULL)
@@ -1004,10 +1096,10 @@ smtp(nullserver, d_flags, e)
if (id == NULL)
id = &inp[strlen(inp)];
if (p == NULL)
- (void) sm_snprintf(cmdbuf, sizeof cmdbuf,
+ (void) sm_snprintf(cmdbuf, sizeof(cmdbuf),
"%s %%.*s ESMTP%%s", greetcode);
else
- (void) sm_snprintf(cmdbuf, sizeof cmdbuf,
+ (void) sm_snprintf(cmdbuf, sizeof(cmdbuf),
"%s-%%.*s ESMTP%%s", greetcode);
message(cmdbuf, (int) (id - inp), inp, id);
@@ -1017,14 +1109,14 @@ smtp(nullserver, d_flags, e)
*p++ = '\0';
if (isascii(*id) && isspace(*id))
id++;
- (void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, "-%s");
+ (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, "-%s");
message(cmdbuf, id);
}
if (id != NULL)
{
if (isascii(*id) && isspace(*id))
id++;
- (void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, " %s");
+ (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, " %s");
message(cmdbuf, id);
}
@@ -1040,9 +1132,7 @@ smtp(nullserver, d_flags, e)
/* sendinghost's storage must outlive the current envelope */
if (sendinghost != NULL)
sendinghost = sm_strdup_x(sendinghost);
-#if _FFR_BLOCK_PROXIES
first = true;
-#endif /* _FFR_BLOCK_PROXIES */
gothello = false;
smtp.sm_gotmail = false;
for (;;)
@@ -1055,6 +1145,9 @@ smtp(nullserver, d_flags, e)
LogUsrErrs = false;
OnlyOneError = true;
e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
+#if MILTER
+ milter_cmd_fail = false;
+#endif /* MILTER */
/* setup for the read */
e->e_to = NULL;
@@ -1065,16 +1158,10 @@ smtp(nullserver, d_flags, e)
/* read the input line */
SmtpPhase = "server cmd read";
sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient);
-#if SASL
- /*
- ** XXX SMTP AUTH requires accepting any length,
- ** at least for challenge/response
- */
-#endif /* SASL */
/* handle errors */
if (sm_io_error(OutChannel) ||
- (p = sfgets(inp, sizeof inp, InChannel,
+ (p = sfgets(inp, sizeof(inp), InChannel,
TimeOuts.to_nextcommand, SmtpPhase)) == NULL)
{
char *d;
@@ -1107,16 +1194,36 @@ smtp(nullserver, d_flags, e)
goto doquit;
}
-#if _FFR_BLOCK_PROXIES
+ /* also used by "proxy" check below */
+ inplen = strlen(inp);
+#if SASL
+ /*
+ ** SMTP AUTH requires accepting any length,
+ ** at least for challenge/response. However, not imposing
+ ** a limit is a bad idea (denial of service).
+ */
+
+ if (authenticating != SASL_PROC_AUTH
+ && sm_strncasecmp(inp, "AUTH ", 5) != 0
+ && inplen > MAXLINE)
+ {
+ message("421 4.7.0 %s Command too long, possible attack %s",
+ MyHostName, CurSmtpClient);
+ sm_syslog(LOG_INFO, e->e_id,
+ "%s: SMTP violation, input too long: %lu",
+ CurSmtpClient, (unsigned long) inplen);
+ goto doquit;
+ }
+#endif /* SASL */
+
if (first)
{
- size_t inplen, cmdlen;
+ size_t cmdlen;
int idx;
char *http_cmd;
static char *http_cmds[] = { "GET", "POST",
"CONNECT", "USER", NULL };
- inplen = strlen(inp);
for (idx = 0; (http_cmd = http_cmds[idx]) != NULL;
idx++)
{
@@ -1136,7 +1243,6 @@ smtp(nullserver, d_flags, e)
}
first = false;
}
-#endif /* _FFR_BLOCK_PROXIES */
/* clean up end of line */
fixcrlf(inp, true);
@@ -1270,7 +1376,7 @@ smtp(nullserver, d_flags, e)
{
char pbuf[8];
- (void) sm_snprintf(pbuf, sizeof pbuf,
+ (void) sm_snprintf(pbuf, sizeof(pbuf),
"%u", *ssf);
macdefine(&BlankEnvelope.e_macro,
A_TEMP,
@@ -1386,7 +1492,7 @@ smtp(nullserver, d_flags, e)
cmd = cmdbuf;
while (*p != '\0' &&
!(isascii(*p) && isspace(*p)) &&
- cmd < &cmdbuf[sizeof cmdbuf - 2])
+ cmd < &cmdbuf[sizeof(cmdbuf) - 2])
*cmd++ = *p++;
*cmd = '\0';
@@ -1801,7 +1907,7 @@ smtp(nullserver, d_flags, e)
macvalue(macid("{verify}"), e),
"STARTTLS", e,
RSF_RMCOMM|RSF_COUNT,
- 5, NULL, NOQID) != EX_OK ||
+ 5, NULL, NOQID, NULL) != EX_OK ||
Errors > 0)
{
extern char MsgBuf[];
@@ -1992,15 +2098,6 @@ smtp(nullserver, d_flags, e)
response = milter_helo(p, e, &state);
switch (state)
{
- case SMFIR_REPLYCODE:
- if (MilterLogLevel > 3)
- sm_syslog(LOG_INFO, e->e_id,
- "Milter: helo=%s, reject=%s",
- p, response);
- nullserver = newstr(response);
- smtp.sm_milterize = false;
- break;
-
case SMFIR_REJECT:
if (MilterLogLevel > 3)
sm_syslog(LOG_INFO, e->e_id,
@@ -2019,17 +2116,36 @@ smtp(nullserver, d_flags, e)
smtp.sm_milterize = false;
break;
- case SMFIR_SHUTDOWN:
+ case SMFIR_REPLYCODE:
if (MilterLogLevel > 3)
sm_syslog(LOG_INFO, e->e_id,
+ "Milter: helo=%s, reject=%s",
+ p, response);
+ if (strncmp(response, "421 ", 4) != 0
+ && strncmp(response, "421-", 4) != 0)
+ {
+ nullserver = newstr(response);
+ smtp.sm_milterize = false;
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case SMFIR_SHUTDOWN:
+ if (MilterLogLevel > 3 &&
+ response == NULL)
+ sm_syslog(LOG_INFO, e->e_id,
"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);
+ if (response != NULL)
+ usrerr(response);
+ else
+ message("421 4.7.0 %s closing connection",
+ MyHostName);
/* arrange to ignore send list */
e->e_sendqueue = NULL;
+ lognullconnection = false;
goto doquit;
}
if (response != NULL)
@@ -2258,59 +2374,13 @@ smtp(nullserver, d_flags, e)
}
/* reset to default value */
- SevenBitInput = save_sevenbitinput;
+ SevenBitInput = SevenBitInput_Saved;
/* now parse ESMTP arguments */
e->e_msgsize = 0;
addr = p;
- argno = 0;
- args[argno++] = p;
- p = delimptr;
- while (p != NULL && *p != '\0')
- {
- char *kp;
- char *vp = NULL;
- char *equal = NULL;
-
- /* locate the beginning of the keyword */
- SKIP_SPACE(p);
- if (*p == '\0')
- break;
- kp = p;
-
- /* skip to the value portion */
- while ((isascii(*p) && isalnum(*p)) || *p == '-')
- p++;
- if (*p == '=')
- {
- equal = p;
- *p++ = '\0';
- vp = p;
-
- /* skip to the end of the value */
- while (*p != '\0' && *p != ' ' &&
- !(isascii(*p) && iscntrl(*p)) &&
- *p != '=')
- p++;
- }
-
- if (*p != '\0')
- *p++ = '\0';
-
- if (tTd(19, 1))
- sm_dprintf("MAIL: got arg %s=\"%s\"\n", kp,
- vp == NULL ? "<null>" : vp);
-
- mail_esmtp_args(kp, vp, e, features);
- if (equal != NULL)
- *equal = '=';
- args[argno++] = kp;
- if (argno >= MAXSMTPARGS - 1)
- usrerr("501 5.5.4 Too many parameters");
- if (Errors > 0)
- sm_exc_raisenew_x(&EtypeQuickAbort, 1);
- }
- args[argno] = NULL;
+ parse_esmtp_args(e, NULL, p, delimptr, "MAIL", args,
+ mail_esmtp_args);
if (Errors > 0)
sm_exc_raisenew_x(&EtypeQuickAbort, 1);
@@ -2344,7 +2414,7 @@ smtp(nullserver, d_flags, e)
#endif /* _FFR_MAIL_MACRO */
if (rscheck("check_mail", addr,
NULL, e, RSF_RMCOMM|RSF_COUNT, 3,
- NULL, e->e_id) != EX_OK ||
+ NULL, e->e_id, NULL) != EX_OK ||
Errors > 0)
sm_exc_raisenew_x(&EtypeQuickAbort, 1);
macdefine(&e->e_macro, A_PERM,
@@ -2423,6 +2493,17 @@ smtp(nullserver, d_flags, e)
case CMDRCPT: /* rcpt -- designate recipient */
DELAY_CONN("RCPT");
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_mailer}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_host}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"), NULL);
+#if MILTER
+ (void) memset(&addr_st, '\0', sizeof(addr_st));
+ a = NULL;
+ milter_rcpt_added = false;
+#endif
if (BadRcptThrottle > 0 &&
n_badrcpts >= BadRcptThrottle)
{
@@ -2476,16 +2557,16 @@ smtp(nullserver, d_flags, e)
#if MILTER
/*
- ** If the filter will be deleting recipients,
- ** don't expand them at RCPT time (in the call
+ ** Do not expand recipients at RCPT time (in the call
** to recipient()). If they are expanded, it
** is impossible for removefromlist() to figure
** out the expanded members of the original
** recipient and mark them as QS_DONTSEND.
*/
- if (milter_can_delrcpts())
- e->e_flags |= EF_VRFYONLY;
+ e->e_flags |= EF_VRFYONLY;
+ milter_cmd_done = false;
+ milter_cmd_safe = false;
#endif /* MILTER */
p = skipword(p, "to");
@@ -2533,63 +2614,34 @@ smtp(nullserver, d_flags, e)
/* now parse ESMTP arguments */
addr = p;
- argno = 0;
- args[argno++] = p;
- p = delimptr;
- while (p != NULL && *p != '\0')
- {
- char *kp;
- char *vp = NULL;
- char *equal = NULL;
-
- /* locate the beginning of the keyword */
- SKIP_SPACE(p);
- if (*p == '\0')
- break;
- kp = p;
-
- /* skip to the value portion */
- while ((isascii(*p) && isalnum(*p)) || *p == '-')
- p++;
- if (*p == '=')
- {
- equal = p;
- *p++ = '\0';
- vp = p;
-
- /* skip to the end of the value */
- while (*p != '\0' && *p != ' ' &&
- !(isascii(*p) && iscntrl(*p)) &&
- *p != '=')
- p++;
- }
-
- if (*p != '\0')
- *p++ = '\0';
-
- if (tTd(19, 1))
- sm_dprintf("RCPT: got arg %s=\"%s\"\n", kp,
- vp == NULL ? "<null>" : vp);
-
- rcpt_esmtp_args(a, kp, vp, e, features);
- if (equal != NULL)
- *equal = '=';
- args[argno++] = kp;
- if (argno >= MAXSMTPARGS - 1)
- usrerr("501 5.5.4 Too many parameters");
- if (Errors > 0)
- break;
- }
- args[argno] = NULL;
+ parse_esmtp_args(e, a, p, delimptr, "RCPT", args,
+ rcpt_esmtp_args);
if (Errors > 0)
goto rcpt_done;
+#if MILTER
+ /*
+ ** rscheck() can trigger an "exception"
+ ** in which case the execution continues at
+ ** SM_EXCEPT(exc, "[!F]*")
+ ** This means milter_cmd_safe is not set
+ ** and hence milter is not invoked.
+ ** Would it be "safe" to change that, i.e., use
+ ** milter_cmd_safe = true;
+ ** here so a milter is informed (if requested)
+ ** about RCPTs that are rejected by check_rcpt?
+ */
+# if _FFR_MILTER_CHECK_REJECTIONS_TOO
+ milter_cmd_safe = true;
+# endif
+#endif
+
/* do config file checking of the recipient */
macdefine(&e->e_macro, A_PERM,
macid("{addr_type}"), "e r");
if (rscheck("check_rcpt", addr,
NULL, e, RSF_RMCOMM|RSF_COUNT, 3,
- NULL, e->e_id) != EX_OK ||
+ NULL, e->e_id, p_addr_st) != EX_OK ||
Errors > 0)
goto rcpt_done;
macdefine(&e->e_macro, A_PERM,
@@ -2598,38 +2650,74 @@ smtp(nullserver, d_flags, e)
/* If discarding, don't bother to verify user */
if (bitset(EF_DISCARD, e->e_flags))
a->q_state = QS_VERIFIED;
+#if MILTER
+ milter_cmd_safe = true;
+#endif
+
+ /* save in recipient list after ESMTP mods */
+ a = recipient(a, &e->e_sendqueue, 0, e);
+ /* may trigger exception... */
+
+#if MILTER
+ milter_rcpt_added = true;
+#endif
+
+ if(!(Errors > 0) && QS_IS_BADADDR(a->q_state))
+ {
+ /* punt -- should keep message in ADDRESS.... */
+ usrerr("550 5.1.1 Addressee unknown");
+ }
#if MILTER
+ rcpt_done:
if (smtp.sm_milterlist && smtp.sm_milterize &&
!bitset(EF_DISCARD, e->e_flags))
{
char state;
char *response;
- response = milter_envrcpt(args, e, &state);
+ /* how to get the error codes? */
+ if (Errors > 0)
+ {
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_mailer}"),
+ "error");
+ if (a != NULL &&
+ a->q_status != NULL &&
+ a->q_rstatus != NULL)
+ {
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_host}"),
+ a->q_status);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"),
+ a->q_rstatus);
+ }
+ else
+ {
+ if (addr_st.q_host != NULL)
+ macdefine(&e->e_macro,
+ A_PERM,
+ macid("{rcpt_host}"),
+ addr_st.q_host);
+ if (addr_st.q_user != NULL)
+ macdefine(&e->e_macro,
+ A_PERM,
+ macid("{rcpt_addr}"),
+ addr_st.q_user);
+ }
+ }
+
+ response = milter_envrcpt(args, e, &state,
+ Errors > 0);
+ milter_cmd_done = true;
MILTER_REPLY("to");
}
#endif /* MILTER */
- macdefine(&e->e_macro, A_PERM,
- macid("{rcpt_mailer}"), NULL);
- macdefine(&e->e_macro, A_PERM,
- macid("{rcpt_host}"), NULL);
- macdefine(&e->e_macro, A_PERM,
- macid("{rcpt_addr}"), NULL);
- macdefine(&e->e_macro, A_PERM,
- macid("{dsn_notify}"), NULL);
- if (Errors > 0)
- goto rcpt_done;
-
- /* save in recipient list after ESMTP mods */
- a = recipient(a, &e->e_sendqueue, 0, e);
- if (Errors > 0)
- goto rcpt_done;
-
/* no errors during parsing, but might be a duplicate */
e->e_to = a->q_paddr;
- if (!QS_IS_BADADDR(a->q_state))
+ if (!(Errors > 0) && !QS_IS_BADADDR(a->q_state))
{
if (smtp.sm_nrcpts == 0)
initsys(e);
@@ -2638,12 +2726,20 @@ smtp(nullserver, d_flags, e)
" (will queue)" : "");
smtp.sm_nrcpts++;
}
- else
- {
- /* punt -- should keep message in ADDRESS.... */
- usrerr("550 5.1.1 Addressee unknown");
- }
- rcpt_done:
+
+ /* Is this needed? */
+#if !MILTER
+ rcpt_done:
+#endif /* !MILTER */
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_mailer}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_host}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{dsn_notify}"), NULL);
+
if (Errors > 0)
{
++n_badrcpts;
@@ -2656,6 +2752,55 @@ smtp(nullserver, d_flags, e)
e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY);
++n_badrcpts;
NBADRCPTS;
+#if MILTER
+ if (smtp.sm_milterlist && smtp.sm_milterize &&
+ !bitset(EF_DISCARD, e->e_flags) &&
+ !milter_cmd_done && milter_cmd_safe)
+ {
+ char state;
+ char *response;
+
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_mailer}"), "error");
+
+ /* how to get the error codes? */
+ if (addr_st.q_host != NULL)
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_host}"),
+ addr_st.q_host);
+ else if (a != NULL && a->q_status != NULL)
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_host}"),
+ a->q_status);
+
+ if (addr_st.q_user != NULL)
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"),
+ addr_st.q_user);
+ else if (a != NULL && a->q_rstatus != NULL)
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"),
+ a->q_rstatus);
+
+ response = milter_envrcpt(args, e, &state,
+ true);
+ milter_cmd_done = true;
+ MILTER_REPLY("to");
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_mailer}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_host}"), NULL);
+ macdefine(&e->e_macro, A_PERM,
+ macid("{rcpt_addr}"), NULL);
+ }
+ if (smtp.sm_milterlist && smtp.sm_milterize &&
+ milter_rcpt_added && milter_cmd_done &&
+ milter_cmd_fail)
+ {
+ (void) removefromlist(addr, &e->e_sendqueue, e);
+ milter_cmd_fail = false;
+ }
+#endif /* MILTER */
}
SM_END_TRY
break;
@@ -2738,7 +2883,7 @@ smtp(nullserver, d_flags, e)
/* do config file checking of the address */
if (rscheck(vrfy ? "check_vrfy" : "check_expn",
p, NULL, e, RSF_RMCOMM,
- 3, NULL, NOQID) != EX_OK ||
+ 3, NULL, NOQID, NULL) != EX_OK ||
Errors > 0)
sm_exc_raisenew_x(&EtypeQuickAbort, 1);
(void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
@@ -2834,7 +2979,8 @@ smtp(nullserver, d_flags, e)
*/
if (rscheck("check_etrn", p, NULL, e,
- RSF_RMCOMM, 3, NULL, NOQID) != EX_OK ||
+ RSF_RMCOMM, 3, NULL, NOQID, NULL)
+ != EX_OK ||
Errors > 0)
break;
@@ -2997,7 +3143,7 @@ doquit:
break;
case CMDDBGDEBUG: /* set debug mode */
- tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
+ tTsetup(tTdvect, sizeof(tTdvect), "0-99.1");
tTflag(p);
message("200 2.0.0 Debug set");
break;
@@ -3106,12 +3252,13 @@ smtp_data(smtp, e)
#endif /* MILTER */
bool aborting;
bool doublequeue;
+ bool rv = true;
ADDRESS *a;
ENVELOPE *ee;
char *id;
char *oldid;
+ unsigned int features;
char buf[32];
- bool rv = true;
SmtpPhase = "server DATA";
if (!smtp->sm_gotmail)
@@ -3124,10 +3271,10 @@ smtp_data(smtp, e)
usrerr("503 5.0.0 Need RCPT (recipient)");
return true;
}
- (void) sm_snprintf(buf, sizeof buf, "%u", smtp->sm_nrcpts);
+ (void) sm_snprintf(buf, sizeof(buf), "%u", smtp->sm_nrcpts);
if (rscheck("check_data", buf, NULL, e,
RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL,
- e->e_id) != EX_OK)
+ e->e_id, NULL) != EX_OK)
return true;
#if MILTER && SMFI_VERSION > 3
@@ -3233,14 +3380,12 @@ smtp_data(smtp, e)
collect(InChannel, true, NULL, e, true);
/* redefine message size */
- (void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize);
+ (void) sm_snprintf(buf, sizeof(buf), "%ld", e->e_msgsize);
macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf);
-#if _FFR_CHECK_EOM
/* rscheck() will set Errors or EF_DISCARD if it trips */
(void) rscheck("check_eom", buf, NULL, e, RSF_UNSTRUCTURED|RSF_COUNT,
- 3, NULL, e->e_id);
-#endif /* _FFR_CHECK_EOM */
+ 3, NULL, e->e_id, NULL);
#if MILTER
milteraccept = true;
@@ -3303,7 +3448,7 @@ smtp_data(smtp, e)
}
/* Milter may have changed message size */
- (void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize);
+ (void) sm_snprintf(buf, sizeof(buf), "%ld", e->e_msgsize);
macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf);
/* abort message filters that didn't get the body & log msg is OK */
@@ -3509,7 +3654,7 @@ smtp_data(smtp, e)
{
char msg[MAXLINE];
- expand(MessageAccept, msg, sizeof msg, e);
+ expand(MessageAccept, msg, sizeof(msg), e);
message("250 2.0.0 %s", msg);
}
else
@@ -3603,8 +3748,10 @@ smtp_data(smtp, e)
*/
CurEnv = e;
+ features = e->e_features;
newenvelope(e, e, sm_rpool_new_x(NULL));
e->e_flags = BlankEnvelope.e_flags;
+ e->e_features = features;
/* restore connection quarantining */
if (smtp->sm_quarmsg == NULL)
@@ -3855,24 +4002,68 @@ skipword(p, w)
}
/*
+** RESET_MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
+**
+** Parameters:
+** e -- the envelope.
+**
+** Returns:
+** none.
+*/
+
+void
+reset_mail_esmtp_args(e)
+ ENVELOPE *e;
+{
+ /* "size": no reset */
+
+ /* "body" */
+ SevenBitInput = SevenBitInput_Saved;
+ e->e_bodytype = NULL;
+
+ /* "envid" */
+ e->e_envid = NULL;
+ macdefine(&e->e_macro, A_PERM, macid("{dsn_envid}"), NULL);
+
+ /* "ret" */
+ e->e_flags &= EF_RET_PARAM;
+ e->e_flags &= EF_NO_BODY_RETN;
+ macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), NULL);
+
+#if SASL
+ /* "auth" */
+ macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), NULL);
+ e->e_auth_param = "";
+# if _FFR_AUTH_PASSING
+ macdefine(&BlankEnvelope.e_macro, A_PERM,
+ macid("{auth_author}"), NULL);
+# endif /* _FFR_AUTH_PASSING */
+#endif /* SASL */
+
+ /* "by" */
+ e->e_deliver_by = 0;
+ e->e_dlvr_flag = 0;
+}
+
+/*
** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
**
** Parameters:
+** a -- address (unused, for compatibility with rcpt_esmtp_args)
** kp -- the parameter key.
** vp -- the value of that parameter.
** e -- the envelope.
-** features -- current server features
**
** Returns:
** none.
*/
-static void
-mail_esmtp_args(kp, vp, e, features)
+void
+mail_esmtp_args(a, kp, vp, e)
+ ADDRESS *a;
char *kp;
char *vp;
ENVELOPE *e;
- unsigned int features;
{
if (sm_strcasecmp(kp, "size") == 0)
{
@@ -3919,7 +4110,7 @@ mail_esmtp_args(kp, vp, e, features)
}
else if (sm_strcasecmp(kp, "envid") == 0)
{
- if (!bitset(SRV_OFFER_DSN, features))
+ if (!bitset(SRV_OFFER_DSN, e->e_features))
{
usrerr("504 5.7.0 Sorry, ENVID not supported, we do not allow DSN");
/* NOTREACHED */
@@ -3945,7 +4136,7 @@ mail_esmtp_args(kp, vp, e, features)
}
else if (sm_strcasecmp(kp, "ret") == 0)
{
- if (!bitset(SRV_OFFER_DSN, features))
+ if (!bitset(SRV_OFFER_DSN, e->e_features))
{
usrerr("504 5.7.0 Sorry, RET not supported, we do not allow DSN");
/* NOTREACHED */
@@ -4018,7 +4209,7 @@ mail_esmtp_args(kp, vp, e, features)
QuickAbort = false;
if (strcmp(auth_param, "<>") != 0 &&
(rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM,
- 9, NULL, NOQID) != EX_OK || Errors > 0))
+ 9, NULL, NOQID, NULL) != EX_OK || Errors > 0))
{
if (tTd(95, 8))
{
@@ -4130,6 +4321,7 @@ mail_esmtp_args(kp, vp, e, features)
/* NOTREACHED */
}
}
+
/*
** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line
**
@@ -4138,25 +4330,23 @@ mail_esmtp_args(kp, vp, e, features)
** kp -- the parameter key.
** vp -- the value of that parameter.
** e -- the envelope.
-** features -- current server features
**
** Returns:
** none.
*/
-static void
-rcpt_esmtp_args(a, kp, vp, e, features)
+void
+rcpt_esmtp_args(a, kp, vp, e)
ADDRESS *a;
char *kp;
char *vp;
ENVELOPE *e;
- unsigned int features;
{
if (sm_strcasecmp(kp, "notify") == 0)
{
char *p;
- if (!bitset(SRV_OFFER_DSN, features))
+ if (!bitset(SRV_OFFER_DSN, e->e_features))
{
usrerr("504 5.7.0 Sorry, NOTIFY not supported, we do not allow DSN");
/* NOTREACHED */
@@ -4197,7 +4387,7 @@ rcpt_esmtp_args(a, kp, vp, e, features)
}
else if (sm_strcasecmp(kp, "orcpt") == 0)
{
- if (!bitset(SRV_OFFER_DSN, features))
+ if (!bitset(SRV_OFFER_DSN, e->e_features))
{
usrerr("504 5.7.0 Sorry, ORCPT not supported, we do not allow DSN");
/* NOTREACHED */
@@ -4251,11 +4441,11 @@ printvrfyaddr(a, last, vrfy)
if (vrfy && a->q_mailer != NULL &&
!bitnset(M_VRFY250, a->q_mailer->m_flags))
- (void) sm_strlcpy(fmtbuf, "252", sizeof fmtbuf);
+ (void) sm_strlcpy(fmtbuf, "252", sizeof(fmtbuf));
else
- (void) sm_strlcpy(fmtbuf, "250", sizeof fmtbuf);
+ (void) sm_strlcpy(fmtbuf, "250", sizeof(fmtbuf));
fmtbuf[3] = last ? ' ' : '-';
- (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof fmtbuf - 4);
+ (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof(fmtbuf) - 4);
if (a->q_fullname == NULL)
{
if ((a->q_mailer == NULL ||
@@ -4263,10 +4453,10 @@ printvrfyaddr(a, last, vrfy)
sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) &&
strchr(a->q_user, '@') == NULL)
(void) sm_strlcpy(&fmtbuf[OFFF], "<%s@%s>",
- sizeof fmtbuf - OFFF);
+ sizeof(fmtbuf) - OFFF);
else
(void) sm_strlcpy(&fmtbuf[OFFF], "<%s>",
- sizeof fmtbuf - OFFF);
+ sizeof(fmtbuf) - OFFF);
message(fmtbuf, a->q_user, MyHostName);
}
else
@@ -4276,10 +4466,10 @@ printvrfyaddr(a, last, vrfy)
sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) &&
strchr(a->q_user, '@') == NULL)
(void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s@%s>",
- sizeof fmtbuf - OFFF);
+ sizeof(fmtbuf) - OFFF);
else
(void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s>",
- sizeof fmtbuf - OFFF);
+ sizeof(fmtbuf) - OFFF);
message(fmtbuf, a->q_fullname, a->q_user, MyHostName);
}
}
@@ -4600,7 +4790,7 @@ help(topic, e)
len = strlen(topic);
- while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
+ while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
{
if (buf[0] == '#')
{
@@ -4633,8 +4823,13 @@ help(topic, e)
fixcrlf(p, true);
if (foundvers >= 2)
{
- translate_dollars(p);
- expand(p, inp, sizeof inp, e);
+ char *lbp;
+ int lbs = sizeof(buf) - (p - buf);
+
+ lbp = translate_dollars(p, p, &lbs);
+ expand(lbp, inp, sizeof(inp), e);
+ if (p != lbp)
+ sm_free(lbp);
p = inp;
}
message("214-2.0.0 %s", p);
OpenPOWER on IntegriCloud