[exim-cvs] smtp transport: message_linelength_limit option. …

Αρχική Σελίδα
Delete this message
Reply to this message
Συντάκτης: Exim Git Commits Mailing List
Ημερομηνία:  
Προς: exim-cvs
Αντικείμενο: [exim-cvs] smtp transport: message_linelength_limit option. Bug 1684
Gitweb: https://git.exim.org/exim.git/commitdiff/0de9945258c2e7910c35f715caf07c5e9270aa1b
Commit:     0de9945258c2e7910c35f715caf07c5e9270aa1b
Parent:     64dfd5e0cec10edded40f4669a706e6564aa8e07
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Tue May 12 23:10:08 2020 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Wed May 13 12:11:02 2020 +0100


    smtp transport: message_linelength_limit option.  Bug 1684
---
 doc/doc-docbook/spec.xfpt    | 14 ++++++++++++++
 doc/doc-txt/NewStuff         |  3 +++
 doc/doc-txt/OptionLists.txt  |  1 +
 src/src/configure.default    |  5 -----
 src/src/deliver.c            | 24 ++++++++++++++++++-----
 src/src/smtp_in.c            |  8 ++++----
 src/src/spool_out.c          |  6 +++---
 src/src/transports/smtp.c    | 19 +++++++++++++++++++
 src/src/transports/smtp.h    |  1 +
 test/confs/0588              | 42 +++++++++++++++++++++++++++++++++++++++++
 test/log/0588                | 15 +++++++++++++++
 test/scripts/0000-Basic/0588 | 45 ++++++++++++++++++++++++++++++++++++++++++++
 test/stdout/0572             |  1 +
 test/stdout/0588             | 40 +++++++++++++++++++++++++++++++++++++++
 14 files changed, 207 insertions(+), 17 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 30f5f28..5c6955e 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -25472,6 +25472,20 @@ so can cause parallel connections to the same host if &%remote_max_parallel%&
permits this.


+.new
+.option message_linelength_limit smtp integer 998
+.cindex "line length" limit
+This option sets the maximum line length, in bytes, that the transport
+will send.  Any messages with lines exceeding the given value
+will fail and a failure-DSN ("bounce") message will if possible be returned
+to the sender.
+The default value is that defined by the SMTP standards.
+
+It is generally wise to also check in the data ACL so that messages
+received via SMTP can be refused without producing a bounce.
+.wen
+
+
 .option multi_domain smtp boolean&!! true
 .vindex "&$domain$&"
 When this option is set, the &(smtp)& transport can handle a number of
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 253eae2..82f1c5c 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -21,6 +21,9 @@ Version 4.95
  4. Single-key LMDB lookups, previously experimental, are now supported.
     The support is not built unless specified in the Local/Makefile.


+ 5. Option "message_linelength_limit" on the smtp transport to enforce (by
+    default) the RFC 998 character limit.
+


 Version 4.94
 ------------
diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt
index 5de6d69..cfb3cd0 100644
--- a/doc/doc-txt/OptionLists.txt
+++ b/doc/doc-txt/OptionLists.txt
@@ -382,6 +382,7 @@ message_body_newlines                boolean         false         main
 message_body_visible                 integer         500           main
 message_id_header_domain             string*         unset         main              4.11
 message_id_header_text               string*         unset         main
+message_linelength_limit             integer         998           smtp              4.94
 message_logs                         boolean         true          main              4.10
 message_prefix                       string*         +             appendfile        4.00 replaces prefix
                                      string*         unset         pipe              4.00 replaces prefix
diff --git a/src/src/configure.default b/src/src/configure.default
index 57af99c..7d54e11 100644
--- a/src/src/configure.default
+++ b/src/src/configure.default
@@ -808,13 +808,9 @@ begin transports



# This transport is used for delivering messages over SMTP connections.
-# Refuse to send any message with over-long lines, which could have
-# been received other than via SMTP. The use of message_size_limit to
-# enforce this is a red herring.

