Hi Harri,

we had issues with e-mails containing ORCPT as well and fixed the
rejection with a patch. Originally, we created the patch when 6.7 was
out and applied it to the version of OpenSMTPD available in the FreeBSD
ports.

As of today, OpenSMTPD 6.8 is available in the FreeBSD ports system.
The attached patches can be applied to this version (if you are on
FreeBSD, just put them into ports/mail/opensmtpd/files).

If needed, I can massage the patches so they can be applied against the
OpenBSD base as well, where OpenSMTPD resides in nowadays (we mainly
use it on FreeBSD). I did not do this yet, since I wanted to provide a
quick answer.

In our case, the above mentioned groupware introduced characters in the
ORCPT field (colons.., 0x3a), that led smtp_tx_rcpt_to()
(usr.sbin/smtpd/smtp_session.c) to return with "553 ORCPT address
syntax error".

RFC3461 led us to the solution we are using today.

In section 4.2 [1], the ABNF of ORCPT is defined as:

> orcpt-parameter = "ORCPT=" original-recipient-address
>       original-recipient-address = addr-type ";" xtext
>       addr-type = atom

The log you see is:

> May 27 08:42:30 mymta smtpd[10310]: f06a752b657b4a05 smtp failed-
> command command="RCPT TO:<u...@example.com>
> ORCPT=rfc822;u...@example.com" result="550 Invalid recipient:
> <u...@example.com>"

According to the ABNF of ORCPT, everything after addr-type ";"
("rfc822;" in your case) is supposed to be xtext, which is described a
bit earlier in the introductory part of section 4 [2].

> xtext = *( xchar / hexchar )
> 
> xchar = any ASCII CHAR between "!" (33) and "~" (126) inclusive,
>         except for "+" and "=".
> 
> ; "hexchar"s are intended to encode octets that cannot appear
> ; as ASCII characters within an esmtp-value.
> 
> hexchar = ASCII "+" immediately followed by two upper case
>           hexadecimal digits

smtp_tx_rcpt_to() in usr.sbin/smtpd/smtp_session.c tries to convert the
text of the ORCPT DSN into an e-mail address and wants to check the
validity of the local and the domain part. We replaced this check, are
validating the xtext portion as specified above and are replying with a
more precise error message if this check fails:

 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 (!valid_xtext(opt)) {
         smtp_reply(tx->session,
-            "553 ORCPT address syntax error");
+            "553 ORCPT xtext syntax error");
         return;
 }


In usr.sbin/smtpd/util.c we added valid_xtext():

+int
+valid_xtext(const char *s)
+{
+        while (*s != '\0') {
+                if(*s == '\x2b' || *s == '\x3d') {
+                        return 0;
+                } else if(*s <= '\x21' || *s >= '\x7e') {
+                        return 0;
+                } else {
+                        s++;
+                        continue;
+                }
+                return 0;
+        }
+        return 1;
+}

I hope this helps to narrow down your issue a bit. What kind of non-e-
mailish characters do you see in the ORCPT?

In our case, the xtext portion of the ORCPT quite often contained valid
e-mail addresses, but sometimes, it did not. As far as we understood
the RFCs, xtext doas not necessarily need to be an e-mail address. This
is why we decided to replace the original check. The above mentioned
groupware used colons as field separators inside the xtext portion to
keep track of the communication belonging to certain thread or, well,
recipients.

What do the others think of the way we are handling the ORCPT?

Cheers

Frank



[1] https://datatracker.ietf.org/doc/html/rfc3461#section-4.2
[2] https://datatracker.ietf.org/doc/html/rfc3461#section-4




On Mon, 2022-05-30 at 09:04 +0200, Harald Dunkel wrote:
> Hi folks,
> 
> my MTA (opensmtpd on OpenBSD 7.0) rejects a few EMails with
> a message like
> 
> May 27 08:42:30 mymta smtpd[10310]: f06a752b657b4a05 smtp failed-
> command command="RCPT TO:<u...@example.com>
> ORCPT=rfc822;u...@example.com" result="550 Invalid recipient:
> <u...@example.com>"
> 
> in /var/log/maillog. The EMails to u...@example.com without
> "ORCPT=rfc822;" are accepted and forwarded as usual. All EMails
> with "ORCPT=rfc822;" to any user are rejected.
> 
> I have found https://github.com/OpenSMTPD/OpenSMTPD/issues/658
> of course, but I don't see a configuration issue on my side.
> My MTA is just an MTA, there are no local users except for root.
> 
> Every insightful comment is highly appreciated
> 
> Harri
> 

--- usr.sbin/smtpd/util.c.orig	2022-05-30 14:20:25 UTC
+++ usr.sbin/smtpd/util.c
@@ -532,6 +532,23 @@ valid_domainname(const char *str)
 }
 
 int
+valid_xtext(const char *s)
+{
+	while (*s != '\0') {
+		if(*s == '\x2b' || *s == '\x3d') {
+			return 0;
+		} else if(*s <= '\x21' || *s >= '\x7e') {
+			return 0;
+		} else {
+			s++;
+			continue;
+		}
+		return 0;
+	}
+	return 1;
+}
+
+int
 valid_smtp_response(const char *s)
 {
 	if (strlen(s) < 5)
--- usr.sbin/smtpd/smtpd.h.orig	2022-05-30 14:23:33 UTC
+++ usr.sbin/smtpd/smtpd.h
@@ -1735,6 +1735,7 @@ int mailaddr_match(const struct mailaddr *, const stru
 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);
--- usr.sbin/smtpd/smtp_session.c.orig	2022-05-30 14:24:52 UTC
+++ usr.sbin/smtpd/smtp_session.c
@@ -2591,12 +2591,9 @@ 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 (!valid_xtext(opt)) {
 				smtp_reply(tx->session,
-				    "553 ORCPT address syntax error");
+				    "553 ORCPT xtext syntax error");
 				return;
 			}
 		} else {

Reply via email to