Wietse Venema:
> Wietse Venema:
> > Wietse Venema:
> > > However, when luser_relay handes mail for a non-existent recipient,
> > > and it is configured with a non-existent local user, then the local
> > > delivery agent will go through the same code path twice with the
> > > same address, in which case the duplicate suppressor will silently
> > > terminate the recursion like it does for all other deliveries.
> > >
> > > This may or may not be easy to fix. For now, don't configure
> > > luser_relay with a non-existent address, just like postmaster, if
> > > you don't want errors to go unreported.
> >
> > Easy enough: I was able to fix this on the train. If luser_relay
> > specifies a non-existent local address, then the luser_relay feature
> > becomes a black hole. This was introduced three months after the
> > first public release, on 19990302. This patch should apply to every
> > supported Postfix release.
>
> The patch needs to be updated for the case that luser_relay specifies
> a bare address (no @domain). I'll revisit this in the next day or so.
Done.
Wietse
diff -ur /var/tmp/postfix-3.4-20180222/src/local/unknown.c src/local/unknown.c
--- /var/tmp/postfix-3.4-20180222/src/local/unknown.c 2015-01-11
15:30:20.000000000 -0500
+++ src/local/unknown.c 2018-03-06 19:29:36.168526066 -0500
@@ -73,11 +73,14 @@
#include <sent.h>
#include <deliver_pass.h>
#include <defer.h>
+#include <canon_addr.h>
/* Application-specific. */
#include "local.h"
+#define STREQ(x,y) (strcasecmp((x),(y)) == 0)
+
/* deliver_unknown - delivery for unknown recipients */
int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
@@ -85,6 +88,7 @@
const char *myname = "deliver_unknown";
int status;
VSTRING *expand_luser;
+ VSTRING *canon_luser;
static MAPS *transp_maps;
const char *map_transport;
@@ -139,8 +143,20 @@
if (*var_luser_relay) {
state.msg_attr.unmatched = 0;
expand_luser = vstring_alloc(100);
+ canon_luser = vstring_alloc(100);
local_expand(expand_luser, var_luser_relay, &state, &usr_attr, (void *)
0);
- status = deliver_resolve_addr(state, usr_attr, STR(expand_luser));
+ /* In case luser_relay specifies a domain-less address. */
+ canon_addr_external(canon_luser, vstring_str(expand_luser));
+ /* Assumes that the address resolver won't change the address. */
+ if (STREQ(vstring_str(canon_luser), state.msg_attr.rcpt.address)) {
+ dsb_simple(state.msg_attr.why, "5.1.1",
+ "unknown user: \"%s\"", state.msg_attr.user);
+ status = bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr));
+ } else {
+ status = deliver_resolve_addr(state, usr_attr, STR(expand_luser));
+ }
+ vstring_free(canon_luser);
vstring_free(expand_luser);
return (status);
}
@@ -149,8 +165,6 @@
* If no alias was found for a required reserved name, toss the message
* into the bit bucket, and issue a warning instead.
*/
-#define STREQ(x,y) (strcasecmp(x,y) == 0)
-
if (STREQ(state.msg_attr.user, MAIL_ADDR_MAIL_DAEMON)
|| STREQ(state.msg_attr.user, MAIL_ADDR_POSTMASTER)) {
msg_warn("required alias not found: %s", state.msg_attr.user);