📄 srvrsmtp.c
字号:
e->e_flags |= EF_VRFYONLY;
# if _FFR_MILTER
/*
** If the filter will be deleting recipients,
** don't expand them 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;
# endif /* _FFR_MILTER */
p = skipword(p, "to");
if (p == NULL)
break;
# if _FFR_ADDR_TYPE
define(macid("{addr_type}", NULL), "e r", e);
# endif /* _FFR_ADDR_TYPE */
a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e);
#if _FFR_ADDR_TYPE
define(macid("{addr_type}", NULL), NULL, e);
#endif /* _FFR_ADDR_TYPE */
if (Errors > 0)
break;
if (a == NULL)
{
usrerr("501 5.0.0 Missing recipient");
break;
}
if (delimptr != NULL && *delimptr != '\0')
*delimptr++ = '\0';
/* put resulting triple from parseaddr() into macros */
if (a->q_mailer != NULL)
define(macid("{rcpt_mailer}", NULL),
a->q_mailer->m_name, e);
else
define(macid("{rcpt_mailer}", NULL),
NULL, e);
if (a->q_host != NULL)
define(macid("{rcpt_host}", NULL),
a->q_host, e);
else
define(macid("{rcpt_host}", NULL),
"localhost", e);
if (a->q_user != NULL)
define(macid("{rcpt_addr}", NULL),
a->q_user, e);
else
define(macid("{rcpt_addr}", NULL),
NULL, e);
if (Errors > 0)
break;
/* 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 */
while (isascii(*p) && isspace(*p))
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))
dprintf("RCPT: got arg %s=\"%s\"\n", kp,
vp == NULL ? "<null>" : vp);
rcpt_esmtp_args(a, kp, vp, e);
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;
if (Errors > 0)
break;
/* do config file checking of the recipient */
if (rscheck("check_rcpt", addr,
NULL, e, TRUE, TRUE, 4) != EX_OK ||
Errors > 0)
break;
# if _FFR_MILTER
if (milterize && !bitset(EF_DISCARD, e->e_flags))
{
char state;
char *response;
response = milter_envrcpt(args, e, &state);
switch (state)
{
case SMFIR_REPLYCODE:
usrerr(response);
break;
case SMFIR_REJECT:
usrerr("550 5.7.1 Command rejected");
break;
case SMFIR_DISCARD:
e->e_flags |= EF_DISCARD;
break;
case SMFIR_TEMPFAIL:
usrerr("451 4.7.1 Please try again later");
break;
}
if (response != NULL)
free(response);
}
# endif /* _FFR_MILTER */
define(macid("{rcpt_mailer}", NULL), NULL, e);
define(macid("{rcpt_relay}", NULL), NULL, e);
define(macid("{rcpt_addr}", NULL), NULL, e);
define(macid("{dsn_notify}", NULL), NULL, e);
if (Errors > 0)
break;
/* save in recipient list after ESMTP mods */
a = recipient(a, &e->e_sendqueue, 0, e);
if (Errors > 0)
break;
/* no errors during parsing, but might be a duplicate */
e->e_to = a->q_paddr;
if (!QS_IS_BADADDR(a->q_state))
{
if (e->e_queuedir == NOQDIR)
initsys(e);
message("250 2.1.5 Recipient ok%s",
QS_IS_QUEUEUP(a->q_state) ?
" (will queue)" : "");
nrcpts++;
}
else
{
/* punt -- should keep message in ADDRESS.... */
usrerr("550 5.1.1 Addressee unknown");
}
break;
case CMDDATA: /* data -- text of mail */
SmtpPhase = "server DATA";
if (!gotmail)
{
usrerr("503 5.0.0 Need MAIL command");
break;
}
else if (nrcpts <= 0)
{
usrerr("503 5.0.0 Need RCPT (recipient)");
break;
}
/* put back discard bit */
if (discard)
e->e_flags |= EF_DISCARD;
/* check to see if we need to re-expand aliases */
/* also reset QS_BADADDR on already-diagnosted addrs */
doublequeue = FALSE;
for (a = e->e_sendqueue; a != NULL; a = a->q_next)
{
if (QS_IS_VERIFIED(a->q_state) &&
!bitset(EF_DISCARD, e->e_flags))
{
/* need to re-expand aliases */
doublequeue = TRUE;
}
if (QS_IS_BADADDR(a->q_state))
{
/* make this "go away" */
a->q_state = QS_DONTSEND;
}
}
/* collect the text of the message */
SmtpPhase = "collect";
buffer_errors();
collect(InChannel, TRUE, NULL, e);
# if _FFR_MILTER
if (milterize &&
Errors <= 0 &&
!bitset(EF_DISCARD, e->e_flags))
{
char state;
char *response;
response = milter_data(e, &state);
switch (state)
{
case SMFIR_REPLYCODE:
usrerr(response);
break;
case SMFIR_REJECT:
usrerr("554 5.7.1 Command rejected");
break;
case SMFIR_DISCARD:
e->e_flags |= EF_DISCARD;
break;
case SMFIR_TEMPFAIL:
usrerr("451 4.7.1 Please try again later");
break;
}
if (response != NULL)
free(response);
}
/* abort message filters that didn't get the body */
if (milterize)
milter_abort(e);
# endif /* _FFR_MILTER */
/* redefine message size */
if ((q = macvalue(macid("{msg_size}", NULL), e))
!= NULL)
free(q);
snprintf(inp, sizeof inp, "%ld", e->e_msgsize);
define(macid("{msg_size}", NULL), newstr(inp), e);
if (Errors > 0)
{
/* Log who the mail would have gone to */
if (LogLevel > 8 &&
e->e_message != NULL)
{
for (a = e->e_sendqueue;
a != NULL;
a = a->q_next)
{
if (!QS_IS_UNDELIVERED(a->q_state))
continue;
e->e_to = a->q_paddr;
logdelivery(NULL, NULL,
a->q_status,
e->e_message,
NULL,
(time_t) 0, e);
}
e->e_to = NULL;
}
flush_errors(TRUE);
buffer_errors();
goto abortmessage;
}
/* make sure we actually do delivery */
e->e_flags &= ~EF_CLRQUEUE;
/* from now on, we have to operate silently */
buffer_errors();
e->e_errormode = EM_MAIL;
/*
** Arrange to send to everyone.
** If sending to multiple people, mail back
** errors rather than reporting directly.
** In any case, don't mail back errors for
** anything that has happened up to
** now (the other end will do this).
** Truncate our transcript -- the mail has gotten
** to us successfully, and if we have
** to mail this back, it will be easier
** on the reader.
** Then send to everyone.
** Finally give a reply code. If an error has
** already been given, don't mail a
** message back.
** We goose error returns by clearing error bit.
*/
SmtpPhase = "delivery";
(void) bftruncate(e->e_xfp);
id = e->e_id;
/*
** If a header/body check (header checks or milter)
** set EF_DISCARD, don't queueup the message --
** that would lose the EF_DISCARD bit and deliver
** the message.
*/
if (bitset(EF_DISCARD, e->e_flags))
doublequeue = FALSE;
if (doublequeue)
{
/* make sure it is in the queue */
queueup(e, FALSE);
}
else
{
/* send to all recipients */
# if NAMED_BIND
_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
# endif /* NAMED_BIND */
sendall(e, SM_DEFAULT);
}
e->e_to = NULL;
/* issue success message */
message("250 2.0.0 %s Message accepted for delivery", id);
/* if we just queued, poke it */
if (doublequeue &&
e->e_sendmode != SM_QUEUE &&
e->e_sendmode != SM_DEFER)
{
CurrentLA = sm_getla(e);
if (!shouldqueue(e->e_msgpriority, e->e_ctime))
{
/* close all the queue files */
closexscript(e);
if (e->e_dfp != NULL)
(void) bfclose(e->e_dfp);
e->e_dfp = NULL;
unlockqueue(e);
(void) dowork(e->e_queuedir, id,
TRUE, TRUE, e);
}
}
abortmessage:
if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
logsender(e, NULL);
e->e_flags &= ~EF_LOGSENDER;
/* if in a child, pop back to our parent */
if (InChild)
finis(TRUE, ExitStat);
/* clean up a bit */
gotmail = FALSE;
dropenvelope(e, TRUE);
CurEnv = e = newenvelope(e, CurEnv);
e->e_flags = BlankEnvelope.e_flags;
break;
case CMDRSET: /* rset -- reset state */
# if _FFR_MILTER
/* abort milter filters */
milter_abort(e);
# endif /* _FFR_MILTER */
if (tTd(94, 100))
message("451 4.0.0 Test failure");
else
message("250 2.0.0 Reset state");
/* arrange to ignore any current send list */
e->e_sendqueue = NULL;
e->e_flags |= EF_CLRQUEUE;
if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
logsender(e, NULL);
e->e_flags &= ~EF_LOGSENDER;
if (InChild)
finis(TRUE, ExitStat);
/* clean up a bit */
gotmail = FALSE;
SuprErrs = TRUE;
dropenvelope(e, TRUE);
CurEnv = e = newenvelope(e, CurEnv);
break;
case CMDVRFY: /* vrfy -- verify address */
case CMDEXPN: /* expn -- expand address */
if (tempfail)
{
if (LogLevel > 9)
sm_syslog(LOG_INFO, e->e_id,
"SMTP %s command (%.100s) from %.100s tempfailed (due to previous checks)",
c->cmd_code == CMDVRFY ? "VRFY" : "EXPN",
p, CurSmtpClient);
usrerr("550 5.7.1 Please try again later");
break;
}
wt = checksmtpattack(&nverifies, MAXVRFYCOMMANDS, FALSE,
c->cmd_code == CMDVRFY ? "VRFY" : "EXPN", e);
previous = curtime();
vrfy = c->cmd_code == CMDVRFY;
if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
PrivacyFlags))
{
if (vrfy)
message("252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
else
message("502 5.7.0 Sorry, we do not allow this operation");
if (LogLevel > 5)
sm_syslog(LOG_INFO, e->e_id,
"%.100s: %s [rejected]",
CurSmtpClient,
shortenstring(inp, MAXSHORTSTR));
break;
}
else if (!gothello &&
bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
PrivacyFlags))
{
usrerr("503 5.0.0 I demand that you introduce yourself first");
break;
}
if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0)
break;
if (Errors > 0)
goto undo_subproc;
if (LogLevel > 5)
sm_syslog(LOG_INFO, e->e_id,
"%.100s: %s",
CurSmtpClient,
shortenstring(inp, MAXSHORTSTR));
if (setjmp(TopFrame) > 0)
goto undo_subproc;
QuickAbort = TRUE;
vrfyqueue = NULL;
if (vrfy)
e->e_flags |= EF_VRFYONLY;
while (*p != '\0' && isascii(*p) && isspace(*p))
p++;
if (*p == '\0')
{
usrerr("501 5.5.2 Argument required");
}
else
{
/* do config file checking of the address */
if (rscheck(vrfy ? "check_vrfy" : "check_expn",
p, NULL, e, TRUE, FALSE, 4)
!= EX_OK || Errors > 0)
goto undo_subproc;
(void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
}
if (wt > 0)
(void) sleep(wt - (curtime() - previous));
if (Errors > 0)
goto undo_subproc;
if (vrfyqueue == NULL)
{
usrerr("554 5.5.2 Nothing to %s", vrfy ? "VRFY" : "EXPN");
}
while (vrfyqueue != NULL)
{
if (!QS_IS_UNDELIVERED(vrfyqueue->q_state))
{
vrfyqueue = vrfyqueue->q_next;
continue;
}
/* see if there is more in the vrfy list */
a = vrfyqueue;
while ((a = a->q_next) != NULL &&
(!QS_IS_UNDELIVERED(a->q_state)))
continue;
printvrfyaddr(vrfyqueue, a == NULL, vrfy);
vrfyqueue = a;
}
if (InChild)
finis(TRUE, ExitStat);
break;
case CMDETRN: /* etrn -- force queue flush */
if (bitset(PRIV_NOETRN, PrivacyFlags) ||
bitnset(D_NOETRN, d_flags))
{
/* different message for MSA ? */
message("502 5.7.0 Sorry, we do not allow this operation");
if (LogLevel > 5)
sm_syslog(LOG_INFO, e->e_id,
"%.100s: %s [rejected]",
CurSmtpClient,
shortenstring(inp, MAXSHORTSTR));
break;
}
if (tempfail)
{
if (LogLevel > 9)
sm_syslog(LOG_INFO, e->e_id,
"SMTP ETRN command (%.100s) from %.100s tempfailed (due to previous checks)",
p, CurSmtpClient);
usrerr("451 4.7.1 Please try again later");
break;
}
if (strlen(p) <= 0)
{
usrerr("500 5.5.2 Parameter required");
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -