gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnurl] 156/282: smtp: Support UTF-8 based host names in the MAIL comman


From: gnunet
Subject: [gnurl] 156/282: smtp: Support UTF-8 based host names in the MAIL command
Date: Wed, 01 Apr 2020 14:30:21 +0200

This is an automated email from the git hooks/post-receive script.

ng0 pushed a commit to branch master
in repository gnurl.

commit 68fb25fa3fcff62dda71d2c67894eedf93291e05
Author: Steve Holme <address@hidden>
AuthorDate: Fri Feb 7 15:53:25 2020 +0000

    smtp: Support UTF-8 based host names in the MAIL command
    
    Non-ASCII host names will be ACE encoded if IDN is supported.
---
 lib/smtp.c                      | 127 ++++++++++++++++++++++++++++++++++++++--
 tests/data/Makefile.inc         |   2 +-
 tests/data/test959              |   3 +
 tests/data/{test959 => test962} |  23 +++++---
 4 files changed, 141 insertions(+), 14 deletions(-)

diff --git a/lib/smtp.c b/lib/smtp.c
index 7bcff0ce7..18c45afbe 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -27,6 +27,8 @@
  * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
  * RFC4954 SMTP Authentication
  * RFC5321 SMTP protocol
+ * RFC5890 Internationalized Domain Names for Applications (IDNA)
+ * RFC6531 SMTP Extension for Internationalized Email
  * RFC6749 OAuth 2.0 Authorization Framework
  * RFC8314 Use of TLS for Email Submission and Access
  * Draft   SMTP URL Interface   <draft-earhart-url-smtp-00.txt>
@@ -101,6 +103,8 @@ static CURLcode smtp_setup_connection(struct connectdata 
*conn);
 static CURLcode smtp_parse_url_options(struct connectdata *conn);
 static CURLcode smtp_parse_url_path(struct connectdata *conn);
 static CURLcode smtp_parse_custom_request(struct connectdata *conn);
+static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
+                                   char **address, struct hostname *host);
 static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
                                   const char *initresp);
 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
@@ -516,18 +520,58 @@ static CURLcode smtp_perform_mail(struct connectdata 
*conn)
   if(!data->set.str[STRING_MAIL_FROM])
     /* Null reverse-path, RFC-5321, sect. 3.6.3 */
     from = strdup("<>");
-  else if(data->set.str[STRING_MAIL_FROM][0] == '<')
-    from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
-  else
-    from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
+  else {
+    char *address = NULL;
+    struct hostname host = { NULL, NULL, NULL, NULL };
+
+    /* Parse the FROM mailbox into the local address and host name parts,
+       converting the host name to an IDN A-label if necessary */
+    result = smtp_parse_address(conn, data->set.str[STRING_MAIL_FROM],
+                                &address, &host);
+    if(result)
+      return result;
+
+    if(host.name) {
+      from = aprintf("<%s@%s>", address, host.name);
+
+      Curl_free_idnconverted_hostname(&host);
+    }
+    else
+      /* An invalid mailbox was provided but we'll simply let the server worry
+         about that and reply with a 501 error */
+      from = aprintf("<%s>", address);
+
+    free(address);
+  }
 
   if(!from)
     return CURLE_OUT_OF_MEMORY;
 
   /* Calculate the optional AUTH parameter */
   if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
-    if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
-      auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
+    if(data->set.str[STRING_MAIL_AUTH][0] != '\0') {
+      char *address = NULL;
+      struct hostname host = { NULL, NULL, NULL, NULL };
+
+      /* Parse the AUTH mailbox into the local address and host name parts,
+         converting the host name to an IDN A-label if necessary */
+      result = smtp_parse_address(conn, data->set.str[STRING_MAIL_AUTH],
+                                  &address, &host);
+      if(result)
+        return result;
+
+      if(host.name) {
+        from = aprintf("<%s@%s>", address, host.name);
+
+        Curl_free_idnconverted_hostname(&host);
+      }
+      else
+        /* An invalid mailbox was provided but we'll simply let the server
+           worry about it */
+        auth = aprintf("<%s>", address);
+
+      free(address);
+    }
     else
       /* Empty AUTH, RFC-2554, sect. 5 */
       auth = strdup("<>");
@@ -561,6 +605,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
     if(result) {
       free(from);
       free(auth);
+
       return result;
     }
 
@@ -1566,6 +1611,76 @@ static CURLcode smtp_parse_custom_request(struct 
connectdata *conn)
   return result;
 }
 