remote_smtp:
driver = smtp
- message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
.ifdef _HAVE_TLS
tls_resumption_hosts = *
#endif
@@ -832,7 +828,6 @@ remote_smtp:

 smarthost_smtp:
   driver = smtp
-  message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
   multi_domain
   #
 .ifdef _HAVE_TLS
diff --git a/src/src/deliver.c b/src/src/deliver.c
index 3dcd7f9..67d711b 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -5380,7 +5380,8 @@ Returns:       nothing
 static void
 print_dsn_diagnostic_code(const address_item *addr, FILE *f)
 {
-uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL;
+uschar * s = testflag(addr, af_pass_message) ? addr->message : NULL;
+unsigned cnt;


 /* af_pass_message and addr->message set ? print remote host answer */
 if (s)
@@ -5392,19 +5393,32 @@ if (s)
   if (!(s = Ustrstr(addr->message, ": ")))
     return;                /* not found, bail out */
   s += 2;  /* skip ": " */
-  fprintf(f, "Diagnostic-Code: smtp; ");
+  cnt = fprintf(f, "Diagnostic-Code: smtp; ");
   }
 /* no message available. do nothing */
 else return;


 while (*s)
+  {
+  if (cnt > 950)    /* RFC line length limit: 998 */
+    {
+    DEBUG(D_deliver) debug_printf("print_dsn_diagnostic_code() truncated line\n");
+    fputs("[truncated]", f);
+    break;
+    }
+
   if (*s == '\\' && s[1] == 'n')
     {
     fputs("\n ", f);    /* as defined in RFC 3461 */
     s += 2;
+    cnt += 2;
     }
   else
+    {
     fputc(*s++, f);
+    cnt++;
+    }
+  }


 fputc('\n', f);
 }
@@ -7831,11 +7845,11 @@ wording. */
         fprintf(fp, "Remote-MTA: X-ip; [%s]%s\n", hu->address, p);
         }
       if ((s = addr->smtp_greeting) && *s)
-        fprintf(fp, "X-Remote-MTA-smtp-greeting: X-str; %s\n", s);
+        fprintf(fp, "X-Remote-MTA-smtp-greeting: X-str; %.900s\n", s);
       if ((s = addr->helo_response) && *s)
-        fprintf(fp, "X-Remote-MTA-helo-response: X-str; %s\n", s);
+        fprintf(fp, "X-Remote-MTA-helo-response: X-str; %.900s\n", s);
       if ((s = addr->message) && *s)
-        fprintf(fp, "X-Exim-Diagnostic: X-str; %s\n", s);
+        fprintf(fp, "X-Exim-Diagnostic: X-str; %.900s\n", s);
       }
 #endif
       print_dsn_diagnostic_code(addr, fp);
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index 412ef4d..2b4323b 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -5173,9 +5173,9 @@ while (done <= 0)
     recipients_list[recipients_count-1].orcpt = orcpt;
     recipients_list[recipients_count-1].dsn_flags = dsn_flags;


-    DEBUG(D_receive) debug_printf("DSN: orcpt: %s  flags: %d\n",
+    /* DEBUG(D_receive) debug_printf("DSN: orcpt: %s  flags: %d\n",
       recipients_list[recipients_count-1].orcpt,
-      recipients_list[recipients_count-1].dsn_flags);
+      recipients_list[recipients_count-1].dsn_flags); */
     }


       /* The recipient was discarded */
@@ -5190,8 +5190,8 @@ while (done <= 0)
     discarded = TRUE;
     log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: "
       "discarded by %s ACL%s%s", host_and_ident(TRUE),
-      sender_address_unrewritten? sender_address_unrewritten : sender_address,
-      smtp_cmd_argument, f.recipients_discarded? "MAIL" : "RCPT",
+      sender_address_unrewritten ? sender_address_unrewritten : sender_address,
+      smtp_cmd_argument, f.recipients_discarded ? "MAIL" : "RCPT",
       log_msg ? US": " : US"", log_msg ? log_msg : US"");
     }


