I have refined and more thoroughly tested a previous patch that relaxes the ORCPT address check.

Over the years mail has been rejected by senders that use RCPT TO commands like:
RCPT TO:<i...@exmpale.com> ORCPT=rfc822;groupwise-i...@example.com:0:0 or
RCPT TO:<i...@exmpale.com> ORCPT=rfc822;groupwise-i...@example.com:0:0 NOTIFY=SUCCESS,FAILURE

In the above the domain part of the ORCPT address resolves to example.com:0:0 which is rejected by smtpd with the message: smtpd[20797]: 1a3a396cd4c57d05 smtp failed-command command="RCPT TO:<i...@example.com> ORCPT=rfc822;groupwise-i...@example.com:0:0 NOTIFY=SUCCESS,FAILURE" result="553 ORCPT address syntax error"

I've studied RFC 3461 section 4 and 4.2 but it's not entirely clear to me if the above ORCPT command is valid or not. The encoding adheres to the spec, which says it must be valid xtext.

With this patch smtpd accepts any ORCPT that is valid xtext as defined in the RFC (and logs on informational message when it consists of an invalid user or domain name).

Cheers,

Tim

---
 usr.sbin/smtpd/smtp_session.c | 22 ++++++++++++++++++----
 usr.sbin/smtpd/smtpd.h        |  1 +
 usr.sbin/smtpd/util.c         | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index 72e13e8fd8d..c0c29d4a695 100644
--- a/usr.sbin/smtpd/smtp_session.c
+++ b/usr.sbin/smtpd/smtp_session.c
@@ -2415,6 +2415,7 @@ smtp_tx_create_message(struct smtp_tx *tx)
 static void
 smtp_tx_rcpt_to(struct smtp_tx *tx, const char *line)
 {
+       struct mailaddr orcptaddr;
        char *opt, *p;
        char *copy;
        char tmp[SMTP_LINE_MAX];
@@ -2469,10 +2470,23 @@ smtp_tx_rcpt_to(struct smtp_tx *tx, const char *line)
                        if (strncasecmp(opt, "rfc822;", 7) == 0)
                                opt += 7;

-                       if (!text_to_mailaddr(&tx->evp.dsn_orcpt, opt) ||
-                           !valid_localpart(tx->evp.dsn_orcpt.user) ||
-                           (strlen(tx->evp.dsn_orcpt.domain) != 0 &&
-                            !valid_domainpart(tx->evp.dsn_orcpt.domain))) {
+                       if (!text_to_mailaddr(&orcptaddr, opt)) {
+                               smtp_reply(tx->session,
+                                   "553 ORCPT address syntax error");
+                               return;
+                       }
+
+                       if (valid_localpart(orcptaddr.user) &&
+                           (strlen(orcptaddr.domain) != 0 &&
+                            valid_domainpart(orcptaddr.domain))) {
+                               tx->evp.dsn_orcpt = orcptaddr;
+                       } else if (valid_xtext(opt)) {
+                               log_info("%016"PRIx64" smtp "
+ "uncommon ORCPT: \"%s\", u:\"%s\", d:\"%s\"",
+                                   tx->session->id,
+                                   opt, orcptaddr.user, orcptaddr.domain);
+                               tx->evp.dsn_orcpt = orcptaddr;
+                       } else {
                                smtp_reply(tx->session,
                                    "553 ORCPT address syntax error");
                                return;
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 125a6a5dfbe..c59706885e2 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1702,6 +1702,7 @@ int mailaddr_match(const struct mailaddr *, const struct mailaddr *);
 int valid_localpart(const char *);
 int valid_domainpart(const char *);
 int valid_domainname(const char *);
+int valid_xtext(const char *s);
 int valid_smtp_response(const char *);
 int secure_file(int, char *, char *, uid_t, int);
 int  lowercase(char *, const char *, size_t);
diff --git a/usr.sbin/smtpd/util.c b/usr.sbin/smtpd/util.c
index feb663cc61e..0c4d0015fa4 100644
--- a/usr.sbin/smtpd/util.c
+++ b/usr.sbin/smtpd/util.c
@@ -515,6 +515,38 @@ valid_domainname(const char *str)
        return 1;
 }

+int
+valid_xtext(const char *s)
+{
+       while (*s != '\0') {
+               if (*s == '=')
+                       return 0;
+
+               if (*s < '\x21' || *s > '\x7e')
+                       return 0;
+
+               if (*s == '+') {
+                       /* expect hexchar "+XX" RFC 3461 4. */
+                       if (strnlen(s, 3) != 3)
+                               return 0;
+
+                       s++;
+
+                       if (!isdigit(*s) && !isupper(*s))
+                               return 0;
+
+                       s++;
+
+                       if (!isdigit(*s) && !isupper(*s))
+                               return 0;
+               }
+
+               s++;
+       }
+
+       return 1;
+}
+
 int
 valid_smtp_response(const char *s)
 {
--
2.37.3

Reply via email to