public inbox for pmg-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pmg-devel] [PATCH pmg-api v3 0/2] fix #2795 - add DSN support
@ 2021-11-25 19:19 Stoiko Ivanov
  2021-11-25 19:20 ` [pmg-devel] [PATCH pmg-api v3 1/2] partially fix #2795: allow for '>' in smtp parameters Stoiko Ivanov
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Stoiko Ivanov @ 2021-11-25 19:19 UTC (permalink / raw)
  To: pmg-devel

huge thanks again to Dominik for his testing and uncovering bugs!

v2->v3:
*  adapted the regular expression to also work if not parameters at all are
  provided (as happens in after-queue filtering)
* added the DSN-EHLO keyword (else the first postfix instance did send the
  notification - whereas we want to send the information on (so that a later
  system sends it)
* tried a bit more systematic testing (including changing between before and
  after queue filtering)

original cover-letter for v2:
v1->v2:
* incorporated Dominik's feedback - huge thanks!!
* all parameters we don't care about are ignored (as before)
* the options are not transformed into lowercase unconditionally anymore
  (they contain mail-addresses, and mail-ids - which are not case-insensitive)
* split up the patch into 2 commits - since the regexes for the MAIL and
  RCPT commands is more sensitive than I expected:
** read up on allowed characters in local-parts - tried extending the regex
   to parse mailboxes more correctly - failed at that
** decided it's ok to not allow '>' in localparts (we did not do so before)
** did quite a bit more testing thanks to that

Stoiko Ivanov (2):
  partially fix #2795: allow for '>' in smtp parameters
  fix #2795: add support for DSN

 src/PMG/RuleDB/Accept.pm |  2 +-
 src/PMG/RuleDB/BCC.pm    |  6 +++++-
 src/PMG/SMTP.pm          | 29 +++++++++++++++++++++++------
 src/PMG/Utils.pm         | 19 ++++++++++++++++---
 src/bin/pmg-smtp-filter  |  1 +
 5 files changed, 46 insertions(+), 11 deletions(-)

-- 
2.30.2





^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pmg-devel] [PATCH pmg-api v3 1/2] partially fix #2795: allow for '>' in smtp parameters
  2021-11-25 19:19 [pmg-devel] [PATCH pmg-api v3 0/2] fix #2795 - add DSN support Stoiko Ivanov
@ 2021-11-25 19:20 ` Stoiko Ivanov
  2021-11-25 19:20 ` [pmg-devel] [PATCH pmg-api v3 2/2] fix #2795: add support for DSN Stoiko Ivanov
  2021-11-26 11:59 ` [pmg-devel] applied-series: [PATCH pmg-api v3 0/2] fix #2795 - add DSN support Stoiko Ivanov
  2 siblings, 0 replies; 4+ messages in thread
From: Stoiko Ivanov @ 2021-11-25 19:20 UTC (permalink / raw)
  To: pmg-devel

The regular expressions parsing the MAIL and RCPT commands do not
cover the case where a esmtp parameter may contain angle brackets
(e.g. the ENVID parameter for the delivery status notification
extension - RFC3464 [0]).

following section 4.1.2 of RFC5321 [1] the regex is changed to:
* consider everything up to the first '>' the mailbox
* consider everything afterwards (if it starts with a ' ') as
  parameters
* since the parameter group might not match (in case no parameters are
  set - e.g. after-queue filtering) - default to '' if it's not
  defined

This is fairly robusts, only not parsing correctly if the local part
contains '>' (as quoted text) - but this did not work before anyways
(and causes problems in other places as well).

tested with:
```
cat test.eml | /usr/sbin/sendmail -N success,delay,failure \
-V '<someid@somehost>' \
-f '"local>part"@test.example' \
discard@test.example
```

[0] https://tools.ietf.org/html/rfc3464
[1] https://tools.ietf.org/html/rfc5321#section-4.1.2

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
 src/PMG/SMTP.pm | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/PMG/SMTP.pm b/src/PMG/SMTP.pm