diff --git a/src/src/spool_out.c b/src/src/spool_out.c
index 5d658fd..9a514b3 100644
--- a/src/src/spool_out.c
+++ b/src/src/spool_out.c
@@ -277,9 +277,9 @@ if (message_smtputf8)
#endif

/* Write the dsn flags to the spool header file */
-DEBUG(D_deliver) debug_printf("DSN: Write SPOOL: -dsn_envid %s\n", dsn_envid);
+/* DEBUG(D_deliver) debug_printf("DSN: Write SPOOL: -dsn_envid %s\n", dsn_envid); */
if (dsn_envid) fprintf(fp, "-dsn_envid %s\n", dsn_envid);
-DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_ret %d\n", dsn_ret);
+/* DEBUG(D_deliver) debug_printf("DSN: Write SPOOL: -dsn_ret %d\n", dsn_ret); */
if (dsn_ret) fprintf(fp, "-dsn_ret %d\n", dsn_ret);

/* To complete the envelope, write out the tree of non-recipients, followed by
@@ -293,7 +293,7 @@ for (int i = 0; i < recipients_count; i++)
{
recipient_item *r = recipients_list + i;

- DEBUG(D_deliver) debug_printf("DSN: Flags: 0x%x\n", r->dsn_flags);
+ /* DEBUG(D_deliver) debug_printf("DSN: Flags: 0x%x\n", r->dsn_flags); */

   if (r->pno < 0 && !r->errors_to && r->dsn_flags == 0)
     fprintf(fp, "%s\n", r->address);
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index f47c6d9..12a1994 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -111,6 +111,7 @@ optionlist smtp_transport_options[] = {
   { "lmtp_ignore_quota",    opt_bool,       LOFF(lmtp_ignore_quota) },
   { "max_rcpt",             opt_int | opt_public,
       OPT_OFF(transport_instance, max_addresses) },
+  { "message_linelength_limit", opt_int,   LOFF(message_linelength_limit) },
   { "multi_domain",         opt_expand_bool | opt_public,
       OPT_OFF(transport_instance, multi_domain) },
   { "port",                 opt_stringptr, LOFF(port) },
@@ -207,6 +208,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   .size_addition =        1024,
   .hosts_max_try =        5,
   .hosts_max_try_hardlimit =    50,
+  .message_linelength_limit =    998,
   .address_retry_include_sender = TRUE,
   .allow_localhost =        FALSE,
   .authenticated_sender_force =    FALSE,
@@ -4524,6 +4526,23 @@ DEBUG(D_transport)
       cutthrough.cctx.sock >= 0 ? cutthrough.cctx.sock : 0);
   }


