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:<[email protected]>
ORCPT=rfc822;[email protected]:0:0 or RCPT
TO:<[email protected]> ORCPT=rfc822;[email protected]: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:<[email protected]> ORCPT=rfc822;[email protected]: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