index 68c833e..b3550d4 100644
--- a/src/PMG/SMTP.pm
+++ b/src/PMG/SMTP.pm
@@ -100,9 +100,9 @@ sub loop {
 	    $self->reply ("250 2.5.0 OK");
 	    next;
 	} elsif ($cmd eq 'mail') {
-	    if ($args =~ m/^from:\s*<([^\s\>]*)>([^>]*)$/i) {
+	    if ($args =~ m/^from:\s*<([^\s\>]*?)>( .*)?$/i) {
 		delete $self->{to};
-		my ($from, $opts) = ($1, $2);
+		my ($from, $opts) = ($1, $2 // '');
 		if ($opts =~ m/\sSMTPUTF8/) {
 		    $self->{smtputf8} = 1;
 		    $from = decode('UTF-8', $from);
@@ -115,7 +115,7 @@ sub loop {
 		next;
 	    }
 	} elsif ($cmd eq 'rcpt') {
-	    if ($args =~ m/^to:\s*<([^\s\>]+)>[^>]*$/i) {
+	    if ($args =~ m/^to:\s*<([^\s\>]+?)>( .*)?$/i) {
 		my $to = $self->{smtputf8} ? decode('UTF-8', $1) : $1;
 		push @{$self->{to}} , $to;
 		$self->reply ('250 2.5.0 OK');
-- 
2.30.2





^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pmg-devel] [PATCH pmg-api v3 2/2] fix #2795: add support for DSN
  2021-11-25 19:19 [pmg-devel] [PATCH pmg-api v3 0/2] fix #2795 - add DSN support Stoiko Ivanov
  2021-11-25 19:20 ` [pmg-devel] [PATCH pmg-api v3 1/2] partially fix #2795: allow for '>' in smtp parameters Stoiko Ivanov
@ 2021-11-25 19:20 ` Stoiko Ivanov
  2021-11-26 11:59 ` [pmg-devel] applied-series: [PATCH pmg-api v3 0/2] fix #2795 - add DSN support Stoiko Ivanov
  2 siblings, 0 replies; 4+ messages in thread
From: Stoiko Ivanov @ 2021-11-25 19:20 UTC (permalink / raw)
  To: pmg-devel

store the esmtp parameters for the MAIL and RCPT command needed to
support Delivery status notifications (DSN - RFC 3464 [0]) and pass
them to the outbound postfix instance (port 10025) used for sending
the mail further (see also [1]).

Postfix does syntax-checking before passing the mail to the proxy
also in before-queue filtering mode.

Since the handling is done by postfix we don't need to generate any
DSN in the regular case.
For mail put into quarantine I decided to skip sending a delivery
notification (on the expectation, that few people are using quarantine
outbound, and that I would not consider a mail put in quarantine as
delivered successfully)

We only store a whitelist of parameters, instead of passing all,
because some parameters might not be valid anymore after processing
(e.g. SIZE)

The DSN EHLO keyword was added for the after-queue filtering case -
else the inbound postfix is the system that sends out the
notification.

tested with various combinations of the -V, -N and -R parameters to
sendmail (e.g.):
```
/usr/sbin/sendmail -N success,delay,failure \
-V '<xxxxxxxx@test.proxmox.com>'\
-R hdrs test@test.domain.example
```
tested the following scenarios in before and after-queue filter mode:
* successful delivery
* successful delivery with set DSN
* failed delivery (recipient rejects with 544)
* failed delivery with DSN
* delivering a mail with empty envelope sender (bounce)

some tests with invalid combinations were also done with netcat.

[0] https://tools.ietf.org/html/rfc3464
[1] http://www.postfix.org/DSN_README.html

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
 src/PMG/RuleDB/Accept.pm |  2 +-
 src/PMG/RuleDB/BCC.pm    |  6 +++++-
 src/PMG/SMTP.pm          | 23 ++++++++++++++++++++---
 src/PMG/Utils.pm         | 19 ++++++++++++++++---
 src/bin/pmg-smtp-filter  |  1 +
 5 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/src/PMG/RuleDB/Accept.pm b/src/PMG/RuleDB/Accept.pm
index 0bcf250..cd67ea2 100644
--- a/src/PMG/RuleDB/Accept.pm
+++ b/src/PMG/RuleDB/Accept.pm
@@ -122,7 +122,7 @@ sub execute {
 	} else {
 	    my ($qid, $code, $mess) = PMG::Utils::reinject_mail(
 		$entity, $msginfo->{sender}, $tg,
-		$msginfo->{xforward}, $msginfo->{fqdn});
+		$msginfo->{xforward}, $msginfo->{fqdn}, $msginfo->{param});
 	    if ($qid) {
 		foreach (@$tg) {
 		    syslog('info', "%s: accept mail to <%s> (%s) (rule: %s)", $queue->{logid}, encode('UTF-8', $_), $qid, $rulename);
diff --git a/src/PMG/RuleDB/BCC.pm b/src/PMG/RuleDB/BCC.pm
index a8db3f5..d364690 100644
--- a/src/PMG/RuleDB/BCC.pm
+++ b/src/PMG/RuleDB/BCC.pm
@@ -156,9 +156,13 @@ sub execute {
 	    $entity->print ($fh);
 	    print $fh "bcc end\n";
 	} else {
+	    my $param = {};
+	    for my $bcc (@bcc_targets) {
+		$param->{rcpt}->{$bcc}->{notify} = "never";
+	    }
 	    my $qid = PMG::Utils::reinject_mail(
 		$entity, $msginfo->{sender}, \@bcc_targets,
-		$msginfo->{xforward}, $msginfo->{fqdn}, 1);
+		$msginfo->{xforward}, $msginfo->{fqdn}, $param);
 	    foreach (@bcc_targets) {
 		if ($qid) {
 		    syslog('info', "%s: bcc to <%s> (rule: %s, %s)", $queue->{logid}, $_, $rulename, $qid);
diff --git a/src/PMG/SMTP.pm b/src/PMG/SMTP.pm
index b3550d4..fbf5c95 100644
--- a/src/PMG/SMTP.pm
+++ b/src/PMG/SMTP.pm
@@ -38,6 +38,7 @@ sub reset {
     delete $self->{smtputf8};
     delete $self->{xforward};
     delete $self->{status};
+    delete $self->{param};
 }
 
 sub abort {
@@ -77,6 +78,7 @@ sub loop {
 	    $self->reply ("250-ENHANCEDSTATUSCODES");
 	    $self->reply ("250-8BITMIME");
 	    $self->reply ("250-SMTPUTF8");
+	    $self->reply ("250-DSN");
 	    $self->reply ("250-XFORWARD NAME ADDR PROTO HELO");
 	    $self->reply ("250 OK.");
 	    $self->{lmtp} = 1 if ($cmd eq 'lhlo');
@@ -103,9 +105,16 @@ sub loop {
 	    if ($args =~ m/^from:\s*<([^\s\>]*?)>( .*)?$/i) {
 		delete $self->{to};
 		my ($from, $opts) = ($1, $2 // '');
-		if ($opts =~ m/\sSMTPUTF8/) {
-		    $self->{smtputf8} = 1;
-		    $from = decode('UTF-8', $from);
+
+		for my $opt (split(' ', $opts)) {
+		    if ($opt =~ /(ret|envid)=([^ =]+)/i ) {
+			$self->{param}->{mail}->{$1} = $2;
+		    } elsif ($opt =~ m/smtputf8/i) {
+			$self->{smtputf8} = 1;
+			$from = decode('UTF-8', $from);
+		    } else {
+			#ignore everything else
+		    }
 		}
 		$self->{from} = $from;
 		$self->reply ('250 2.5.0 OK');
@@ -117,7 +126,15 @@ sub loop {
 	} elsif ($cmd eq 'rcpt') {
 	    if ($args =~ m/^to:\s*<([^\s\>]+?)>( .*)?$/i) {
 		my $to = $self->{smtputf8} ? decode('UTF-8', $1) : $1;
+		my $opts = $2 // '';
 		push @{$self->{to}} , $to;
+		for my $opt (split(' ', $opts)) {
+		    if ($opt =~ /(notify|orcpt)=([^ =]+)/i ) {
+			$self->{param}->{rcpt}->{$to}->{$1} = $2;
+		    } else {
+			#ignore everything else
+		    }
+		}
 		$self->reply ('250 2.5.0 OK');
 		next;
 	    } else {
diff --git a/src/PMG/Utils.pm b/src/PMG/Utils.pm
index 92c3a7a..4eebfa5 100644
--- a/src/PMG/Utils.pm
+++ b/src/PMG/Utils.pm
@@ -203,7 +203,7 @@ sub subst_values {
 }
 
 sub reinject_mail {
-    my ($entity, $sender, $targets, $xforward, $me, $nodsn) = @_;
+    my ($entity, $sender, $targets, $xforward, $me, $params) = @_;
 
     my $smtp;
     my $resid;
@@ -244,15 +244,28 @@ sub reinject_mail {
 	    $mail_opts .= " SMTPUTF8" if $has_utf8_targets;
 	}
 
+	if (defined($params->{mail})) {
+	    my $mailparams = $params->{mail};
+	    for my $p (keys %$mailparams) {
+		$mail_opts .= " $p=$mailparams->{$p}";
+	    }
+	}
+
 	if (!$smtp->_MAIL("FROM:" . $sender_addr . $mail_opts)) {
 	    syslog('err', "smtp error - got: %s %s", $smtp->code, scalar ($smtp->message));
 	    die "smtp from: ERROR";
 	}
 
-	my $rcpt_opts = $nodsn ? " NOTIFY=NEVER" : "";
-
 	foreach my $target (@$targets) {
 	    my $rcpt_addr;
+	    my $rcpt_opts = '';
+	    if (defined($params->{rcpt}->{$target})) {
+		my $rcptparams = $params->{rcpt}->{$target};
+		for my $p (keys %$rcptparams) {
+		    $rcpt_opts .= " $p=$rcptparams->{$p}";
+		}
+	    }
+
 	    if (utf8::is_utf8($target)) {
 		$rcpt_addr = encode('UTF-8', $smtp->_addr($target));
 	    } else {
diff --git a/src/bin/pmg-smtp-filter b/src/bin/pmg-smtp-filter
index b070c8e..45eb125 100755
--- a/src/bin/pmg-smtp-filter
+++ b/src/bin/pmg-smtp-filter
@@ -640,6 +640,7 @@ sub handle_smtp {
 	$msginfo->{sender} = $smtp->{from};
 	$msginfo->{xforward} = $smtp->{xforward};
 	$msginfo->{targets} = $smtp->{to};
+	$msginfo->{param} = $smtp->{param};
 
 	my $dkim_sign = $msginfo->{trusted} && $pmg_cfg->get('admin', 'dkim_sign');
 	if ($dkim_sign) {
-- 
2.30.2





^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pmg-devel] applied-series: [PATCH pmg-api v3 0/2] fix #2795 - add DSN support
  2021-11-25 19:19 [pmg-devel] [PATCH pmg-api v3 0/2] fix #2795 - add DSN support Stoiko Ivanov
  2021-11-25 19:20 ` [pmg-devel] [PATCH pmg-api v3 1/2] partially fix #2795: allow for '>' in smtp parameters Stoiko Ivanov
  2021-11-25 19:20 ` [pmg-devel] [PATCH pmg-api v3 2/2] fix #2795: add support for DSN Stoiko Ivanov
@ 2021-11-26 11:59 ` Stoiko Ivanov
  2 siblings, 0 replies; 4+ messages in thread
From: Stoiko Ivanov @ 2021-11-26 11:59 UTC (permalink / raw)
  To: pmg-devel

On Thu, 25 Nov 2021 20:19:59 +0100
Stoiko Ivanov <s.ivanov@proxmox.com> wrote:

> huge thanks again to Dominik for his testing and uncovering bugs!
> 
> v2->v3:
> *  adapted the regular expression to also work if not parameters at all are
>   provided (as happens in after-queue filtering)
> * added the DSN-EHLO keyword (else the first postfix instance did send the
>   notification - whereas we want to send the information on (so that a later
>   system sends it)
> * tried a bit more systematic testing (including changing between before and
>   after queue filtering)
> 
> original cover-letter for v2:
> v1->v2:
> * incorporated Dominik's feedback - huge thanks!!
> * all parameters we don't care about are ignored (as before)
> * the options are not transformed into lowercase unconditionally anymore
>   (they contain mail-addresses, and mail-ids - which are not case-insensitive)
> * split up the patch into 2 commits - since the regexes for the MAIL and
>   RCPT commands is more sensitive than I expected:
> ** read up on allowed characters in local-parts - tried extending the regex
>    to parse mailboxes more correctly - failed at that
> ** decided it's ok to not allow '>' in localparts (we did not do so before)
> ** did quite a bit more testing thanks to that
> 
> Stoiko Ivanov (2):
>   partially fix #2795: allow for '>' in smtp parameters
>   fix #2795: add support for DSN
> 
>  src/PMG/RuleDB/Accept.pm |  2 +-
>  src/PMG/RuleDB/BCC.pm    |  6 +++++-
>  src/PMG/SMTP.pm          | 29 +++++++++++++++++++++++------
>  src/PMG/Utils.pm         | 19 ++++++++++++++++---
>  src/bin/pmg-smtp-filter  |  1 +
>  5 files changed, 46 insertions(+), 11 deletions(-)
> 

for completeness' sake 
applied with Dominik's R-b and T-b
(see the thread of the v2)




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-11-26 11:59 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-25 19:19 [pmg-devel] [PATCH pmg-api v3 0/2] fix #2795 - add DSN support Stoiko Ivanov
2021-11-25 19:20 ` [pmg-devel] [PATCH pmg-api v3 1/2] partially fix #2795: allow for '>' in smtp parameters Stoiko Ivanov
2021-11-25 19:20 ` [pmg-devel] [PATCH pmg-api v3 2/2] fix #2795: add support for DSN Stoiko Ivanov
2021-11-26 11:59 ` [pmg-devel] applied-series: [PATCH pmg-api v3 0/2] fix #2795 - add DSN support Stoiko Ivanov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal