mirror of
https://github.com/curl/curl.git
synced 2025-02-23 15:10:03 +08: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:
parent
2abcd132f8
commit
338553eda3
7
CHANGES
7
CHANGES
@ -6,6 +6,13 @@
|
|||||||
|
|
||||||
Changelog
|
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)
|
Daniel Stenberg (20 Feb 2010)
|
||||||
- Fixed the SMTP compliance by making sure RCPT TO addresses are specified
|
- Fixed the SMTP compliance by making sure RCPT TO addresses are specified
|
||||||
properly in angle brackets. Recipients provided with CURLOPT_MAIL_RCPT now
|
properly in angle brackets. Recipients provided with CURLOPT_MAIL_RCPT now
|
||||||
|
@ -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 2818 - HTTP Over TLS (TLS is the successor to SSL)
|
||||||
|
|
||||||
|
RFC 2821 - SMTP protocol
|
||||||
|
|
||||||
RFC 2964 - Use of HTTP State Management
|
RFC 2964 - Use of HTTP State Management
|
||||||
|
|
||||||
RFC 2965 - HTTP State Management Mechanism. Cookies. Obsoletes RFC2109
|
RFC 2965 - HTTP State Management Mechanism. Cookies. Obsoletes RFC2109
|
||||||
|
|
||||||
|
RFC 3207 - SMTP over TLS
|
||||||
|
91
lib/smtp.c
91
lib/smtp.c
@ -19,6 +19,7 @@
|
|||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
* RFC2821 SMTP protocol
|
* RFC2821 SMTP protocol
|
||||||
|
* RFC3207 SMTP over TLS
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
@ -228,6 +229,7 @@ static void state(struct connectdata *conn,
|
|||||||
"STOP",
|
"STOP",
|
||||||
"SERVERGREET",
|
"SERVERGREET",
|
||||||
"EHLO",
|
"EHLO",
|
||||||
|
"HELO",
|
||||||
"STARTTLS",
|
"STARTTLS",
|
||||||
"MAIL",
|
"MAIL",
|
||||||
"RCPT",
|
"RCPT",
|
||||||
@ -253,11 +255,26 @@ static CURLcode smtp_state_ehlo(struct connectdata *conn)
|
|||||||
|
|
||||||
/* send EHLO */
|
/* send EHLO */
|
||||||
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "EHLO %s", smtpc->domain);
|
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "EHLO %s", smtpc->domain);
|
||||||
|
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
state(conn, SMTP_EHLO);
|
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;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,9 +295,13 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
|
|||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
(void)instate; /* no use for this yet */
|
(void)instate; /* no use for this yet */
|
||||||
|
|
||||||
if(smtpcode != 'O') {
|
if(smtpcode != 220) {
|
||||||
failf(data, "STARTTLS denied. %c", smtpcode);
|
if(data->set.ftp_ssl == CURLUSESSL_TRY)
|
||||||
result = CURLE_LOGIN_DENIED;
|
state(conn, SMTP_STOP);
|
||||||
|
else {
|
||||||
|
failf(data, "STARTTLS denied. %c", smtpcode);
|
||||||
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Curl_ssl_connect is BLOCKING */
|
/* Curl_ssl_connect is BLOCKING */
|
||||||
@ -290,7 +311,6 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
|
|||||||
result = smtp_state_ehlo(conn);
|
result = smtp_state_ehlo(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state(conn, SMTP_STOP);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,13 +324,45 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn,
|
|||||||
|
|
||||||
(void)instate; /* no use for this yet */
|
(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) {
|
if(smtpcode/100 != 2) {
|
||||||
failf(data, "Access denied: %d", smtpcode);
|
failf(data, "Access denied: %d", smtpcode);
|
||||||
result = CURLE_LOGIN_DENIED;
|
result = CURLE_LOGIN_DENIED;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* end the connect phase */
|
||||||
|
state(conn, SMTP_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end the connect phase */
|
|
||||||
state(conn, SMTP_STOP);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,14 +530,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
|
|||||||
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
|
result = smtp_state_ehlo(conn);
|
||||||
/* 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);
|
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
break;
|
break;
|
||||||
@ -494,6 +539,10 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
|
|||||||
result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
|
result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SMTP_HELO:
|
||||||
|
result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
|
||||||
|
break;
|
||||||
|
|
||||||
case SMTP_MAIL:
|
case SMTP_MAIL:
|
||||||
result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
|
result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
|
||||||
break;
|
break;
|
||||||
@ -597,6 +646,10 @@ static CURLcode smtp_connect(struct connectdata *conn,
|
|||||||
const char *path = conn->data->state.path;
|
const char *path = conn->data->state.path;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
#ifdef HAVE_GETHOSTNAME
|
||||||
|
char localhost[1024 + 1];
|
||||||
|
#endif
|
||||||
|
|
||||||
*done = FALSE; /* default to not done yet */
|
*done = FALSE; /* default to not done yet */
|
||||||
|
|
||||||
/* If there already is a protocol-specific struct allocated for this
|
/* 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->endofresp = smtp_endofresp;
|
||||||
pp->conn = conn;
|
pp->conn = conn;
|
||||||
|
|
||||||
if(!*path)
|
if(!*path) {
|
||||||
|
#ifdef HAVE_GETHOSTNAME
|
||||||
|
if(!gethostname(localhost, sizeof localhost))
|
||||||
|
path = localhost;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
path = "localhost";
|
path = "localhost";
|
||||||
|
}
|
||||||
|
|
||||||
/* url decode the path and use it as domain with EHLO */
|
/* url decode the path and use it as domain with EHLO */
|
||||||
smtpc->domain = curl_easy_unescape(conn->data, path, 0, &len);
|
smtpc->domain = curl_easy_unescape(conn->data, path, 0, &len);
|
||||||
|
@ -33,6 +33,7 @@ typedef enum {
|
|||||||
SMTP_SERVERGREET, /* waiting for the initial greeting immediately after
|
SMTP_SERVERGREET, /* waiting for the initial greeting immediately after
|
||||||
a connect */
|
a connect */
|
||||||
SMTP_EHLO,
|
SMTP_EHLO,
|
||||||
|
SMTP_HELO,
|
||||||
SMTP_STARTTLS,
|
SMTP_STARTTLS,
|
||||||
SMTP_MAIL, /* MAIL FROM */
|
SMTP_MAIL, /* MAIL FROM */
|
||||||
SMTP_RCPT, /* RCPT TO */
|
SMTP_RCPT, /* RCPT TO */
|
||||||
|
@ -7,3 +7,4 @@
|
|||||||
564
|
564
|
||||||
802
|
802
|
||||||
803
|
803
|
||||||
|
804
|
||||||
|
@ -65,7 +65,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
|
|||||||
test564 test1101 test1102 test1103 test1104 test299 test310 test311 \
|
test564 test1101 test1102 test1103 test1104 test299 test310 test311 \
|
||||||
test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
|
test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
|
||||||
test1107 test1108 test1109 test1110 test1111 test1112 test129 test567 \
|
test1107 test1108 test1109 test1110 test1111 test1112 test129 test567 \
|
||||||
test568 test569 test570 test571
|
test568 test569 test570 test571 test804
|
||||||
|
|
||||||
filecheck:
|
filecheck:
|
||||||
@mkdir test-place; \
|
@mkdir test-place; \
|
||||||
|
59
tests/data/test804
Normal file
59
tests/data/test804
Normal 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>
|
Loading…
Reference in New Issue
Block a user