📄 srvrsmtp.c
字号:
macvalue(macid("{verify}", NULL), e),
"STARTTLS", e, TRUE, TRUE, 6) != EX_OK ||
Errors > 0)
{
extern char MsgBuf[];
if (MsgBuf[0] != '\0' && ISSMTPREPLY(MsgBuf))
nullserver = newstr(MsgBuf);
else
nullserver = "503 5.7.0 Authentication required.";
}
QuickAbort = saveQuickAbort;
SuprErrs = saveSuprErrs;
tls_ok = FALSE; /* don't offer STARTTLS again */
gothello = FALSE; /* discard info */
n_helo = 0;
OneXact = TRUE; /* only one xaction this run */
# if SASL
if (sasl_ok)
{
char *s;
if ((s = macvalue(macid("{cipher_bits}", NULL), e)) != NULL &&
(ext_ssf.ssf = atoi(s)) > 0)
{
# if _FFR_EXT_MECH
ext_ssf.auth_id = macvalue(macid("{cert_subject}",
NULL),
e);
# endif /* _FFR_EXT_MECH */
sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL,
&ext_ssf) == SASL_OK;
if (mechlist != NULL)
free(mechlist);
mechlist = NULL;
if (sasl_ok)
{
n_mechs = saslmechs(conn,
&mechlist);
sasl_ok = n_mechs > 0;
}
}
}
# endif /* SASL */
/* switch to secure connection */
#if SFIO
r = sfdctls(InChannel, OutChannel, srv_ssl);
#else /* SFIO */
# if _FFR_TLS_TOREK
r = sfdctls(&InChannel, &OutChannel, srv_ssl);
# endif /* _FFR_TLS_TOREK */
#endif /* SFIO */
if (r == 0)
tls_active = TRUE;
else
{
/*
** XXX this is an internal error
** how to deal with it?
** we can't generate an error message
** since the other side switched to an
** encrypted layer, but we could not...
** just "hang up"?
*/
nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer";
syserr("TLS: can't switch to encrypted layer");
}
break;
# endif /* STARTTLS */
case CMDHELO: /* hello -- introduce yourself */
case CMDEHLO: /* extended hello */
if (c->cmd_code == CMDEHLO)
{
protocol = "ESMTP";
SmtpPhase = "server EHLO";
}
else
{
protocol = "SMTP";
SmtpPhase = "server HELO";
}
/* avoid denial-of-service */
(void) checksmtpattack(&n_helo, MAXHELOCOMMANDS, TRUE,
"HELO/EHLO", e);
/* check for duplicate HELO/EHLO per RFC 1651 4.2 */
if (gothello)
{
usrerr("503 %s Duplicate HELO/EHLO",
MyHostName);
break;
}
/* check for valid domain name (re 1123 5.2.5) */
if (*p == '\0' && !AllowBogusHELO)
{
usrerr("501 %s requires domain address",
cmdbuf);
break;
}
/* check for long domain name (hides Received: info) */
if (strlen(p) > MAXNAME)
{
usrerr("501 Invalid domain name");
if (LogLevel > 9)
sm_syslog(LOG_INFO, CurEnv->e_id,
"invalid domain name (too long) from %.100s",
CurSmtpClient);
break;
}
for (q = p; *q != '\0'; q++)
{
if (!isascii(*q))
break;
if (isalnum(*q))
continue;
if (isspace(*q))
{
*q = '\0';
break;
}
if (strchr("[].-_#", *q) == NULL)
break;
}
if (*q == '\0')
{
q = "pleased to meet you";
sendinghost = newstr(p);
}
else if (!AllowBogusHELO)
{
usrerr("501 Invalid domain name");
if (LogLevel > 9)
sm_syslog(LOG_INFO, CurEnv->e_id,
"invalid domain name (%.100s) from %.100s",
p, CurSmtpClient);
break;
}
else
{
q = "accepting invalid domain name";
}
gothello = TRUE;
# if _FFR_MILTER
if (milterize && !bitset(EF_DISCARD, e->e_flags))
{
char state;
char *response;
response = milter_helo(p, e, &state);
switch (state)
{
case SMFIR_REPLYCODE:
nullserver = response;
milterize = FALSE;
break;
case SMFIR_REJECT:
nullserver = "Command rejected";
milterize = FALSE;
break;
case SMFIR_TEMPFAIL:
tempfail = TRUE;
milterize = FALSE;
break;
}
}
# endif /* _FFR_MILTER */
/* print HELO response message */
if (c->cmd_code != CMDEHLO)
{
message("250 %s Hello %s, %s",
MyHostName, CurSmtpClient, q);
break;
}
message("250-%s Hello %s, %s",
MyHostName, CurSmtpClient, q);
/* offer ENHSC even for nullserver */
if (nullserver != NULL)
{
message("250 ENHANCEDSTATUSCODES");
break;
}
/*
** print EHLO features list
**
** Note: If you change this list,
** remember to update 'helpfile'
*/
message("250-ENHANCEDSTATUSCODES");
if (!bitset(PRIV_NOEXPN, PrivacyFlags))
{
message("250-EXPN");
if (!bitset(PRIV_NOVERB, PrivacyFlags))
message("250-VERB");
}
# if MIME8TO7
message("250-8BITMIME");
# endif /* MIME8TO7 */
if (MaxMessageSize > 0)
message("250-SIZE %ld", MaxMessageSize);
else
message("250-SIZE");
# if DSN
if (SendMIMEErrors &&
!bitset(PRIV_NORECEIPTS, PrivacyFlags))
message("250-DSN");
# endif /* DSN */
message("250-ONEX");
if (!bitset(PRIV_NOETRN, PrivacyFlags) &&
!bitnset(D_NOETRN, d_flags))
message("250-ETRN");
message("250-XUSR");
# if SASL
if (sasl_ok && mechlist != NULL && *mechlist != '\0')
message("250-AUTH %s", mechlist);
# endif /* SASL */
# if STARTTLS
if (tls_ok && usetls)
message("250-STARTTLS");
# endif /* STARTTLS */
message("250 HELP");
break;
case CMDMAIL: /* mail -- designate sender */
SmtpPhase = "server MAIL";
/* check for validity of this command */
if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
{
usrerr("503 5.0.0 Polite people say HELO first");
break;
}
if (gotmail)
{
usrerr("503 5.5.0 Sender already specified");
break;
}
if (InChild)
{
errno = 0;
syserr("503 5.5.0 Nested MAIL command: MAIL %s", p);
finis(TRUE, ExitStat);
}
# if SASL
if (bitnset(D_AUTHREQ, d_flags) &&
authenticating != SASL_IS_AUTH)
{
usrerr("530 5.7.0 Authentication required");
break;
}
# endif /* SASL */
p = skipword(p, "from");
if (p == NULL)
break;
if (tempfail)
{
if (LogLevel > 9)
sm_syslog(LOG_INFO, e->e_id,
"SMTP MAIL command (%.100s) from %.100s tempfailed (due to previous checks)",
p, CurSmtpClient);
usrerr("451 4.7.1 Please try again later");
break;
}
/* make sure we know who the sending host is */
if (sendinghost == NULL)
sendinghost = peerhostname;
/* fork a subprocess to process this command */
ric = runinchild("SMTP-MAIL", e);
/* Catch a problem and stop processing */
if (ric == RIC_TEMPFAIL && nullserver == NULL)
nullserver = "452 4.3.0 Internal software error";
if (ric != RIC_INCHILD)
break;
if (Errors > 0)
goto undo_subproc_no_pm;
if (!gothello)
{
auth_warning(e,
"%s didn't use HELO protocol",
CurSmtpClient);
}
# ifdef PICKY_HELO_CHECK
if (strcasecmp(sendinghost, peerhostname) != 0 &&
(strcasecmp(peerhostname, "localhost") != 0 ||
strcasecmp(sendinghost, MyHostName) != 0))
{
auth_warning(e, "Host %s claimed to be %s",
CurSmtpClient, sendinghost);
}
# endif /* PICKY_HELO_CHECK */
if (protocol == NULL)
protocol = "SMTP";
define('r', protocol, e);
define('s', sendinghost, e);
if (Errors > 0)
goto undo_subproc_no_pm;
nrcpts = 0;
define(macid("{ntries}", NULL), "0", e);
e->e_flags |= EF_CLRQUEUE;
sm_setproctitle(TRUE, e, "%s %s: %.80s",
qid_printname(e),
CurSmtpClient, inp);
/* child -- go do the processing */
if (setjmp(TopFrame) > 0)
{
/* this failed -- undo work */
undo_subproc_no_pm:
e->e_flags &= ~EF_PM_NOTIFY;
undo_subproc:
if (InChild)
{
QuickAbort = FALSE;
SuprErrs = TRUE;
e->e_flags &= ~EF_FATALERRS;
if (LogLevel > 4 &&
bitset(EF_LOGSENDER, e->e_flags))
logsender(e, NULL);
e->e_flags &= ~EF_LOGSENDER;
finis(TRUE, ExitStat);
}
break;
}
QuickAbort = TRUE;
/* must parse sender first */
delimptr = NULL;
setsender(p, e, &delimptr, ' ', FALSE);
if (delimptr != NULL && *delimptr != '\0')
*delimptr++ = '\0';
if (Errors > 0)
goto undo_subproc_no_pm;
/* Successfully set e_from, allow logging */
e->e_flags |= EF_LOGSENDER;
/* put resulting triple from parseaddr() into macros */
if (e->e_from.q_mailer != NULL)
define(macid("{mail_mailer}", NULL),
e->e_from.q_mailer->m_name, e);
else
define(macid("{mail_mailer}", NULL),
NULL, e);
if (e->e_from.q_host != NULL)
define(macid("{mail_host}", NULL),
e->e_from.q_host, e);
else
define(macid("{mail_host}", NULL),
"localhost", e);
if (e->e_from.q_user != NULL)
define(macid("{mail_addr}", NULL),
e->e_from.q_user, e);
else
define(macid("{mail_addr}", NULL),
NULL, e);
if (Errors > 0)
goto undo_subproc_no_pm;
/* check for possible spoofing */
if (RealUid != 0 && OpMode == MD_SMTP &&
!wordinclass(RealUserName, 't') &&
(!bitnset(M_LOCALMAILER,
e->e_from.q_mailer->m_flags) ||
strcmp(e->e_from.q_user, RealUserName) != 0))
{
auth_warning(e, "%s owned process doing -bs",
RealUserName);
}
/* 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 */
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("MAIL: got arg %s=\"%s\"\n", kp,
vp == NULL ? "<null>" : vp);
mail_esmtp_args(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)
goto undo_subproc_no_pm;
}
args[argno] = NULL;
if (Errors > 0)
goto undo_subproc_no_pm;
/* do config file checking of the sender */
if (rscheck("check_mail", addr,
NULL, e, TRUE, TRUE, 4) != EX_OK ||
Errors > 0)
goto undo_subproc_no_pm;
if (MaxMessageSize > 0 &&
(e->e_msgsize > MaxMessageSize || e->e_msgsize < 0))
{
usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)",
MaxMessageSize);
goto undo_subproc_no_pm;
}
if (!enoughdiskspace(e->e_msgsize, TRUE))
{
usrerr("452 4.4.5 Insufficient disk space; try again later");
goto undo_subproc_no_pm;
}
if (Errors > 0)
goto undo_subproc_no_pm;
# if _FFR_MILTER
LogUsrErrs = TRUE;
if (milterize && !bitset(EF_DISCARD, e->e_flags))
{
char state;
char *response;
response = milter_envfrom(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 */
if (Errors > 0)
goto undo_subproc_no_pm;
message("250 2.1.0 Sender ok");
gotmail = TRUE;
break;
case CMDRCPT: /* rcpt -- designate recipient */
if (!gotmail)
{
usrerr("503 5.0.0 Need MAIL before RCPT");
break;
}
SmtpPhase = "server RCPT";
if (setjmp(TopFrame) > 0)
{
e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY);
break;
}
QuickAbort = TRUE;
LogUsrErrs = TRUE;
/* limit flooding of our machine */
if (MaxRcptPerMsg > 0 && nrcpts >= MaxRcptPerMsg)
{
usrerr("452 4.5.3 Too many recipients");
break;
}
if (e->e_sendmode != SM_DELIVER)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -