A. Schulze:
> 
> wietse:
> 
> > If it is DATA, then address verification is possible but it requires  
> > source code
> > changes to Postfix:
> >
> > - After successful RCPT TO, do not assume that the recipient exists,
> >   but send DATA and disconnect after the DATA response is received.
> >
> > This will cause extra noise in the logfile, therefore it should be
> > configurable:
> >
> > - Configure what sites reject recipients after DATA.  The list of
> >   such domains is limited, so this is not a big burden.
> 
> this would be indeed a useful extension...

Patch follows. Most if not all *should* also work with Postfix 2.11
and possibly earlier versions.

This introduces a new parameter smtp_address_verify_target (default:
rcpt) that can be set to "data" for qmail-like servers.

Since this setting causes the Postfix SMTP client to hang up after
a positive DATA response, the remote SMTP server may log something
like this:

    Dec 27 10:53:14 server postfix/smtpd[51624]: lost connection
        after DATA (0 bytes) from host.example.org[192.168.1.3]

    Dec 27 10:53:14 server postfix/smtpd[51624]: disconnect from
        host.example.org[192.168.1.3] ehlo=1 mail=1 rcpt=1 data=0/1

Most of the patch is documentation and user interface stuff.

        Wietse

20141227

        Feature: smtp_address_verify_target (default: rcpt) that
        determines what protocol stage decides if a recipient is
        valid. Specify "data" for servers that reject recipients
        after the DATA command. mantools/postlink, proto/postconf.proto,
        global/mail_params.h, smtp/lmtp_params.c, smtp/smtp.c,
        smtp/smtp.h, smtp/smtp_params.c, smtp/smtp_proto.c.

diff -cr /var/tmp/postfix-2.12-20141226/man/man5/postconf.5 
./man/man5/postconf.5
*** /var/tmp/postfix-2.12-20141226/man/man5/postconf.5  2014-12-21 
19:49:22.000000000 -0500
--- ./man/man5/postconf.5       2014-12-27 10:47:44.000000000 -0500
***************
*** 2472,2477 ****
--- 2472,2484 ----
  configuration parameter.  See there for details.
  .PP
  This feature is available in Postfix 2.8 and later.
+ .SH lmtp_address_verify_target (default: rcpt)
+ The LMTP protocol stage that determines whether a recipient is
+ deliverable. Specify one of "rcpt" or "data". The latter is needed
+ with remote LMTP servers that reject recipients after the DATA
+ command.
+ .PP
+ This feature is available in Postfix 2.12 and later.
  .SH lmtp_assume_final (default: no)
  When a remote LMTP server announces no DSN support, assume that
  the
***************
*** 6085,6090 ****
--- 6092,6104 ----
  .br
  .PP
  This feature is available in Postfix 2.8 and later.
+ .SH smtp_address_verify_target (default: rcpt)
+ The SMTP protocol stage that determines whether a recipient is
+ deliverable. Specify one of "rcpt" or "data". The latter is needed
+ with remote SMTP servers that reject recipients after the DATA
+ command.
+ .PP
+ This feature is available in Postfix 2.12 and later.
  .SH smtp_always_send_ehlo (default: yes)
  Always send EHLO at the start of an SMTP session.
  .PP
diff -cr /var/tmp/postfix-2.12-20141226/man/man8/smtp.8 ./man/man8/smtp.8
*** /var/tmp/postfix-2.12-20141226/man/man8/smtp.8      2014-12-25 
11:52:01.000000000 -0500
--- ./man/man8/smtp.8   2014-12-27 10:47:44.000000000 -0500
***************
*** 725,730 ****
--- 725,735 ----
  .IP "\fBsmtp_fallback_relay ($fallback_relay)\fR"
  Optional list of relay hosts for SMTP destinations that can't be
  found or that are unreachable.
+ .PP
+ Available with Postfix 2.12 and later:
+ .IP "\fBsmtp_address_verify_target (rcpt)\fR"
+ The SMTP protocol stage that determines whether a recipient is
+ deliverable.
  .SH "SEE ALSO"
  .na
  .nf
diff -cr /var/tmp/postfix-2.12-20141226/mantools/postlink ./mantools/postlink
*** /var/tmp/postfix-2.12-20141226/mantools/postlink    2014-12-12 
20:44:45.000000000 -0500
--- ./mantools/postlink 2014-12-27 10:38:24.000000000 -0500
***************
*** 89,94 ****
--- 89,96 ----
      s;\baddress_verify_service_name\b;<a 
href="postconf.5.html#address_verify_service_name">$&</a>;g;
      s;\baddress_verify_transport_maps\b;<a 
href="postconf.5.html#address_verify_transport_maps">$&</a>;g;
      s;\baddress_verify_virtual_transport\b;<a 
href="postconf.5.html#address_verify_virtual_transport">$&</a>;g;
+     s;\bsmtp_address_verify_target\b;<a 
href="postconf.5.html#smtp_address_verify_target">$&</a>;g;
+     s;\blmtp_address_verify_target\b;<a 
href="postconf.5.html#lmtp_address_verify_target">$&</a>;g;
      s;\balias_database\b;<a href="postconf.5.html#alias_database">$&</a>;g;
      s;\balias_maps\b;<a href="postconf.5.html#alias_maps">$&</a>;g;
      s;\ballow_mail_to_com[-</bB>]*\n*[ <bB>]*mands\b;<a 