+/* Check the restrictions on line length */
+
+debug_printf("%s %d: max_received_linelength %u message_linelength_limit %u\n", __FUNCTION__, __LINE__, max_received_linelength, ob->message_linelength_limit);
+if (max_received_linelength > ob->message_linelength_limit)
+  {
+  struct timeval now;
+  gettimeofday(&now, NULL);
+
+  for (address_item * addr = addrlist; addr; addr = addr->next)
+    if (addr->transport_return == DEFER)
+      addr->transport_return = PENDING_DEFER;
+
+  set_errno_nohost(addrlist, ERRNO_SMTPFORMAT,
+    US"message has lines too long for transport", FAIL, TRUE, &now);
+  goto END_TRANSPORT;
+  }
+
 /* Set the flag requesting that these hosts be added to the waiting
 database if the delivery fails temporarily or if we are running with
 queue_smtp or a 2-stage queue run. This gets unset for certain
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index 037105a..607a377 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -62,6 +62,7 @@ typedef struct {
   int     size_addition;
   int     hosts_max_try;
   int     hosts_max_try_hardlimit;
+  int      message_linelength_limit;
   BOOL    address_retry_include_sender;
   BOOL    allow_localhost;
   BOOL    authenticated_sender_force;
diff --git a/test/confs/0588 b/test/confs/0588
new file mode 100644
index 0000000..9a88c9c
--- /dev/null
+++ b/test/confs/0588
@@ -0,0 +1,42 @@
+# Exim test configuration 0588
+
+.include DIR/aux-var/std_conf_prefix
+
+log_selector = +received_recipients +sender_on_delivery +millisec
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+# ----- Routers -----
+
+begin routers
+
+rx_dump:
+  driver =    redirect
+  condition =    ${if !eq {$received_ip_address}{127.0.0.1}}
+  data =    :blackhole:
+
+smtp_try:
+  driver =    accept
+  transport =    send_to_server
+
+# ----- Transports -----
+
+begin transports
+
+send_to_server:
+  driver = smtp
+  hosts = HOSTIPV4
+  allow_localhost
+  port = PORT_D
+  hosts_try_fastopen = :
+
+# ----- Retry -----
+
+begin retry
+
+* * F,5d,10s
+
+# End
+
diff --git a/test/log/0588 b/test/log/0588
new file mode 100644
index 0000000..9446451
--- /dev/null
+++ b/test/log/0588
@@ -0,0 +1,15 @@
+
+******** SERVER ********
+2017-07-30 18:51:05.712 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 <= CALLER@??? H=(test) [127.0.0.1] P=smtp S=sss for good@???
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 <= CALLER@??? H=(test) [127.0.0.1] P=smtp S=sss for bad@???
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 <= CALLER@??? H=the.local.host.name [ip4.ip4.ip4.ip4] P=esmtp S=sss for good@???
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 => :blackhole: <good@???> R=rx_dump
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 => good@??? F=<CALLER@???> R=smtp_try T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaZ-0005vi-00"
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 ** bad@??? F=<CALLER@???> R=smtp_try T=send_to_server: message has lines too long for transport
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 <= <> R=10HmaY-0005vi-00 U=EXIMUSER P=local S=sss for CALLER@???
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 => :blackhole: <CALLER@???> R=rx_dump
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 Completed
diff --git a/test/scripts/0000-Basic/0588 b/test/scripts/0000-Basic/0588
new file mode 100644
index 0000000..44328a7
--- /dev/null
+++ b/test/scripts/0000-Basic/0588
@@ -0,0 +1,45 @@
+# message_linelength_limit
+#
+# The "write" script cmd subtracts 1 for the newline,
+# and the linecount in exim doesn't count the line-ending.
+write test-data-good 1x999
+++++
+****
+write test-data-bad  1x1000
+++++
+****
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+client 127.0.0.1 PORT_D
+??? 220
+HELO test
+??? 250
+MAIL FROM:<CALLER@???>
+??? 250
+RCPT TO:<good@???>
+??? 250
+DATA
+??? 354
+Subject: should be good
+
+<<< test-data-good
+.
+??? 250
+MAIL FROM:<CALLER@???>
+??? 250
+RCPT TO:<bad@???>
+??? 250
+DATA
+??? 354
+Subject: should be bad
+
+<<< test-data-bad
+.
+??? 250
+QUIT
+??? 221
+****
+#
+sleep 1
+killdaemon
diff --git a/test/stdout/0572 b/test/stdout/0572
index d66f928..fd77c72 100644
--- a/test/stdout/0572
+++ b/test/stdout/0572
@@ -64,6 +64,7 @@ interface = ip4.ip4.ip4.ip4
 keepalive
 no_lmtp_ignore_quota
 max_rcpt = 100
+message_linelength_limit = 998
 multi_domain
 port = 1224
 protocol = smtp
diff --git a/test/stdout/0588 b/test/stdout/0588
new file mode 100644
index 0000000..994f04e
--- /dev/null
+++ b/test/stdout/0588
@@ -0,0 +1,40 @@
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> HELO test
+??? 250
+<<< 250 the.local.host.name Hello test [127.0.0.1]
+>>> MAIL FROM:<CALLER@???>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<good@???>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: should be good
+>>> 
+>>> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+>>> .
+??? 250
+<<< 250 OK id=10HmaX-0005vi-00
+>>> MAIL FROM:<CALLER@???>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<bad@???>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: should be bad
+>>> 
+>>> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+>>> .
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 the.local.host.name closing connection
+End of script