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
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
------------
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
# 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
smarthost_smtp:
driver = smtp
- message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
multi_domain
#
.ifdef _HAVE_TLS
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)
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);
}
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);
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 */
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"");
}
#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
{
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);
{ "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) },
.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,
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
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;
--- /dev/null
+# 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
+
--- /dev/null
+
+******** 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@test.ex H=(test) [127.0.0.1] P=smtp S=sss for good@test.ex
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 <= CALLER@test.ex H=(test) [127.0.0.1] P=smtp S=sss for bad@test.ex
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 <= CALLER@test.ex H=the.local.host.name [ip4.ip4.ip4.ip4] P=esmtp S=sss for good@test.ex
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 => :blackhole: <good@test.ex> 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@test.ex F=<CALLER@test.ex> 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@test.ex F=<CALLER@test.ex> 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@test.ex
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 => :blackhole: <CALLER@test.ex> 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
--- /dev/null
+# 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@test.ex>
+??? 250
+RCPT TO:<good@test.ex>
+??? 250
+DATA
+??? 354
+Subject: should be good
+
+<<< test-data-good
+.
+??? 250
+MAIL FROM:<CALLER@test.ex>
+??? 250
+RCPT TO:<bad@test.ex>
+??? 250
+DATA
+??? 354
+Subject: should be bad
+
+<<< test-data-bad
+.
+??? 250
+QUIT
+??? 221
+****
+#
+sleep 1
+killdaemon
keepalive
no_lmtp_ignore_quota
max_rcpt = 100
+message_linelength_limit = 998
multi_domain
port = 1224
protocol = smtp
--- /dev/null
+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@test.ex>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<good@test.ex>
+??? 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@test.ex>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<bad@test.ex>
+??? 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