href="postconf.5.html#allow_mail_to_commands">$&</a>;g;
diff -cr /var/tmp/postfix-2.12-20141226/proto/postconf.proto 
./proto/postconf.proto
*** /var/tmp/postfix-2.12-20141226/proto/postconf.proto 2014-12-21 
19:47:44.000000000 -0500
--- ./proto/postconf.proto      2014-12-27 10:37:56.000000000 -0500
***************
*** 15419,15424 ****
--- 15419,15442 ----
  
  <p> This feature is available in Postfix 2.9 and later.  </p>
  
+ %PARAM smtp_address_verify_target rcpt
+ 
+ <p> The SMTP protocol stage that determines whether a recipient is
+ deliverable. Specify one of "rcpt" or "data". The latter is needed
+ with remote SMTP servers that reject recipients after the DATA
+ command. </p>
+ 
+ <p> This feature is available in Postfix 2.12 and later.  </p>
+ 
+ %PARAM lmtp_address_verify_target rcpt
+ 
+ <p> The LMTP protocol stage that determines whether a recipient is
+ deliverable. Specify one of "rcpt" or "data". The latter is needed
+ with remote LMTP servers that reject recipients after the DATA
+ command. </p>
+ 
+ <p> This feature is available in Postfix 2.12 and later.  </p>
+ 
  %PARAM daemon_table_open_error_is_fatal no
  
  <p> How a Postfix daemon process handles errors while opening lookup
diff -cr /var/tmp/postfix-2.12-20141226/src/global/mail_params.h 
./src/global/mail_params.h
*** /var/tmp/postfix-2.12-20141226/src/global/mail_params.h     2014-12-12 
20:42:53.000000000 -0500
--- ./src/global/mail_params.h  2014-12-27 10:44:18.000000000 -0500
***************
*** 2778,2783 ****
--- 2778,2791 ----
  #define DEF_VRFY_XPORT_MAPS           "$" VAR_TRANSPORT_MAPS
  extern char *var_vrfy_xport_maps;
  
+ #define SMTP_VRFY_TGT_RCPT            "rcpt"
+ #define SMTP_VRFY_TGT_DATA            "data"
+ #define VAR_LMTP_VRFY_TGT             "lmtp_address_verify_target"
+ #define DEF_LMTP_VRFY_TGT             SMTP_VRFY_TGT_RCPT
+ #define VAR_SMTP_VRFY_TGT             "smtp_address_verify_target"
+ #define DEF_SMTP_VRFY_TGT             SMTP_VRFY_TGT_RCPT
+ extern char *var_smtp_vrfy_tgt;
+ 
   /*
    * Message delivery trace service.
    */
diff -cr /var/tmp/postfix-2.12-20141226/src/smtp/lmtp_params.c 
./src/smtp/lmtp_params.c
*** /var/tmp/postfix-2.12-20141226/src/smtp/lmtp_params.c       2014-11-27 
12:18:44.000000000 -0500
--- ./src/smtp/lmtp_params.c    2014-12-27 10:43:46.000000000 -0500
***************
*** 33,38 ****
--- 33,39 ----
        VAR_LMTP_SASL_TYPE, DEF_LMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0,
        VAR_LMTP_BIND_ADDR, DEF_LMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
        VAR_LMTP_BIND_ADDR6, DEF_LMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0,
+       VAR_LMTP_VRFY_TGT, DEF_LMTP_VRFY_TGT, &var_smtp_vrfy_tgt, 1, 0,
        VAR_LMTP_HELO_NAME, DEF_LMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
        VAR_LMTP_HOST_LOOKUP, DEF_LMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0,
        VAR_LMTP_DNS_SUPPORT, DEF_LMTP_DNS_SUPPORT, &var_smtp_dns_support, 0, 0,
diff -cr /var/tmp/postfix-2.12-20141226/src/smtp/smtp.c ./src/smtp/smtp.c
*** /var/tmp/postfix-2.12-20141226/src/smtp/smtp.c      2014-12-25 
11:47:18.000000000 -0500
--- ./src/smtp/smtp.c   2014-12-27 10:47:44.000000000 -0500
***************
*** 685,690 ****
--- 685,695 ----
  /* .IP "\fBsmtp_fallback_relay ($fallback_relay)\fR"
  /*    Optional list of relay hosts for SMTP destinations that can't be
  /*    found or that are unreachable.
+ /* .PP
+ /*    Available with Postfix 2.12 and later:
+ /* .IP "\fBsmtp_address_verify_target (rcpt)\fR"
+ /*    The SMTP protocol stage that determines whether a recipient is
+ /*    deliverable.
  /* SEE ALSO
  /*    generic(5), output address rewriting
  /*    header_checks(5), message header content inspection
***************
*** 816,821 ****
--- 821,827 ----
  char   *var_smtp_sasl_type;
  char   *var_smtp_bind_addr;
  char   *var_smtp_bind_addr6;
+ char   *var_smtp_vrfy_tgt;
  bool    var_smtp_rand_addr;
  int     var_smtp_pix_thresh;
  int     var_queue_run_delay;
***************
*** 1077,1082 ****
--- 1083,1093 ----
       */
      smtp_dns_res_opt = name_mask(VAR_LMTP_SMTP(DNS_RES_OPT), 
dns_res_opt_masks,
                                 var_smtp_dns_res_opt);
