smtp: Moved EHLO response handling to smtp_state_ehlo_resp()

Similar to the processing of untagged CAPABILITY responses in IMAP moved
the processing of multiline EHLO responses to smtp_state_ehlo_resp() and
introduced an internal response code of one to differentiate a multiline
continuation from the end of command. This also allows for the separate
processing of multiline responses from commands such as VRFY and EXPN.
This commit is contained in:
Steve Holme 2013-11-15 10:46:29 +00:00
parent 786cba1ada
commit f16c0de4e9
1 changed files with 93 additions and 79 deletions

View File

@ -230,78 +230,27 @@ static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
{
struct smtp_conn *smtpc = &conn->proto.smtpc;
bool result = FALSE;
size_t wordlen;
/* Nothing for us */
if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
return FALSE; /* Nothing for us */
return FALSE;
/* Do we have a command response? This should be the response code followed
by a space and optionally some text as per RFC-5321 and as outlined in
Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
only send the response code instead. */
result = (line[3] == ' ' || len == 5) ? TRUE : FALSE;
if(result)
only send the response code instead as per Section 4.2. */
if(line[3] == ' ' || len == 5) {
result = TRUE;
*resp = curlx_sltosi(strtol(line, NULL, 10));
/* Are we processing EHLO command data? */
if(smtpc->state == SMTP_EHLO && (!result || (result && *resp/100 == 2))) {
line += 4;
len -= 4;
/* Does the server support the STARTTLS capability? */
if(len >= 8 && !memcmp(line, "STARTTLS", 8))
smtpc->tls_supported = TRUE;
/* Does the server support the SIZE capability? */
else if(len >= 4 && !memcmp(line, "SIZE", 4))
smtpc->size_supported = TRUE;
/* Do we have the authentication mechanism list? */
else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
line += 5;
len -= 5;
/* Loop through the data line */
for(;;) {
while(len &&
(*line == ' ' || *line == '\t' ||
*line == '\r' || *line == '\n')) {
line++;
len--;
}
if(!len)
break;
/* Extract the word */
for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
line[wordlen] != '\t' && line[wordlen] != '\r' &&
line[wordlen] != '\n';)
wordlen++;
/* Test the word for a matching authentication mechanism */
if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
smtpc->authmechs |= SASL_MECH_LOGIN;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
smtpc->authmechs |= SASL_MECH_PLAIN;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
smtpc->authmechs |= SASL_MECH_CRAM_MD5;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
smtpc->authmechs |= SASL_MECH_GSSAPI;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
smtpc->authmechs |= SASL_MECH_EXTERNAL;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
smtpc->authmechs |= SASL_MECH_NTLM;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
smtpc->authmechs |= SASL_MECH_XOAUTH2;
line += wordlen;
len -= wordlen;
}
}
/* Make sure real server never sends internal value */
if(*resp == 1)
*resp = 0;
}
/* Do we have a multiline (continuation) response? */
else if(line[3] == '-') {
result = TRUE;
*resp = 1; /* Internal response code */
}
return result;
@ -774,10 +723,13 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
struct smtp_conn *smtpc = &conn->proto.smtpc;
const char *line = data->state.buffer;
size_t len = strlen(line);
size_t wordlen;
(void)instate; /* no use for this yet */
if(smtpcode/100 != 2) {
if(smtpcode/100 != 2 && smtpcode != 1) {
if((data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) &&
!conn->bits.user_passwd)
result = smtp_perform_helo(conn);
@ -786,21 +738,83 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
result = CURLE_REMOTE_ACCESS_DENIED;
}
}
else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
/* We don't have a SSL/TLS connection yet, but SSL is requested */
if(smtpc->tls_supported)
/* Switch to TLS connection now */
result = smtp_perform_starttls(conn);
else if(data->set.use_ssl == CURLUSESSL_TRY)
/* Fallback and carry on with authentication */
result = smtp_perform_authenticate(conn);
else {
failf(data, "STARTTLS not supported.");
result = CURLE_USE_SSL_FAILED;
else {
line += 4;
len -= 4;
/* Does the server support the STARTTLS capability? */
if(len >= 8 && !memcmp(line, "STARTTLS", 8))
smtpc->tls_supported = TRUE;
/* Does the server support the SIZE capability? */
else if(len >= 4 && !memcmp(line, "SIZE", 4))
smtpc->size_supported = TRUE;
/* Do we have the authentication mechanism list? */
else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
line += 5;
len -= 5;
/* Loop through the data line */
for(;;) {
while(len &&
(*line == ' ' || *line == '\t' ||
*line == '\r' || *line == '\n')) {
line++;
len--;
}
if(!len)
break;
/* Extract the word */
for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
line[wordlen] != '\t' && line[wordlen] != '\r' &&
line[wordlen] != '\n';)
wordlen++;
/* Test the word for a matching authentication mechanism */
if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
smtpc->authmechs |= SASL_MECH_LOGIN;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
smtpc->authmechs |= SASL_MECH_PLAIN;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
smtpc->authmechs |= SASL_MECH_CRAM_MD5;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
smtpc->authmechs |= SASL_MECH_GSSAPI;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
smtpc->authmechs |= SASL_MECH_EXTERNAL;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
smtpc->authmechs |= SASL_MECH_NTLM;
else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
smtpc->authmechs |= SASL_MECH_XOAUTH2;
line += wordlen;
len -= wordlen;
}
}
if(smtpcode != 1) {
if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
/* We don't have a SSL/TLS connection yet, but SSL is requested */
if(smtpc->tls_supported)
/* Switch to TLS connection now */
result = smtp_perform_starttls(conn);
else if(data->set.use_ssl == CURLUSESSL_TRY)
/* Fallback and carry on with authentication */
result = smtp_perform_authenticate(conn);
else {
failf(data, "STARTTLS not supported.");
result = CURLE_USE_SSL_FAILED;
}
}
else
result = smtp_perform_authenticate(conn);
}
}
else
result = smtp_perform_authenticate(conn);
return result;
}
@ -1344,7 +1358,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
return result;
/* Store the latest response for later retrieval */
if(smtpc->state != SMTP_QUIT)
if(smtpc->state != SMTP_QUIT && smtpcode != 1)
data->info.httpcode = smtpcode;
if(smtpcode) {