📄 usersmtp.c
字号:
}
# endif /* SFIO */
return EX_TEMPFAIL;
}
*mechused = mechusing;
/* send the info across the wire */
if (outlen > 0)
{
saslresult = sasl_encode64(out, outlen, in64, MAXOUTLEN, NULL);
if (saslresult != SASL_OK) /* internal error */
{
if (LogLevel > 8)
sm_syslog(LOG_ERR, e->e_id,
"encode64 for AUTH failed");
return EX_TEMPFAIL;
}
smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
}
else
{
smtpmessage("AUTH %s", m, mci, mechusing);
}
/* get the reply */
smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, getsasldata, NULL);
/* which timeout? XXX */
for (;;)
{
/* check return code from server */
if (smtpresult == 235)
{
define(macid("{auth_type}", NULL),
newstr(mechusing), e);
# if !SFIO
if (LogLevel > 9)
sm_syslog(LOG_INFO, NOQID,
"SASL: outgoing connection to %.64s: mech=%.16s",
mci->mci_host, mechusing);
# endif /* !SFIO */
return EX_OK;
}
if (smtpresult == -1)
return EX_IOERR;
if (smtpresult != 334)
return EX_TEMPFAIL;
saslresult = sasl_client_step(mci->mci_conn,
mci->mci_sasl_string,
mci->mci_sasl_string_len,
&client_interact,
&out, &outlen);
if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
{
if (tTd(95, 5))
dprintf("AUTH FAIL: %s (%d)\n",
sasl_errstring(saslresult, NULL, NULL),
saslresult);
/* fail deliberately, see RFC 2254 4. */
smtpmessage("*", m, mci);
/*
** but we should only fail for this authentication
** mechanism; how to do that?
*/
smtpresult = reply(m, mci, e, TimeOuts.to_datafinal,
getsasldata, NULL);
return EX_TEMPFAIL;
}
if (outlen > 0)
{
saslresult = sasl_encode64(out, outlen, in64,
MAXOUTLEN, NULL);
if (saslresult != SASL_OK)
{
/* give an error reply to the other side! */
smtpmessage("*", m, mci);
return EX_TEMPFAIL;
}
}
else
in64[0] = '\0';
smtpmessage(in64, m, mci);
smtpresult = reply(m, mci, e, TimeOuts.to_datafinal,
getsasldata, NULL);
/* which timeout? XXX */
}
/* NOTREACHED */
}
/*
** SMTPAUTH -- try to AUTHenticate
**
** This will try mechanisms in the order the sasl library decided until:
** - there are no more mechanisms
** - a mechanism succeeds
** - the sasl library fails initializing
**
** Parameters:
** m -- the mailer.
** mci -- the mailer connection info.
** e -- the envelope.
**
** Returns:
** EX_OK/EX_TEMPFAIL
*/
int
smtpauth(m, mci, e)
MAILER *m;
MCI *mci;
ENVELOPE *e;
{
int result;
char *mechused;
char *h;
static char *defrealm = NULL;
static char *mechs = NULL;
mci->mci_sasl_auth = FALSE;
if (defrealm == NULL)
{
h = readauth(SASL_DEFREALM, SASLInfo, TRUE);
if (h != NULL && *h != '\0')
defrealm = newstr(h);
}
if (defrealm == NULL || *defrealm == '\0')
defrealm = newstr(macvalue('j', CurEnv));
callbacks[CB_GETREALM_IDX].context = defrealm;
# if _FFR_DEFAUTHINFO_MECHS
if (mechs == NULL)
{
h = readauth(SASL_MECH, SASLInfo, TRUE);
if (h != NULL && *h != '\0')
mechs = newstr(h);
}
# endif /* _FFR_DEFAUTHINFO_MECHS */
if (mechs == NULL || *mechs == '\0')
mechs = AuthMechanisms;
mci->mci_saslcap = intersect(mechs, mci->mci_saslcap);
/* initialize sasl client library */
result = sasl_client_init(callbacks);
if (result != SASL_OK)
return EX_TEMPFAIL;
do
{
result = attemptauth(m, mci, e, &mechused);
if (result == EX_OK)
mci->mci_sasl_auth = TRUE;
else if (result == EX_TEMPFAIL)
{
mci->mci_saslcap = removemech(mechused,
mci->mci_saslcap);
if (mci->mci_saslcap == NULL ||
*(mci->mci_saslcap) == '\0')
return EX_TEMPFAIL;
}
else /* all others for now */
return EX_TEMPFAIL;
} while (result != EX_OK);
return result;
}
# endif /* SASL */
/*
** SMTPMAILFROM -- send MAIL command
**
** Parameters:
** m -- the mailer.
** mci -- the mailer connection structure.
** e -- the envelope (including the sender to specify).
*/
int
smtpmailfrom(m, mci, e)
MAILER *m;
MCI *mci;
ENVELOPE *e;
{
int r;
char *bufp;
char *bodytype;
char buf[MAXNAME + 1];
char optbuf[MAXLINE];
char *enhsc;
if (tTd(18, 2))
dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
enhsc = NULL;
/* set up appropriate options to include */
if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
{
snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize);
bufp = &optbuf[strlen(optbuf)];
}
else
{
optbuf[0] = '\0';
bufp = optbuf;
}
bodytype = e->e_bodytype;
if (bitset(MCIF_8BITMIME, mci->mci_flags))
{
if (bodytype == NULL &&
bitset(MM_MIME8BIT, MimeMode) &&
bitset(EF_HAS8BIT, e->e_flags) &&
!bitset(EF_DONT_MIME, e->e_flags) &&
!bitnset(M_8BITS, m->m_flags))
bodytype = "8BITMIME";
if (bodytype != NULL &&
SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
{
snprintf(bufp, SPACELEFT(optbuf, bufp),
" BODY=%s", bodytype);
bufp += strlen(bufp);
}
}
else if (bitnset(M_8BITS, m->m_flags) ||
!bitset(EF_HAS8BIT, e->e_flags) ||
bitset(MCIF_8BITOK, mci->mci_flags))
{
/* EMPTY */
/* just pass it through */
}
# if MIME8TO7
else if (bitset(MM_CVTMIME, MimeMode) &&
!bitset(EF_DONT_MIME, e->e_flags) &&
(!bitset(MM_PASS8BIT, MimeMode) ||
bitset(EF_IS_MIME, e->e_flags)))
{
/* must convert from 8bit MIME format to 7bit encoded */
mci->mci_flags |= MCIF_CVT8TO7;
}
# endif /* MIME8TO7 */
else if (!bitset(MM_PASS8BIT, MimeMode))
{
/* cannot just send a 8-bit version */
extern char MsgBuf[];
usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName);
mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
return EX_DATAERR;
}
if (bitset(MCIF_DSN, mci->mci_flags))
{
if (e->e_envid != NULL &&
SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
{
snprintf(bufp, SPACELEFT(optbuf, bufp),
" ENVID=%s", e->e_envid);
bufp += strlen(bufp);
}
/* RET= parameter */
if (bitset(EF_RET_PARAM, e->e_flags) &&
SPACELEFT(optbuf, bufp) > 9)
{
snprintf(bufp, SPACELEFT(optbuf, bufp),
" RET=%s",
bitset(EF_NO_BODY_RETN, e->e_flags) ?
"HDRS" : "FULL");
bufp += strlen(bufp);
}
}
if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
# if SASL
&& (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
# endif /* SASL */
)
{
snprintf(bufp, SPACELEFT(optbuf, bufp),
" AUTH=%s", e->e_auth_param);
bufp += strlen(bufp);
}
/*
** Send the MAIL command.
** Designates the sender.
*/
mci->mci_state = MCIS_ACTIVE;
if (bitset(EF_RESPONSE, e->e_flags) &&
!bitnset(M_NO_NULL_FROM, m->m_flags))
buf[0] = '\0';
else
expand("\201g", buf, sizeof buf, e);
if (buf[0] == '<')
{
/* strip off <angle brackets> (put back on below) */
bufp = &buf[strlen(buf) - 1];
if (*bufp == '>')
*bufp = '\0';
bufp = &buf[1];
}
else
bufp = buf;
if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
!bitnset(M_FROMPATH, m->m_flags))
{
smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
}
else
{
smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
*bufp == '@' ? ',' : ':', bufp, optbuf);
}
SmtpPhase = mci->mci_phase = "client MAIL";
sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
CurHostName, mci->mci_phase);
r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc);
if (r < 0)
{
/* communications failure */
mci->mci_errno = errno;
mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
smtpquit(m, mci, e);
return EX_TEMPFAIL;
}
else if (r == 421)
{
/* service shutting down */
mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
SmtpReplyBuffer);
smtpquit(m, mci, e);
return EX_TEMPFAIL;
}
else if (REPLYTYPE(r) == 4)
{
mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)),
SmtpReplyBuffer);
return EX_TEMPFAIL;
}
else if (REPLYTYPE(r) == 2)
{
return EX_OK;
}
else if (r == 501)
{
/* syntax error in arguments */
mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"),
SmtpReplyBuffer);
return EX_DATAERR;
}
else if (r == 553)
{
/* mailbox name not allowed */
mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"),
SmtpReplyBuffer);
return EX_DATAERR;
}
else if (r == 552)
{
/* exceeded storage allocation */
mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"),
SmtpReplyBuffer);
if (bitset(MCIF_SIZE, mci->mci_flags))
e->e_flags |= EF_NO_BODY_RETN;
return EX_UNAVAILABLE;
}
else if (REPLYTYPE(r) == 5)
{
/* unknown error */
mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"),
SmtpReplyBuffer);
return EX_UNAVAILABLE;
}
if (LogLevel > 1)
{
sm_syslog(LOG_CRIT, e->e_id,
"%.100s: SMTP MAIL protocol error: %s",
CurHostName,
shortenstring(SmtpReplyBuffer, 403));
}
/* protocol error -- close up */
mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
SmtpReplyBuffer);
smtpquit(m, mci, e);
return EX_PROTOCOL;
}
/*
** SMTPRCPT -- designate recipient.
**
** Parameters:
** to -- address of recipient.
** m -- the mailer we are sending to.
** mci -- the connection info for this transaction.
** e -- the envelope for this transaction.
**
** Returns:
** exit status corresponding to recipient status.
**
** Side Effects:
** Sends the mail via SMTP.
*/
int
smtprcpt(to, m, mci, e)
ADDRESS *to;
register MAILER *m;
MCI *mci;
ENVELOPE *e;
{
register int r;
char *bufp;
char optbuf[MAXLINE];
char *enhsc;
enhsc = NULL;
optbuf[0] = '\0';
bufp = optbuf;
/*
** warning: in the following it is assumed that the free space
** in bufp is sizeof optbuf
*/
if (bitset(MCIF_DSN, mci->mci_flags))
{
/* NOTIFY= parameter */
if (bitset(QHASNOTIFY, to->q_flags) &&
bitset(QPRIMARY, to->q_flags) &&
!bitnset(M_LOCALMAILER, m->m_flags))
{
bool firstone = TRUE;
(void) strlcat(bufp, " NOTIFY=", sizeof optbuf);
if (bitset(QPINGONSUCCESS, to->q_flags))
{
(void) strlcat(bufp, "SUCCESS", sizeof optbuf);
firstone = FALSE;
}
if (bitset(QPINGONFAILURE, to->q_flags))
{
if (!firstone)
(void) strlcat(bufp, ",",
sizeof optbuf);
(void) strlcat(bufp, "FAILURE", sizeof optbuf);
firstone = FALSE;
}
if (bitset(QPINGONDELAY, to->q_flags))
{
if (!firstone)
(void) strlcat(bufp, ",",
sizeof optbuf);
(void) strlcat(bufp, "DELAY", sizeof optbuf);
firstone = FALSE;
}
if (firstone)
(void) strlcat(bufp, "NEVER", sizeof optbuf);
bufp += strlen(bufp);
}
/* ORCPT= parameter */
if (to->q_orcpt != NULL &&
SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
{
snprintf(bufp, SPACELEFT(optbuf, bufp),
" ORCPT=%s", to->q_orcpt);
bufp += strlen(bufp);
}
}
smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
SmtpPhase = mci->mci_phase = "client RCPT";
sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
CurHostName, mci->mci_phase);
r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc);
to->q_rstatus = newstr(SmtpReplyBuffer);
to->q_status = ENHSCN(enhsc, smtptodsn(r));
if (!bitnset(M_LMTP, m->m_flags))
to->q_statmta = mci->mci_host;
if (r < 0 || REPLYTYPE(r) == 4)
return EX_TEMPFAIL;
else if (REPLYTYPE(r) == 2)
return EX_OK;
else if (r == 550)
{
to->q_status = ENHSCN(enhsc, "5.1.1");
return EX_NOUSER;
}
else if (r == 551)
{
to->q_status = ENHSCN(enhsc, "5.1.6");
return EX_NOUSER;
}
else if (r == 553)
{
to->q_status = ENHSCN(enhsc, "5.1.3");
return EX_NOUSER;
}
else if (REPLYTYPE(r) == 5)
{
return EX_UNAVAILABLE;
}
if (LogLevel > 1)
{
sm_syslog(LOG_CRIT, e->e_id,
"%.100s: SMTP RCPT protocol error: %s",
CurHostName,
shortenstring(SmtpReplyBuffer, 403));
}
mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
SmtpReplyBuffer);
return EX_PROTOCOL;
}
/*
** SMTPDATA -- send the data and clean up the transaction.
**
** Parameters:
** m -- mailer being sent to.
** mci -- the mailer connection information.
** e -- the envelope for this message.
**
** Returns:
** exit status corresponding to DATA command.
**
** Side Effects:
** none.
*/
static jmp_buf CtxDataTimeout;
int
smtpdata(m, mci, e)
MAILER *m;
register MCI *mci;
register ENVELOPE *e;
{
register int r;
register EVENT *ev;
int rstat;
int xstat;
time_t timeout;
char *enhsc;
enhsc = NULL;
/*
** Send the data.
** First send the command and check that it is ok.
** Then send the data.
** Follow it up with a dot to terminate.
** Finally get the results of the transaction.
*/
/* send the command and check ok to proceed */
smtpmessage("DATA", m, mci);
SmtpPhase = mci->mci_phase = "client DATA 354";
sm_setproctitle(TRUE, e, "%s %s: %s",
qid_printname(e), CurHostName, mci->mci_phase);
r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc);
if (r < 0 || REPLYTYPE(r) == 4)
{
smtpquit(m, mci, e);
return EX_TEMPFAIL;
}
else if (REPLYTYPE(r) == 5)
{
smtprset(m, mci, e);
return EX_UNAVAILABLE;
}
else if (REPLYTYPE(r) != 3)
{
if (LogLevel > 1)
{
sm_syslog(LOG_CRIT, e->e_id,
"%.100s: SMTP DATA-1 protocol error: %s",
CurHostName,
shortenstring(SmtpReplyBuffer, 403));
}
smtprset(m, mci, e);
mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
SmtpReplyBuffer);
return EX_PROTOCOL;
}
/*
** Set timeout around data writes. Make it at least large
** enough for DNS timeouts on all recipients plus some fudge
** 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);
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -