]> granicus.if.org Git - curl/commitdiff
- Proper handling of STARTTLS on SMTP, taking CURLUSESSL_TRY into account.
authorPatrick Monnerat <Patrick.Monnerat@datasphere.ch>
Mon, 22 Feb 2010 12:41:02 +0000 (12:41 +0000)
committerPatrick Monnerat <Patrick.Monnerat@datasphere.ch>
Mon, 22 Feb 2010 12:41:02 +0000 (12:41 +0000)
- 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.

CHANGES
docs/RESOURCES
lib/smtp.c
lib/smtp.h
tests/data/DISABLED
tests/data/Makefile.am
tests/data/test804 [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 99c93dc9ea2516a4ed24b94692f702b9a121b069..79f0c6ed4b3bda4a3ea7dd117abdfea91730354d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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
index b8bfc2fbd7f41f022227a575bfbf000f469314eb..4d6465d6e52eb209d03ec0fd827765e51e629a20 100644 (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
index 238fc2dbb70fdf9e6b7d098f43381591f1f2faff..45df3042e71ef53cd28c7df923299ebcad357afa 100644 (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;
+  } 
+  else {
+    /* end the connect phase */
+    state(conn, SMTP_STOP);
   }
-
-  /* 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);
index 02cd467f55fada2be050efdb6721a394b991f977..41efabba4e9c65494c435df3ca409a838b784c47 100644 (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 */
index c65cdd90b9470e64113fcc9c92c942bd8e09f06b..24bc532c2c059bc3a48ac3031f43d8e7e29269d5 100644 (file)
@@ -7,3 +7,4 @@
 564
 802
 803
+804
index 0a9ac547c24d69efbad9eb92434dd7cbdf3689d4..1878e013ce30006c692b3cb79a2989e8898ca641 100644 (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; \
diff --git a/tests/data/test804 b/tests/data/test804
new file mode 100644 (file)
index 0000000..e1fc419
--- /dev/null
@@ -0,0 +1,59 @@
+<testcase>\r
+<info>\r
+<keywords>\r
+SMTP\r
+SMTP HELO\r
+RFC821\r
+</keywords>\r
+</info>\r
+\r
+#\r
+# Server-side\r
+<reply>\r
+<servercmd>\r
+REPLY EHLO 500 Command unrecognized\r
+REPLY HELO 250 Already old but still servicing...\r
+</servercmd>\r
+</reply>\r
+\r
+#\r
+# Client-side\r
+<client>\r
+<server>\r
+smtp\r
+</server>\r
+ <name>\r
+RFC821-only SMTP server (EHLO not supported)\r
+ </name>\r
+<stdin>\r
+From: different\r
+To: another\r
+\r
+body\r
+</stdin>\r
+ <command>\r
+smtp://%HOSTIP:%SMTPPORT/user --mail-rcpt 804@foo --mail-from 804@from -T -\r
+</command>\r
+</client>\r
+\r
+#\r
+# Verify data after the test has been "shot"\r
+<verify>\r
+<protocol>\r
+EHLO user\r\r
+HELO user\r\r
+MAIL FROM:804@from\r\r
+RCPT TO:<804@foo>\r\r
+DATA\r\r
+QUIT\r\r
+</protocol>\r
+<upload>\r
+From: different\r
+To: another\r
+\r
+body\r
+\r\r
+.\r\r
+</upload>\r
+</verify>\r
+</testcase>\r