+/***********************************************************************
+ *
+ * smtp_parse_address()
+ *
+ * Parse the fully qualified mailbox address into a local address part and the
+ * host name, converting the host name to an IDN A-label, as per RFC-5890, if
+ * necessary.
+ *
+ * Parameters:
+ *
+ * conn  [in]              - The connection handle.
+ * fqma  [in]              - The fully qualified mailbox address (which may or
+ *                           may not contain UTF-8 characters).
+ * address        [in/out] - A new allocated buffer which holds the local
+ *                           address part of the mailbox. This buffer must be
+ *                           free'ed by the caller.
+ * host           [in/out] - The host name structure that holds the original,
+ *                           and optionally encoded, host name.
+ *                           Curl_free_idnconverted_hostname() must be called
+ *                           once the caller has finished with the structure.
+ *
+ * Returns CURLE_OK on success.
+ *
+ * Notes:
+ *
+ * If an mailbox '@' seperator cannot be located then the mailbox is considered
+ * to be either a local mailbox or an invalid mailbox (depending on what the
+ * calling function deems it to be) then the input will simply be returned in
+ * the address part with the host name being NULL.
+ */
+static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
+                                   char **address, struct hostname *host)
+{
+  CURLcode result = CURLE_OK;
+  size_t length;
+
+  /* Duplicate the fully qualified email address so we can manipulate it,
+     ensuring it doesn't contain the delimiters if specified */
+  char *dup = strdup(fqma[0] == '<' ? fqma + 1  : fqma);
+  if(!dup)
+    return CURLE_OUT_OF_MEMORY;
+
+  length = strlen(dup);
+  if(dup[length - 1] == '>')
+    dup[length - 1] = '\0';
+
+  /* Extract the host name from the addresss (if we can) */
+  host->name = strpbrk(dup, "@");
+  if(host->name) {
+    *host->name = '\0';
+    host->name = host->name + 1;
+
+    /* Convert the host name to IDN ACE */
+    result = Curl_idnconvert_hostname(conn, host);
+    if(result) {
+      free(dup);
+      host->name = NULL;
+
+      return result;
+    }
+  }
+  else
+    host->name = NULL;
+
+  /* Extract the local address from the mailbox */
+  *address = dup;
+
+  return result;
+}
+
 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
 {
   /* When sending a SMTP payload we must detect CRLF. sequences making sure
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index 6cc6beb17..0f0192847 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -108,7 +108,7 @@ test918 test919 test920 test921 test922 test923 test924 
test925 test926 \
 test927 test928 test929 test930 test931 test932 test933 test934 test935 \
 test936 test937 test938 test939 test940 test941 test942 test943 test944 \
 test945 test946 test947 test948 test949 test950 test951 test952 test953 \
-test954 test955 test956 test957 test958 test959 test960 test961 \
+test954 test955 test956 test957 test958 test959 test960 test961 test962 \
 \
 test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \
 test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \
diff --git a/tests/data/test959 b/tests/data/test959
index 519aca45a..1de523cb3 100644
--- a/tests/data/test959
+++ b/tests/data/test959
@@ -16,6 +16,9 @@ SMTP
 <server>
 smtp
 </server>
+<features>
+!idn
+</features>
 <setenv>
 LC_ALL=en_US.UTF-8
 LC_CTYPE=en_US.UTF-8
diff --git a/tests/data/test959 b/tests/data/test962
similarity index 72%
copy from tests/data/test959
copy to tests/data/test962
index 519aca45a..b6ec405f1 100644
--- a/tests/data/test959
+++ b/tests/data/test962
@@ -2,6 +2,7 @@
 <info>
 <keywords>
 SMTP
+IDN
 </keywords>
 </info>
 
@@ -16,6 +17,9 @@ SMTP
 <server>
 smtp
 </server>
+<features>
+idn
+</features>
 <setenv>
 LC_ALL=en_US.UTF-8
 LC_CTYPE=en_US.UTF-8
@@ -33,21 +37,26 @@ To: another
 body
 </stdin>
 <command>
-smtp://%HOSTIP:%SMTPPORT/959 --mail-rcpt address@hidden --mail-from 
sender@åäö.se -T -
+smtp://%HOSTIP:%SMTPPORT/962 --mail-rcpt address@hidden --mail-from 
sender@åäö.se -T -
 </command>
 </client>
 
 #
 # Verify data after the test has been "shot"
 <verify>
-# 55 - CURLE_SEND_ERROR
-<errorcode>
-55
-</errorcode>
 <protocol>
-EHLO 959
-MAIL FROM:<sender@åäö.se>
+EHLO 962
+MAIL FROM:<address@hidden>
+RCPT TO:<address@hidden>
+DATA
 QUIT
 </protocol>
+<upload>
+From: different
+To: another
+
+body
+.
+</upload>
 </verify>
 </testcase>

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]