+ 
+     /*
+      * Address verification.
+      */
+     smtp_vrfy_init();
  }
  
  /* pre_init - pre-jail initialization */
diff -cr /var/tmp/postfix-2.12-20141226/src/smtp/smtp.h ./src/smtp/smtp.h
*** /var/tmp/postfix-2.12-20141226/src/smtp/smtp.h      2014-12-02 
17:37:41.000000000 -0500
--- ./src/smtp/smtp.h   2014-12-27 10:44:43.000000000 -0500
***************
*** 365,370 ****
--- 365,371 ----
   /*
    * smtp_proto.c
    */
+ extern void smtp_vrfy_init(void);
  extern int smtp_helo(SMTP_STATE *);
  extern int smtp_xfer(SMTP_STATE *);
  extern int smtp_rset(SMTP_STATE *);
diff -cr /var/tmp/postfix-2.12-20141226/src/smtp/smtp_params.c 
./src/smtp/smtp_params.c
*** /var/tmp/postfix-2.12-20141226/src/smtp/smtp_params.c       2014-11-27 
12:18:44.000000000 -0500
--- ./src/smtp/smtp_params.c    2014-12-27 10:42:04.000000000 -0500
***************
*** 34,39 ****
--- 34,40 ----
        VAR_SMTP_SASL_TYPE, DEF_SMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0,
        VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
        VAR_SMTP_BIND_ADDR6, DEF_SMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0,
+       VAR_SMTP_VRFY_TGT, DEF_SMTP_VRFY_TGT, &var_smtp_vrfy_tgt, 1, 0,
        VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
        VAR_SMTP_HOST_LOOKUP, DEF_SMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0,
        VAR_SMTP_DNS_SUPPORT, DEF_SMTP_DNS_SUPPORT, &var_smtp_dns_support, 0, 0,
diff -cr /var/tmp/postfix-2.12-20141226/src/smtp/smtp_proto.c 
./src/smtp/smtp_proto.c
*** /var/tmp/postfix-2.12-20141226/src/smtp/smtp_proto.c        2014-12-06 
20:35:33.000000000 -0500
--- ./src/smtp/smtp_proto.c     2014-12-27 10:44:33.000000000 -0500
***************
*** 261,266 ****
--- 261,284 ----
      smtp_text_out,
  };
  
+ static int smtp_vrfy_tgt;
+ 
+ /* smtp_vrfy_init - initialize */
+ 
+ void    smtp_vrfy_init(void)
+ {
+     static const NAME_CODE vrfy_init_table[] = {
+       SMTP_VRFY_TGT_RCPT, SMTP_STATE_RCPT,
+       SMTP_VRFY_TGT_DATA, SMTP_STATE_DATA,
+       0,
+     };
+ 
+     if ((smtp_vrfy_tgt = name_code(vrfy_init_table, NAME_CODE_FLAG_NONE,
+                                  var_smtp_vrfy_tgt)) == 0)
+       msg_fatal("bad protocol stage: \"%s = %s\"",
+                 VAR_SMTP_VRFY_TGT, var_smtp_vrfy_tgt);
+ }
+ 
  /* smtp_helo - perform initial handshake with SMTP server */
  
  int     smtp_helo(SMTP_STATE *state)
***************
*** 1541,1547 ****
                                           dsn_notify_str(rcpt->dsn_notify));
            }
            if ((next_rcpt = send_rcpt + 1) == SMTP_RCPT_LEFT(state))
!               next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
                    SMTP_STATE_ABORT : SMTP_STATE_DATA;
            break;
  
--- 1559,1566 ----
                                           dsn_notify_str(rcpt->dsn_notify));
            }
            if ((next_rcpt = send_rcpt + 1) == SMTP_RCPT_LEFT(state))
!               next_state = (DEL_REQ_TRACE_ONLY(request->flags)
!                             && smtp_vrfy_tgt == SMTP_STATE_RCPT) ?
                    SMTP_STATE_ABORT : SMTP_STATE_DATA;
            break;
  
***************
*** 1551,1557 ****
             */
        case SMTP_STATE_DATA:
            vstring_strcpy(next_command, "DATA");
!           next_state = SMTP_STATE_DOT;
            break;
  
            /*
--- 1570,1578 ----
             */
        case SMTP_STATE_DATA:
            vstring_strcpy(next_command, "DATA");
!           next_state = (DEL_REQ_TRACE_ONLY(request->flags)
!                         && smtp_vrfy_tgt == SMTP_STATE_DATA) ?
!               SMTP_STATE_LAST : SMTP_STATE_DOT;
            break;
  
            /*

Reply via email to