📄 srvrsmtp.c
字号:
# if SASL
if (authenticating == SASL_PROC_AUTH)
{
# if 0
if (*inp == '\0')
{
authenticating = SASL_NOT_AUTH;
message("501 5.5.2 missing input");
continue;
}
# endif /* 0 */
if (*inp == '*' && *(inp + 1) == '\0')
{
authenticating = SASL_NOT_AUTH;
/* rfc 2254 4. */
message("501 5.0.0 AUTH aborted");
continue;
}
/* could this be shorter? XXX */
out = xalloc(strlen(inp));
result = sasl_decode64(inp, strlen(inp), out, &outlen);
if (result != SASL_OK)
{
authenticating = SASL_NOT_AUTH;
/* rfc 2254 4. */
message("501 5.5.4 cannot decode AUTH parameter %s",
inp);
continue;
}
result = sasl_server_step(conn, out, outlen,
&out, &outlen, &errstr);
/* get an OK if we're done */
if (result == SASL_OK)
{
authenticated:
message("235 2.0.0 OK Authenticated");
authenticating = SASL_IS_AUTH;
define(macid("{auth_type}", NULL),
newstr(auth_type), &BlankEnvelope);
result = sasl_getprop(conn, SASL_USERNAME,
(void **)&user);
if (result != SASL_OK)
{
user = "";
define(macid("{auth_authen}", NULL),
NULL, &BlankEnvelope);
}
else
{
define(macid("{auth_authen}", NULL),
newstr(user), &BlankEnvelope);
}
# if 0
/* get realm? */
sasl_getprop(conn, SASL_REALM, (void **) &data);
# endif /* 0 */
# if SFIO
/* get security strength (features) */
result = sasl_getprop(conn, SASL_SSF,
(void **) &ssf);
if (result != SASL_OK)
{
define(macid("{auth_ssf}", NULL),
"0", &BlankEnvelope);
ssf = NULL;
}
else
{
char pbuf[8];
snprintf(pbuf, sizeof pbuf, "%u", *ssf);
define(macid("{auth_ssf}", NULL),
newstr(pbuf), &BlankEnvelope);
if (tTd(95, 8))
dprintf("SASL auth_ssf: %u\n",
*ssf);
}
/*
** only switch to encrypted connection
** if a security layer has been negotiated
*/
if (ssf != NULL && *ssf > 0)
{
/*
** convert sfio stuff to use SASL
** check return values
** if the call fails,
** fall back to unencrypted version
** unless some cf option requires
** encryption then the connection must
** be aborted
*/
if (sfdcsasl(InChannel, OutChannel,
conn) == 0)
{
/* restart dialogue */
gothello = FALSE;
OneXact = TRUE;
n_helo = 0;
}
else
syserr("503 5.3.3 SASL TLS failed");
if (LogLevel > 9)
sm_syslog(LOG_INFO,
NOQID,
"SASL: connection from %.64s: mech=%.16s, id=%.64s, bits=%d",
CurSmtpClient,
auth_type, user,
*ssf);
}
# else /* SFIO */
if (LogLevel > 9)
sm_syslog(LOG_INFO, NOQID,
"SASL: connection from %.64s: mech=%.16s, id=%.64s",
CurSmtpClient, auth_type,
user);
# endif /* SFIO */
}
else if (result == SASL_CONTINUE)
{
len = ENC64LEN(outlen);
out2 = xalloc(len);
result = sasl_encode64(out, outlen, out2, len,
(u_int *)&out2len);
if (result != SASL_OK)
{
/* correct code? XXX */
/* 454 Temp. authentication failure */
message("454 4.5.4 Internal error: unable to encode64");
if (LogLevel > 5)
sm_syslog(LOG_WARNING, e->e_id,
"SASL encode64 error [%d for \"%s\"]",
result, out);
/* start over? */
authenticating = SASL_NOT_AUTH;
}
else
{
message("334 %s", out2);
if (tTd(95, 2))
dprintf("SASL continue: msg='%s' len=%d\n",
out2, out2len);
}
}
else
{
/* not SASL_OK or SASL_CONT */
message("500 5.7.0 authentication failed");
if (LogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
"AUTH failure (%s): %s (%d)",
auth_type,
sasl_errstring(result, NULL,
NULL),
result);
authenticating = SASL_NOT_AUTH;
}
}
else
{
/* don't want to do any of this if authenticating */
# endif /* SASL */
/* echo command to transcript */
if (e->e_xfp != NULL)
fprintf(e->e_xfp, "<<< %s\n", inp);
if (LogLevel >= 15)
sm_syslog(LOG_INFO, e->e_id,
"<-- %s",
inp);
if (e->e_id == NULL)
sm_setproctitle(TRUE, e, "%s: %.80s",
CurSmtpClient, inp);
else
sm_setproctitle(TRUE, e, "%s %s: %.80s",
qid_printname(e),
CurSmtpClient, inp);
/* break off command */
for (p = inp; isascii(*p) && isspace(*p); p++)
continue;
cmd = cmdbuf;
while (*p != '\0' &&
!(isascii(*p) && isspace(*p)) &&
cmd < &cmdbuf[sizeof cmdbuf - 2])
*cmd++ = *p++;
*cmd = '\0';
/* throw away leading whitespace */
while (isascii(*p) && isspace(*p))
p++;
/* decode command */
for (c = CmdTab; c->cmd_name != NULL; c++)
{
if (strcasecmp(c->cmd_name, cmdbuf) == 0)
break;
}
/* reset errors */
errno = 0;
/*
** Process command.
**
** If we are running as a null server, return 550
** to everything.
*/
if (nullserver != NULL || bitnset(D_ETRNONLY, d_flags))
{
switch (c->cmd_code)
{
case CMDQUIT:
case CMDHELO:
case CMDEHLO:
case CMDNOOP:
case CMDRSET:
/* process normally */
break;
case CMDETRN:
if (bitnset(D_ETRNONLY, d_flags) &&
nullserver == NULL)
break;
continue;
default:
if (++badcommands > MAXBADCOMMANDS)
{
delay *= 2;
if (delay >= MAXTIMEOUT)
delay = MAXTIMEOUT;
(void) sleep(delay);
}
if (nullserver != NULL)
{
if (ISSMTPREPLY(nullserver))
usrerr(nullserver);
else
usrerr("550 5.0.0 %s", nullserver);
}
else
usrerr("452 4.4.5 Insufficient disk space; try again later");
continue;
}
}
/* non-null server */
switch (c->cmd_code)
{
case CMDMAIL:
case CMDEXPN:
case CMDVRFY:
case CMDETRN:
lognullconnection = FALSE;
}
switch (c->cmd_code)
{
# if SASL
case CMDAUTH: /* sasl */
if (!sasl_ok)
{
message("503 5.3.3 AUTH not available");
break;
}
if (authenticating == SASL_IS_AUTH)
{
message("503 5.5.0 Already Authenticated");
break;
}
if (gotmail)
{
message("503 5.5.0 AUTH not permitted during a mail transaction");
break;
}
if (tempfail)
{
if (LogLevel > 9)
sm_syslog(LOG_INFO, e->e_id,
"SMTP AUTH command (%.100s) from %.100s tempfailed (due to previous checks)",
p, CurSmtpClient);
usrerr("454 4.7.1 Please try again later");
break;
}
ismore = FALSE;
/* crude way to avoid crack attempts */
(void) checksmtpattack(&n_auth, n_mechs + 1, TRUE,
"AUTH", e);
/* make sure it's a valid string */
for (q = p; *q != '\0' && isascii(*q); q++)
{
if (isspace(*q))
{
*q = '\0';
while (*++q != '\0' &&
isascii(*q) && isspace(*q))
continue;
*(q - 1) = '\0';
ismore = (*q != '\0');
break;
}
}
/* check whether mechanism is available */
if (iteminlist(p, mechlist, " ") == NULL)
{
message("503 5.3.3 AUTH mechanism %s not available",
p);
break;
}
if (ismore)
{
/* could this be shorter? XXX */
in = xalloc(strlen(q));
result = sasl_decode64(q, strlen(q), in,
(u_int *)&inlen);
if (result != SASL_OK)
{
message("501 5.5.4 cannot BASE64 decode '%s'",
q);
if (LogLevel > 5)
sm_syslog(LOG_WARNING, e->e_id,
"SASL decode64 error [%d for \"%s\"]",
result, q);
/* start over? */
authenticating = SASL_NOT_AUTH;
in = NULL;
inlen = 0;
break;
}
# if 0
if (tTd(95, 99))
{
int i;
dprintf("AUTH: more \"");
for (i = 0; i < inlen; i++)
{
if (isascii(in[i]) &&
isprint(in[i]))
dprintf("%c", in[i]);
else
dprintf("_");
}
dprintf("\"\n");
}
# endif /* 0 */
}
else
{
in = NULL;
inlen = 0;
}
/* see if that auth type exists */
result = sasl_server_start(conn, p, in, inlen,
&out, &outlen, &errstr);
if (result != SASL_OK && result != SASL_CONTINUE)
{
message("500 5.7.0 authentication failed");
if (LogLevel > 9)
sm_syslog(LOG_ERR, e->e_id,
"AUTH failure (%s): %s (%d)",
p,
sasl_errstring(result, NULL,
NULL),
result);
break;
}
auth_type = newstr(p);
if (result == SASL_OK)
{
/* ugly, but same code */
goto authenticated;
/* authenticated by the initial response */
}
/* len is at least 2 */
len = ENC64LEN(outlen);
out2 = xalloc(len);
result = sasl_encode64(out, outlen, out2, len,
(u_int *)&out2len);
if (result != SASL_OK)
{
message("454 4.5.4 Temporary authentication failure");
if (LogLevel > 5)
sm_syslog(LOG_WARNING, e->e_id,
"SASL encode64 error [%d for \"%s\"]",
result, out);
/* start over? */
authenticating = SASL_NOT_AUTH;
}
else
{
message("334 %s", out2);
authenticating = SASL_PROC_AUTH;
}
break;
# endif /* SASL */
# if STARTTLS
case CMDSTLS: /* starttls */
if (*p != '\0')
{
message("501 5.5.2 Syntax error (no parameters allowed)");
break;
}
if (!usetls)
{
message("503 5.5.0 TLS not available");
break;
}
if (!tls_ok)
{
message("454 4.3.3 TLS not available after start");
break;
}
if (gotmail)
{
message("503 5.5.0 TLS not permitted during a mail transaction");
break;
}
if (tempfail)
{
if (LogLevel > 9)
sm_syslog(LOG_INFO, e->e_id,
"SMTP STARTTLS command (%.100s) from %.100s tempfailed (due to previous checks)",
p, CurSmtpClient);
usrerr("454 4.7.1 Please try again later");
break;
}
# if TLS_NO_RSA
/*
** XXX do we need a temp key ?
*/
# else /* TLS_NO_RSA */
if (SSL_CTX_need_tmp_RSA(srv_ctx) &&
!SSL_CTX_set_tmp_rsa(srv_ctx,
(rsa = RSA_generate_key(RSA_KEYLENGTH, RSA_F4,
NULL, NULL)))
)
{
message("454 4.3.3 TLS not available: error generating RSA temp key");
if (rsa != NULL)
RSA_free(rsa);
break;
}
# endif /* TLS_NO_RSA */
if (srv_ssl != NULL)
SSL_clear(srv_ssl);
else if ((srv_ssl = SSL_new(srv_ctx)) == NULL)
{
message("454 4.3.3 TLS not available: error generating SSL handle");
break;
}
rfd = fileno(InChannel);
wfd = fileno(OutChannel);
if (rfd < 0 || wfd < 0 ||
SSL_set_rfd(srv_ssl, rfd) <= 0 ||
SSL_set_wfd(srv_ssl, wfd) <= 0)
{
message("454 4.3.3 TLS not available: error set fd");
SSL_free(srv_ssl);
srv_ssl = NULL;
break;
}
message("220 2.0.0 Ready to start TLS");
SSL_set_accept_state(srv_ssl);
# define SSL_ACC(s) SSL_accept(s)
if ((r = SSL_ACC(srv_ssl)) <= 0)
{
int i;
/* what to do in this case? */
i = SSL_get_error(srv_ssl, r);
if (LogLevel > 5)
{
sm_syslog(LOG_WARNING, e->e_id,
"TLS: error: accept failed=%d (%d)",
r, i);
if (LogLevel > 9)
tlslogerr();
}
tls_ok = FALSE;
SSL_free(srv_ssl);
srv_ssl = NULL;
/*
** according to the next draft of
** RFC 2487 the connection should be dropped
*/
/* arrange to ignore any current send list */
e->e_sendqueue = NULL;
goto doquit;
}
/* ignore return code for now, it's in {verify} */
(void) tls_get_info(srv_ssl, &BlankEnvelope, TRUE,
CurSmtpClient);
/*
** call Stls_client to find out whether
** to accept the connection from the client
*/
saveQuickAbort = QuickAbort;
saveSuprErrs = SuprErrs;
SuprErrs = TRUE;
QuickAbort = FALSE;
if (rscheck("tls_client",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -