1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

- Proper handling of STARTTLS on SMTP, taking CURLUSESSL_TRY into account.

- SMTP falls back to RFC821 HELO when EHLO fails (and SSL is not required).
- Use of true local host name (i.e.: via gethostname()) when available, as default argument to SMTP HELO/EHLO.
- Test case 804 for HELO fallback.
This commit is contained in:
Patrick Monnerat 2010-02-22 12:41:02 +00:00
parent 2abcd132f8
commit 338553eda3
7 changed files with 147 additions and 17 deletions

View File

@ -6,6 +6,13 @@
Changelog
Patrick Monnerat (22 Feb 2010)
- Proper handling of STARTTLS on SMTP, taking CURLUSESSL_TRY into account.
- SMTP falls back to RFC821 HELO when EHLO fails (and SSL is not required).
- Use of true local host name (i.e.: via gethostname()) when available, as
default argument to SMTP HELO/EHLO.
- Test case 804 for HELO fallback.
Daniel Stenberg (20 Feb 2010)
- Fixed the SMTP compliance by making sure RCPT TO addresses are specified
properly in angle brackets. Recipients provided with CURLOPT_MAIL_RCPT now

View File

@ -66,7 +66,10 @@ This document lists documents and standards used by curl.
RFC 2818 - HTTP Over TLS (TLS is the successor to SSL)
RFC 2821 - SMTP protocol
RFC 2964 - Use of HTTP State Management
RFC 2965 - HTTP State Management Mechanism. Cookies. Obsoletes RFC2109
RFC 3207 - SMTP over TLS

View File

@ -19,6 +19,7 @@
* KIND, either express or implied.
*
* RFC2821 SMTP protocol
* RFC3207 SMTP over TLS
*
* $Id$
***************************************************************************/
@ -228,6 +229,7 @@ static void state(struct connectdata *conn,
"STOP",
"SERVERGREET",
"EHLO",
"HELO",
"STARTTLS",
"MAIL",
"RCPT",
@ -253,11 +255,26 @@ static CURLcode smtp_state_ehlo(struct connectdata *conn)
/* send EHLO */
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "EHLO %s", smtpc->domain);
if(result)
return result;
state(conn, SMTP_EHLO);
return CURLE_OK;
}
static CURLcode smtp_state_helo(struct connectdata *conn)
{
CURLcode result;
struct smtp_conn *smtpc = &conn->proto.smtpc;
/* send HELO */
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "HELO %s", smtpc->domain);
if(result)
return result;
state(conn, SMTP_HELO);
return CURLE_OK;
}
@ -278,9 +295,13 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
struct SessionHandle *data = conn->data;
(void)instate; /* no use for this yet */
if(smtpcode != 'O') {
failf(data, "STARTTLS denied. %c", smtpcode);
result = CURLE_LOGIN_DENIED;
if(smtpcode != 220) {
if(data->set.ftp_ssl == CURLUSESSL_TRY)
state(conn, SMTP_STOP);
else {
failf(data, "STARTTLS denied. %c", smtpcode);
result = CURLE_LOGIN_DENIED;
}
}
else {
/* Curl_ssl_connect is BLOCKING */
@ -290,7 +311,6 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
result = smtp_state_ehlo(conn);
}
}
state(conn, SMTP_STOP);
return result;
}
@ -304,13 +324,45 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn,
(void)instate; /* no use for this yet */
if(smtpcode/100 != 2) {
if(data->set.ftp_ssl > CURLUSESSL_TRY && !conn->ssl[FIRSTSOCKET].use)
result = smtp_state_helo(conn);
else {
failf(data, "Access denied: %d", smtpcode);
result = CURLE_LOGIN_DENIED;
}
}
else if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
/* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
to TLS connection now */
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "STARTTLS", NULL);
state(conn, SMTP_STARTTLS);
}
else {
/* end the connect phase */
state(conn, SMTP_STOP);
}
return result;
}
/* for HELO responses */
static CURLcode smtp_state_helo_resp(struct connectdata *conn,
int smtpcode,
smtpstate instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
(void)instate; /* no use for this yet */
if(smtpcode/100 != 2) {
failf(data, "Access denied: %d", smtpcode);
result = CURLE_LOGIN_DENIED;
}
/* end the connect phase */
state(conn, SMTP_STOP);
else {
/* end the connect phase */
state(conn, SMTP_STOP);
}
return result;
}
@ -478,14 +530,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
return CURLE_FTP_WEIRD_SERVER_REPLY;
}
if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
/* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
to TLS connection now */
result = Curl_pp_sendf(&smtpc->pp, "STARTTLS", NULL);
state(conn, SMTP_STARTTLS);
}
else
result = smtp_state_ehlo(conn);
result = smtp_state_ehlo(conn);
if(result)
return result;
break;
@ -494,6 +539,10 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
break;
case SMTP_HELO:
result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
break;
case SMTP_MAIL:
result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
break;
@ -597,6 +646,10 @@ static CURLcode smtp_connect(struct connectdata *conn,
const char *path = conn->data->state.path;
int len;
#ifdef HAVE_GETHOSTNAME
char localhost[1024 + 1];
#endif
*done = FALSE; /* default to not done yet */
/* If there already is a protocol-specific struct allocated for this
@ -660,8 +713,14 @@ static CURLcode smtp_connect(struct connectdata *conn,
pp->endofresp = smtp_endofresp;
pp->conn = conn;
if(!*path)
if(!*path) {
#ifdef HAVE_GETHOSTNAME
if(!gethostname(localhost, sizeof localhost))
path = localhost;
else
#endif
path = "localhost";
}
/* url decode the path and use it as domain with EHLO */
smtpc->domain = curl_easy_unescape(conn->data, path, 0, &len);

View File

@ -33,6 +33,7 @@ typedef enum {
SMTP_SERVERGREET, /* waiting for the initial greeting immediately after
a connect */
SMTP_EHLO,
SMTP_HELO,
SMTP_STARTTLS,
SMTP_MAIL, /* MAIL FROM */
SMTP_RCPT, /* RCPT TO */

View File

@ -7,3 +7,4 @@
564
802
803
804

View File

@ -65,7 +65,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
test564 test1101 test1102 test1103 test1104 test299 test310 test311 \
test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
test1107 test1108 test1109 test1110 test1111 test1112 test129 test567 \
test568 test569 test570 test571
test568 test569 test570 test571 test804
filecheck:
@mkdir test-place; \

59
tests/data/test804 Normal file
View File

@ -0,0 +1,59 @@
<testcase>
<info>
<keywords>
SMTP
SMTP HELO
RFC821
</keywords>
</info>
#
# Server-side
<reply>
<servercmd>
REPLY EHLO 500 Command unrecognized
REPLY HELO 250 Already old but still servicing...
</servercmd>
</reply>
#
# Client-side
<client>
<server>
smtp
</server>
<name>
RFC821-only SMTP server (EHLO not supported)
</name>
<stdin>
From: different
To: another
body
</stdin>
<command>
smtp://%HOSTIP:%SMTPPORT/user --mail-rcpt 804@foo --mail-from 804@from -T -
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<protocol>
EHLO user
HELO user
MAIL FROM:804@from
RCPT TO:<804@foo>
DATA
QUIT
</protocol>
<upload>
From: different
To: another
body
.
</upload>
</verify>
</testcase>