]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.9-20240109
authorWietse Venema <wietse@porcupine.org>
Tue, 9 Jan 2024 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Wed, 10 Jan 2024 16:16:15 +0000 (11:16 -0500)
19 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/cleanup.8.html
postfix/html/postconf.5.html
postfix/man/man5/postconf.5
postfix/man/man8/cleanup.8
postfix/mantools/postlink
postfix/proto/postconf.proto
postfix/proto/stop
postfix/proto/stop.double-history
postfix/proto/stop.double-install-proto-text
postfix/src/cleanup/cleanup.c
postfix/src/cleanup/cleanup_init.c
postfix/src/cleanup/cleanup_message.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/smtp_stream.c
postfix/src/global/smtp_stream.h
postfix/src/smtpd/smtpd.c

index ec655022f9243a59226cca5926fa47126c646c91..843d57711857579ae2a3d367525f789cdd2d27ce 100644 (file)
@@ -27681,7 +27681,24 @@ Apologies for any names omitted.
 
 20240106
 
-       Bugfix: with smtpd_forbid_bare_newline enabled, do not
-       "strip" extra <CR> characters before <LF>. This avoids
+       Inbound smuggling: with smtpd_forbid_bare_newline enabled,
+       do not "strip" extra <CR> characters before <LF>. This avoids
        ambiguity when a client sends extra <CR> characters as in
-       <CR><LF>.<CR><CR><LF>. File: global/smtp_stream.c.
+       <CR><LF>.<CR><CR><LF>. There is no smuggling vulnerability
+       because there is no mail system will send the above
+       sequence (mail systems send <CR><LF>..<CR><CR><LF> instead).
+       But this change will silence some testing tools. More at
+       https://www.postfix.org/false-smuggling-claims.html. File:
+       global/smtp_stream.c.
+
+20240109
+
+       Outbound smuggling: with "cleanup_replace_stray_cr_lf =
+       yes" (the default) Postfix will replace stray <CR> or <LF>
+       characters in message content with a space character. This
+       prevents Postfix from enabling outbound (remote) SMTP
+       smuggling, and it also makes evaluation of Postfix-added
+       DKIM etc. signatures independent from how a remote mail
+       server handles stray <CR> or <LF> characters. Files:
+       global/mail_params.h, cleanup/cleanup.c, cleanup/cleanup_message.c,
+       mantools/postlink, proto/postconf.proto.
index 5ead75a50ed5b08f9e7f7936bd8f4534cdbd9410..470215bc8f8d1068767e876b9b53d68b53751a8a 100644 (file)
@@ -26,6 +26,32 @@ now also distributed with the more recent Eclipse Public License
 license of their choice. Those who are more comfortable with the
 IPL can continue with that license.
 
+Incompatibility with snapshot 20240109
+=======================================
+
+Outbound SMTP smuggling: with "cleanup_replace_stray_cr_lf = yes", the
+cleanup daemon replaces each stray <CR> or <LF> character in message
+content with a space character. The replacement happens before any other
+content management.
+
+This prevents outbound SMTP smuggling, where an attacker uses Postfix
+to send a non-standard End-of-DATA sequence that triggers inbound
+SMTP smuggling at a remote SMTP server.
+
+This also ensures that the evaluation of Postfix-added DKIM etc.
+signatures will not depend on how a remote mail server handles stray <CR>
+or <LF> characters.
+
+This feature applies to all email that Postfix locally or remotely
+out. It is not allowlisted based on client identity.
+
+Major changes with snapshot 20240106
+====================================
+
+Inbound SMTP smuggling: strip extra <CR> in <CR><LF>.<CR><CR><LF>,
+to silence some tools that send attack sequences that are not viable.
+Details at https://www.postfix.org/false-smuggling-claims.html
+
 Major changes with snapshot 20240102
 ====================================
 
@@ -36,10 +62,6 @@ This release improves configuration (see below) and logging for rejected
 input (it now includes helo, mail, and rcpt information if available).
 This will be back ported to Postfix 3.8.5, 3.7.10, 3.6.14, and 3.5.24.
 
-- Stricter enforcement of <CR><LF>.<CR><LF>; earlier versions ignored
-  extra <CR> before <LF>, causing ambiguity about what the client
-  actually sent.
-
 - The new setting "smtpd_forbid_bare_newline = normalize" allows
   bare newlines from local and remote SMTP clients that send bare
   newlines consistently, and maintains more compatibility with
index 42b048a6e8a5a5eb83b367d811fc0d8856a311bf..b90af83994780af1dd9d44e8f3e868fddc7f6a2d 100644 (file)
@@ -160,28 +160,36 @@ CLEANUP(8)                                                          CLEANUP(8)
               The set of characters that Postfix will remove from message con-
               tent.
 
+       Available in Postfix version 3.9, 3.8.5, 3.7.10,  3.6.14,  3.5.24,  and
+       later:
+
+       <b><a href="postconf.5.html#cleanup_replace_stray_cr_lf">cleanup_replace_stray_cr_lf</a> (yes)</b>
+              Replace  each  stray  &lt;CR&gt;  or &lt;LF&gt; character in message content
+              with a space character, to prevent outbound SMTP smuggling,  and
+              to make the evaluation of Postfix-added DKIM etc.
+
 <b>BEFORE QUEUE MILTER CONTROLS</b>
        As of version 2.3, Postfix supports the Sendmail version 8 Milter (mail
-       filter)  protocol.  When  mail is not received via the <a href="smtpd.8.html">smtpd(8)</a> server,
+       filter) protocol. When mail is not received via  the  <a href="smtpd.8.html">smtpd(8)</a>  server,
        the <a href="cleanup.8.html">cleanup(8)</a> server will simulate SMTP events to the extent that this
        is possible. For details see the <a href="MILTER_README.html">MILTER_README</a> document.
 
        <b><a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a> (empty)</b>
-              A  list  of  Milter (mail filter) applications for new mail that
+              A list of Milter (mail filter) applications for  new  mail  that
               does not arrive via the Postfix <a href="smtpd.8.html"><b>smtpd</b>(8)</a> server.
 
        <b><a href="postconf.5.html#milter_protocol">milter_protocol</a> (6)</b>
-              The mail filter protocol version and  optional  protocol  exten-
-              sions  for  communication  with  a  Milter application; prior to
+              The  mail  filter  protocol version and optional protocol exten-
+              sions for communication with  a  Milter  application;  prior  to
               Postfix 2.6 the default protocol is 2.
 
        <b><a href="postconf.5.html#milter_default_action">milter_default_action</a> (tempfail)</b>
-              The default action when  a  Milter  (mail  filter)  response  is
-              unavailable  (for  example,  bad Postfix configuration or Milter
+              The  default  action  when  a  Milter  (mail filter) response is
+              unavailable (for example, bad Postfix  configuration  or  Milter
               failure).
 
        <b><a href="postconf.5.html#milter_macro_daemon_name">milter_macro_daemon_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The {daemon_name} macro value for Milter (mail filter)  applica-
+              The  {daemon_name} macro value for Milter (mail filter) applica-
               tions.
 
        <b><a href="postconf.5.html#milter_macro_v">milter_macro_v</a> ($<a href="postconf.5.html#mail_name">mail_name</a> $<a href="postconf.5.html#mail_version">mail_version</a>)</b>
@@ -192,45 +200,45 @@ CLEANUP(8)                                                          CLEANUP(8)
               tion, and for negotiating protocol options.
 
        <b><a href="postconf.5.html#milter_command_timeout">milter_command_timeout</a> (30s)</b>
-              The time limit for sending an SMTP command  to  a  Milter  (mail
+              The  time  limit  for  sending an SMTP command to a Milter (mail
               filter) application, and for receiving the response.
 
        <b><a href="postconf.5.html#milter_content_timeout">milter_content_timeout</a> (300s)</b>
-              The  time  limit  for  sending message content to a Milter (mail
+              The time limit for sending message content  to  a  Milter  (mail
               filter) application, and for receiving the response.
 
        <b><a href="postconf.5.html#milter_connect_macros">milter_connect_macros</a> (see 'postconf -d' output)</b>
-              The macros that are sent to Milter  (mail  filter)  applications
+              The  macros  that  are sent to Milter (mail filter) applications
               after completion of an SMTP connection.
 
        <b><a href="postconf.5.html#milter_helo_macros">milter_helo_macros</a> (see 'postconf -d' output)</b>
-              The  macros  that  are sent to Milter (mail filter) applications
+              The macros that are sent to Milter  (mail  filter)  applications
               after the SMTP HELO or EHLO command.
 
        <b><a href="postconf.5.html#milter_mail_macros">milter_mail_macros</a> (see 'postconf -d' output)</b>
-              The macros that are sent to Milter  (mail  filter)  applications
+              The  macros  that  are sent to Milter (mail filter) applications
               after the SMTP MAIL FROM command.
 
        <b><a href="postconf.5.html#milter_rcpt_macros">milter_rcpt_macros</a> (see 'postconf -d' output)</b>
-              The  macros  that  are sent to Milter (mail filter) applications
+              The macros that are sent to Milter  (mail  filter)  applications
               after the SMTP RCPT TO command.
 
        <b><a href="postconf.5.html#milter_data_macros">milter_data_macros</a> (see 'postconf -d' output)</b>
-              The macros that are sent to version 4  or  higher  Milter  (mail
+              The  macros  that  are  sent to version 4 or higher Milter (mail
               filter) applications after the SMTP DATA command.
 
        <b><a href="postconf.5.html#milter_unknown_command_macros">milter_unknown_command_macros</a> (see 'postconf -d' output)</b>
-              The  macros  that  are  sent to version 3 or higher Milter (mail
+              The macros that are sent to version 3  or  higher  Milter  (mail
               filter) applications after an unknown SMTP command.
 
        <b><a href="postconf.5.html#milter_end_of_data_macros">milter_end_of_data_macros</a> (see 'postconf -d' output)</b>
-              The macros that are sent to Milter  (mail  filter)  applications
+              The  macros  that  are sent to Milter (mail filter) applications
               after the message end-of-data.
 
        Available in Postfix version 2.5 and later:
 
        <b><a href="postconf.5.html#milter_end_of_header_macros">milter_end_of_header_macros</a> (see 'postconf -d' output)</b>
-              The  macros  that  are sent to Milter (mail filter) applications
+              The macros that are sent to Milter  (mail  filter)  applications
               after the end of the message header.
 
        Available in Postfix version 2.7 and later:
@@ -242,8 +250,8 @@ CLEANUP(8)                                                          CLEANUP(8)
        Available in Postfix version 3.1 and later:
 
        <b><a href="postconf.5.html#milter_macro_defaults">milter_macro_defaults</a> (empty)</b>
-              Optional  list  of  <i>name=value</i> pairs that specify default values
-              for arbitrary macros that Postfix may send  to  Milter  applica-
+              Optional list of <i>name=value</i> pairs that  specify  default  values
+              for  arbitrary  macros  that Postfix may send to Milter applica-
               tions.
 
 <b>MIME PROCESSING CONTROLS</b>
@@ -269,92 +277,92 @@ CLEANUP(8)                                                          CLEANUP(8)
               ing information.
 
        <b><a href="postconf.5.html#strict_mime_encoding_domain">strict_mime_encoding_domain</a> (no)</b>
-              Reject  mail with invalid Content-Transfer-Encoding: information
+              Reject mail with invalid Content-Transfer-Encoding:  information
               for the message/* or multipart/* MIME content types.
 
        Available in Postfix version 2.5 and later:
 
        <b><a href="postconf.5.html#detect_8bit_encoding_header">detect_8bit_encoding_header</a> (yes)</b>
-              Automatically detect 8BITMIME body content by  looking  at  Con-
-              tent-Transfer-Encoding:   message  headers;  historically,  this
+              Automatically  detect  8BITMIME  body content by looking at Con-
+              tent-Transfer-Encoding:  message  headers;  historically,   this
               behavior was hard-coded to be "always on".
 
 <b>AUTOMATIC BCC RECIPIENT CONTROLS</b>
-       Postfix can automatically add BCC (blind carbon copy) when mail  enters
+       Postfix  can automatically add BCC (blind carbon copy) when mail enters
        the mail system:
 
        <b><a href="postconf.5.html#always_bcc">always_bcc</a> (empty)</b>
-              Optional  address  that  receives  a "blind carbon copy" of each
+              Optional address that receives a "blind  carbon  copy"  of  each
               message that is received by the Postfix mail system.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#sender_bcc_maps">sender_bcc_maps</a> (empty)</b>
-              Optional BCC (blind carbon-copy) address lookup tables,  indexed
+              Optional  BCC (blind carbon-copy) address lookup tables, indexed
               by envelope sender address.
 
        <b><a href="postconf.5.html#recipient_bcc_maps">recipient_bcc_maps</a> (empty)</b>
-              Optional  BCC (blind carbon-copy) address lookup tables, indexed
+              Optional BCC (blind carbon-copy) address lookup tables,  indexed
               by envelope recipient address.
 
 <b>ADDRESS TRANSFORMATION CONTROLS</b>
-       Address rewriting is delegated to the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a>  daemon.   The
+       Address  rewriting  is delegated to the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a> daemon.  The
        <a href="cleanup.8.html"><b>cleanup</b>(8)</a> server implements table driven address mapping.
 
        <b><a href="postconf.5.html#empty_address_recipient">empty_address_recipient</a> (MAILER-DAEMON)</b>
               The recipient of mail addressed to the null address.
 
        <b><a href="postconf.5.html#canonical_maps">canonical_maps</a> (empty)</b>
-              Optional  address  mapping lookup tables for message headers and
+              Optional address mapping lookup tables for message  headers  and
               envelopes.
 
        <b><a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> (empty)</b>
-              Optional address mapping lookup tables for envelope  and  header
+              Optional  address  mapping lookup tables for envelope and header
               recipient addresses.
 
        <b><a href="postconf.5.html#sender_canonical_maps">sender_canonical_maps</a> (empty)</b>
-              Optional  address  mapping lookup tables for envelope and header
+              Optional address mapping lookup tables for envelope  and  header
               sender addresses.
 
        <b><a href="postconf.5.html#masquerade_classes">masquerade_classes</a> (envelope_sender, header_sender, header_recipient)</b>
               What addresses are subject to address masquerading.
 
        <b><a href="postconf.5.html#masquerade_domains">masquerade_domains</a> (empty)</b>
-              Optional list of  domains  whose  subdomain  structure  will  be
+              Optional  list  of  domains  whose  subdomain  structure will be
               stripped off in email addresses.
 
        <b><a href="postconf.5.html#masquerade_exceptions">masquerade_exceptions</a> (empty)</b>
-              Optional  list  of  user names that are not subjected to address
-              masquerading,  even  when  their   addresses   match   $<a href="postconf.5.html#masquerade_domains">masquer</a>-
+              Optional list of user names that are not  subjected  to  address
+              masquerading,   even   when   their  addresses  match  $<a href="postconf.5.html#masquerade_domains">masquer</a>-
               <a href="postconf.5.html#masquerade_domains">ade_domains</a>.
 
        <b><a href="postconf.5.html#propagate_unmatched_extensions">propagate_unmatched_extensions</a> (canonical, virtual)</b>
-              What  address  lookup  tables copy an address extension from the
+              What address lookup tables copy an address  extension  from  the
               lookup key to the lookup result.
 
        Available before Postfix version 2.0:
 
        <b><a href="postconf.5.html#virtual_maps">virtual_maps</a> (empty)</b>
-              Optional lookup tables with a) names of domains  for  which  all
-              addresses  are  aliased  to  addresses  in other local or remote
+              Optional  lookup  tables  with a) names of domains for which all
+              addresses are aliased to addresses  in  other  local  or  remote
               domains, and b) addresses that are aliased to addresses in other
               local or remote domains.
 
        Available in Postfix version 2.0 and later:
 
        <b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> ($<a href="postconf.5.html#virtual_maps">virtual_maps</a>)</b>
-              Optional  lookup  tables  with aliases that apply to all recipi-
-              ents: <a href="local.8.html"><b>local</b>(8)</a>, virtual, and remote; this is  unlike  <a href="postconf.5.html#alias_maps">alias_maps</a>
+              Optional lookup tables with aliases that apply  to  all  recipi-
+              ents:  <a href="local.8.html"><b>local</b>(8)</a>,  virtual, and remote; this is unlike <a href="postconf.5.html#alias_maps">alias_maps</a>
               that apply only to <a href="local.8.html"><b>local</b>(8)</a> recipients.
 
        Available in Postfix version 2.2 and later:
 
-       <b><a href="postconf.5.html#canonical_classes">canonical_classes</a>  (envelope_sender, envelope_recipient, header_sender,</b>
+       <b><a href="postconf.5.html#canonical_classes">canonical_classes</a> (envelope_sender, envelope_recipient,  header_sender,</b>
        <b>header_recipient)</b>
               What addresses are subject to <a href="postconf.5.html#canonical_maps">canonical_maps</a> address mapping.
 
        <b><a href="postconf.5.html#recipient_canonical_classes">recipient_canonical_classes</a> (envelope_recipient, header_recipient)</b>
-              What  addresses  are subject to <a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> address
+              What addresses are subject to  <a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a>  address
               mapping.
 
        <b><a href="postconf.5.html#sender_canonical_classes">sender_canonical_classes</a> (envelope_sender, header_sender)</b>
@@ -362,9 +370,9 @@ CLEANUP(8)                                                          CLEANUP(8)
               ping.
 
        <b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> (empty)</b>
-              Rewrite  or  add  message headers in mail from remote clients if
-              the <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter value  is  non-empty,
-              updating  incomplete  addresses with the domain specified in the
+              Rewrite or add message headers in mail from  remote  clients  if
+              the  <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a>  parameter value is non-empty,
+              updating incomplete addresses with the domain specified  in  the
               <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter, and adding missing head-
               ers.
 
@@ -375,7 +383,7 @@ CLEANUP(8)                                                          CLEANUP(8)
               <a href="showq.8.html"><b>showq</b>(8)</a> queue displays.
 
        <b><a href="postconf.5.html#header_size_limit">header_size_limit</a> (102400)</b>
-              The  maximal  amount  of  memory  in bytes for storing a message
+              The maximal amount of memory in  bytes  for  storing  a  message
               header.
 
        <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a> (50)</b>
@@ -383,17 +391,17 @@ CLEANUP(8)                                                          CLEANUP(8)
               in the primary message headers.
 
        <b><a href="postconf.5.html#in_flow_delay">in_flow_delay</a> (1s)</b>
-              Time  to  pause before accepting a new message, when the message
+              Time to pause before accepting a new message, when  the  message
               arrival rate exceeds the message delivery rate.
 
        <b><a href="postconf.5.html#message_size_limit">message_size_limit</a> (10240000)</b>
-              The maximal size in  bytes  of  a  message,  including  envelope
+              The  maximal  size  in  bytes  of  a message, including envelope
               information.
 
        Available in Postfix version 2.0 and later:
 
        <b><a href="postconf.5.html#header_address_token_limit">header_address_token_limit</a> (10240)</b>
-              The  maximal  number of address tokens are allowed in an address
+              The maximal number of address tokens are allowed in  an  address
               message header.
 
        <b><a href="postconf.5.html#mime_boundary_length_limit">mime_boundary_length_limit</a> (2048)</b>
@@ -409,7 +417,7 @@ CLEANUP(8)                                                          CLEANUP(8)
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#virtual_alias_expansion_limit">virtual_alias_expansion_limit</a> (1000)</b>
-              The maximal number of addresses  that  virtual  alias  expansion
+              The  maximal  number  of  addresses that virtual alias expansion
               produces from each original recipient.
 
        <b><a href="postconf.5.html#virtual_alias_recursion_limit">virtual_alias_recursion_limit</a> (1000)</b>
@@ -418,50 +426,50 @@ CLEANUP(8)                                                          CLEANUP(8)
        Available in Postfix version 3.0 and later:
 
        <b><a href="postconf.5.html#virtual_alias_address_length_limit">virtual_alias_address_length_limit</a> (1000)</b>
-              The  maximal  length  of  an  email  address after virtual alias
+              The maximal length of  an  email  address  after  virtual  alias
               expansion.
 
 <b>SMTPUTF8 CONTROLS</b>
        Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
 
        <b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
-              Enable preliminary SMTPUTF8 support for the protocols  described
+              Enable  preliminary SMTPUTF8 support for the protocols described
               in <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a>, <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>, and <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a>.
 
        <b><a href="postconf.5.html#smtputf8_autodetect_classes">smtputf8_autodetect_classes</a> (sendmail, verify)</b>
-              Detect  that  a message requires SMTPUTF8 support for the speci-
+              Detect that a message requires SMTPUTF8 support for  the  speci-
               fied mail origin classes.
 
        Available in Postfix version 3.2 and later:
 
        <b><a href="postconf.5.html#enable_idna2003_compatibility">enable_idna2003_compatibility</a> (no)</b>
-              Enable  'transitional'  compatibility   between   IDNA2003   and
-              IDNA2008,  when  converting UTF-8 domain names to/from the ASCII
+              Enable   'transitional'   compatibility   between  IDNA2003  and
+              IDNA2008, when converting UTF-8 domain names to/from  the  ASCII
               form that is used for DNS lookups.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of the Postfix <a href="postconf.5.html">main.cf</a> and  <a href="master.5.html">master.cf</a>  con-
+              The  default  location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
               figuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How  much  time  a  Postfix  daemon process may take to handle a
+              How much time a Postfix daemon process  may  take  to  handle  a
               request before it is terminated by a built-in watchdog timer.
 
        <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The maximal number of digits after the decimal point  when  log-
+              The  maximal  number of digits after the decimal point when log-
               ging sub-second delay values.
 
        <b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
-              The  time  after which the sender receives a copy of the message
+              The time after which the sender receives a copy of  the  message
               headers of mail that is still queued.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
-              The time limit for sending  or  receiving  information  over  an
+              The  time  limit  for  sending  or receiving information over an
               internal communication channel.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The  maximum  amount of time that an idle Postfix daemon process
+              The maximum amount of time that an idle Postfix  daemon  process
               waits for an incoming connection before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
@@ -472,7 +480,7 @@ CLEANUP(8)                                                          CLEANUP(8)
               The internet hostname of this mail system.
 
        <b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The domain name that locally-posted mail appears to  come  from,
+              The  domain  name that locally-posted mail appears to come from,
               and that locally posted mail is delivered to.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
@@ -485,21 +493,21 @@ CLEANUP(8)                                                          CLEANUP(8)
               The location of the Postfix top-level queue directory.
 
        <b><a href="postconf.5.html#soft_bounce">soft_bounce</a> (no)</b>
-              Safety  net to keep mail queued that would otherwise be returned
+              Safety net to keep mail queued that would otherwise be  returned
               to the sender.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              A prefix that  is  prepended  to  the  process  name  in  syslog
+              A  prefix  that  is  prepended  to  the  process  name in syslog
               records, so that, for example, "smtpd" becomes "prefix/smtpd".
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#enable_original_recipient">enable_original_recipient</a> (yes)</b>
-              Enable  support  for  the  original  recipient  address after an
-              address is rewritten to a different address  (for  example  with
+              Enable support for  the  original  recipient  address  after  an
+              address  is  rewritten  to a different address (for example with
               aliasing or with canonical mapping).
 
        Available in Postfix 3.3 and later:
@@ -510,14 +518,14 @@ CLEANUP(8)                                                          CLEANUP(8)
        Available in Postfix 3.5 and later:
 
        <b><a href="postconf.5.html#info_log_address_format">info_log_address_format</a> (external)</b>
-              The  email  address  form that will be used in non-debug logging
+              The email address form that will be used  in  non-debug  logging
               (info, warning, etc.).
 
        Available in Postfix 3.9 and later:
 
        <b><a href="postconf.5.html#force_mime_input_conversion">force_mime_input_conversion</a> (no)</b>
-              Convert body content that claims to be 8-bit into  quoted-print-
-              able,  before  <a href="postconf.5.html#header_checks">header_checks</a>,  <a href="postconf.5.html#body_checks">body_checks</a>,  Milters, and before
+              Convert  body content that claims to be 8-bit into quoted-print-
+              able, before <a href="postconf.5.html#header_checks">header_checks</a>,  <a href="postconf.5.html#body_checks">body_checks</a>,  Milters,  and  before
               after-queue content filters.
 
 <b>FILES</b>
index 225df2cbe7302eebaf3bb6fae11a0c921f50545e..df52fc91ae5e87f9dd09ece56c2818d560f486b3 100644 (file)
@@ -1469,6 +1469,40 @@ Examples:
 </pre>
 
 
+</DD>
+
+<DT><b><a name="cleanup_replace_stray_cr_lf">cleanup_replace_stray_cr_lf</a>
+(default: yes)</b></DT><DD>
+
+<p> Replace each stray &lt;CR&gt; or &lt;LF&gt; character in message
+content with a space character, to prevent outbound SMTP smuggling,
+and to make the evaluation of Postfix-added DKIM etc. signatures
+independent from how a remote mail server handles such characters.
+</p>
+
+<p> SMTP does not allow such characters unless they are part of a
+&lt;CR&gt;&lt;LF&gt; sequence, and different mail systems handle
+such stray characters in an implementation-dependent manner. Stray
+&lt;CR&gt; or &lt;LF&gt; characters could be used for outbound
+SMTP smuggling, where an attacker uses a Postfix server to send
+message content with a non-standard End-of-DATA sequence that
+triggers inbound SMTP smuggling at a remote SMTP server.</p>
+
+<p> The replacement happens before all other content management,
+and before Postfix may add a DKIM etc. signature; if the signature
+were created first, the replacement could invalidate the signature.
+</p>
+
+<p> In addition to preventing SMTP smuggling, replacing stray
+&lt;CR&gt; or &lt;LF&gt; characters ensures that the result of
+signature validation by later mail system will not depend on how
+that mail system handles those stray characters in an
+implementation-dependent manner. </p>
+
+<p> This feature is available in Postfix &ge; 3.9, 3.8.5, 3.7.10,
+3.6.14, and 3.5.24. </p>
+
+
 </DD>
 
 <DT><b><a name="cleanup_service_name">cleanup_service_name</a>
index 0de744d6bf5dd7bb959118dcef50ae17ba3a5e78..dbdb3205eee4214087e261aa51d80342612427fc 100644 (file)
@@ -883,6 +883,32 @@ canonical_maps = hash:/etc/postfix/canonical
 .fi
 .ad
 .ft R
+.SH cleanup_replace_stray_cr_lf (default: yes)
+Replace each stray <CR> or <LF> character in message
+content with a space character, to prevent outbound SMTP smuggling,
+and to make the evaluation of Postfix\-added DKIM etc. signatures
+independent from how a remote mail server handles such characters.
+.PP
+SMTP does not allow such characters unless they are part of a
+<CR><LF> sequence, and different mail systems handle
+such stray characters in an implementation\-dependent manner. Stray
+<CR> or <LF> characters could be used for outbound
+SMTP smuggling, where an attacker uses a Postfix server to send
+message content with a non\-standard End\-of\-DATA sequence that
+triggers inbound SMTP smuggling at a remote SMTP server.
+.PP
+The replacement happens before all other content management,
+and before Postfix may add a DKIM etc. signature; if the signature
+were created first, the replacement could invalidate the signature.
+.PP
+In addition to preventing SMTP smuggling, replacing stray
+<CR> or <LF> characters ensures that the result of
+signature validation by later mail system will not depend on how
+that mail system handles those stray characters in an
+implementation\-dependent manner.
+.PP
+This feature is available in Postfix >= 3.9, 3.8.5, 3.7.10,
+3.6.14, and 3.5.24.
 .SH cleanup_service_name (default: cleanup)
 The name of the \fBcleanup\fR(8) service. This service rewrites addresses
 into the standard form, and performs \fBcanonical\fR(5) address mapping
index 3180bc9f8a526bcbf8af0d8df8fb337938d7ccd6..8b15e91e6479f461231a56afd08b7cb8d5293bc9 100644 (file)
@@ -165,6 +165,13 @@ content.
 .IP "\fBmessage_strip_characters (empty)\fR"
 The set of characters that Postfix will remove from message
 content.
+.PP
+Available in Postfix version 3.9, 3.8.5, 3.7.10, 3.6.14,
+3.5.24, and later:
+.IP "\fBcleanup_replace_stray_cr_lf (yes)\fR"
+Replace each stray <CR> or <LF> character in message
+content with a space character, to prevent outbound SMTP smuggling,
+and to make the evaluation of Postfix\-added DKIM etc.
 .SH "BEFORE QUEUE MILTER CONTROLS"
 .na
 .nf
index 85f6b68c4d05cb2c4ea58f646d40c4616281d5fd..8b9837a8b9f79baeacb3e68c4153fdf3ba761a41 100755 (executable)
@@ -564,6 +564,7 @@ while (<>) {
     s;\bsmtpd_for[-</bB>]*\n*[ <bB>]*bid_bare_newline\b;<a href="postconf.5.html#smtpd_forbid_bare_newline">$&</a>;g;
     s;\bsmtpd_for[-</bB>]*\n*[ <bB>]*bid_bare_newline_reject_code\b;<a href="postconf.5.html#smtpd_forbid_bare_newline_reject_code">$&</a>;g;
     s;\bsmtpd_for[-</bB>]*\n*[ <bB>]*bid_bare_newline_exclusions\b;<a href="postconf.5.html#smtpd_forbid_bare_newline_exclusions">$&</a>;g;
+    s;\bcleanup_replace_stray_cr_lf\b;<a href="postconf.5.html#cleanup_replace_stray_cr_lf">$&</a>;g;
     s;\bsmtpd_for[-</bB>]*\n*[ <bB>]*bid_unauth_pipelining\b;<a href="postconf.5.html#smtpd_forbid_unauth_pipelining">$&</a>;g;
     s;\bsmtpd_hard_error_limit\b;<a href="postconf.5.html#smtpd_hard_error_limit">$&</a>;g;
     s;\bsmtpd_helo_required\b;<a href="postconf.5.html#smtpd_helo_required">$&</a>;g;
index bbc3c77ba0aa29fd4b1144f81321521058eb6668..2666d0fcce1b545c6e3c0f1bc1642953d0005e05 100644 (file)
@@ -11240,17 +11240,6 @@ is rejected by the <b>reject_plaintext_session</b> restriction.
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
-%PARAM smtpd_forbid_bare_newline_reject_code 550
-
-<p>
-The numerical Postfix SMTP server response code when a request
-is rejected by the <b>smtpd_forbid_bare_newline</b> feature.
-Specify a 5XX status code (521 to disconnect).
-</p>
-
-<p> This feature is available in Postfix &ge; 3.9, 3.8.5, 3.7.10,
-3.6.14, and 3.5.24. </p>
-
 %PARAM resolve_numeric_domain no
 
 <p> Resolve "user@ipaddress" as "user@[ipaddress]", instead of
@@ -19158,6 +19147,47 @@ behavior as mynetworks. </p>
 <p> This feature is available in Postfix &ge; 3.9, 3.8.4, 3.7.9,
 3.6.13, and 3.5.23. </p>
 
+%PARAM smtpd_forbid_bare_newline_reject_code 550
+
+<p>
+The numerical Postfix SMTP server response code when a request
+is rejected by the <b>smtpd_forbid_bare_newline</b> feature.
+Specify a 5XX status code (521 to disconnect).
+</p>
+
+<p> This feature is available in Postfix &ge; 3.9, 3.8.5, 3.7.10,
+3.6.14, and 3.5.24. </p>
+
+%PARAM cleanup_replace_stray_cr_lf yes
+
+<p> Replace each stray &lt;CR&gt; or &lt;LF&gt; character in message
+content with a space character, to prevent outbound SMTP smuggling,
+and to make the evaluation of Postfix-added DKIM etc. signatures
+independent from how a remote mail server handles such characters.
+</p>
+
+<p> SMTP does not allow such characters unless they are part of a
+&lt;CR&gt;&lt;LF&gt; sequence, and different mail systems handle
+such stray characters in an implementation-dependent manner. Stray
+&lt;CR&gt; or &lt;LF&gt; characters could be used for outbound
+SMTP smuggling, where an attacker uses a Postfix server to send
+message content with a non-standard End-of-DATA sequence that
+triggers inbound SMTP smuggling at a remote SMTP server.</p>
+
+<p> The replacement happens before all other content management,
+and before Postfix may add a DKIM etc. signature; if the signature
+were created first, the replacement could invalidate the signature.
+</p>
+
+<p> In addition to preventing SMTP smuggling, replacing stray
+&lt;CR&gt; or &lt;LF&gt; characters ensures that the result of
+signature validation by later mail system will not depend on how
+that mail system handles those stray characters in an
+implementation-dependent manner. </p>
+
+<p> This feature is available in Postfix &ge; 3.9, 3.8.5, 3.7.10,
+3.6.14, and 3.5.24. </p>
+
 %PARAM smtpd_forbid_unauth_pipelining Postfix &ge; 3.9: yes
 
 <p> Disconnect remote SMTP clients that violate RFC 2920 (or 5321)
index 13a4b3d63a91c6a696a2d49b836a9ada6d87ba3f..efdde6354da0ad15e69efdc2ae2643d70150fc87 100644 (file)
@@ -1590,3 +1590,4 @@ resychronization
 ENVID
 netcat
 probers
+lf
index aaca3c97653d5623918a7a4d87da46758ac17b9e..eff21250f283fc301a13f8bd179f2969412b4513 100644 (file)
@@ -90,3 +90,6 @@ proto  proto aliases proto virtual proto ADDRESS_REWRITING_README html
  keep reading message content after an unexpected LF LF 
  forms Files proto postconf proto smtpd smtpd c 
  CR LF CR CR LF File global smtp_stream c 
+ CR LF CR CR LF There is no smuggling vulnerability
+ sequence mail systems send CR LF CR CR LF instead 
+ global mail_params h cleanup cleanup c cleanup cleanup_message c 
index edccb249808bf2031a10a04a5b112779cc65324a..261e1cbbcc6e01e042a28146dafa4783cdc844bb 100644 (file)
@@ -40,3 +40,4 @@ root  root you
  user foo domain user domain domain 
 virtual  virtual alias domain anything right hand content does not matter 
  skipping unexpected LF LF in DATA from 
+Inbound SMTP smuggling strip extra CR in CR LF CR CR LF 
index 99e5a592ef2dc2cbf1a833cd6cdf1cad29fc33bc..eac3c2538ec5cb31da5b6c7a5a44f64a3a199fd0 100644 (file)
 /* .IP "\fBmessage_strip_characters (empty)\fR"
 /*     The set of characters that Postfix will remove from message
 /*     content.
+/* .PP
+/*     Available in Postfix version 3.9, 3.8.5, 3.7.10, 3.6.14,
+/*     3.5.24, and later:
+/* .IP "\fBcleanup_replace_stray_cr_lf (yes)\fR"
+/*     Replace each stray <CR> or <LF> character in message
+/*     content with a space character, to prevent outbound SMTP smuggling,
+/*     and to make the evaluation of Postfix-added DKIM etc.
 /* BEFORE QUEUE MILTER CONTROLS
 /* .ad
 /* .fi
index ddf64b2884550869efe56f6c0fdc9b0176099eda..446ddf2f95dd2edc61f5a016c3c5ee564d5ba470 100644 (file)
@@ -175,6 +175,7 @@ int     var_always_add_hdrs;                /* always add missing headers */
 int     var_virt_addrlen_limit;                /* stop exponential growth */
 char   *var_hfrom_format;              /* header_from_format */
 int     var_force_mime_iconv;          /* force mime downgrade on input */
+int     var_cleanup_mask_stray_cr_lf;  /* replace stray CR or LF with space */
 
 const CONFIG_INT_TABLE cleanup_int_table[] = {
     VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0,
@@ -192,6 +193,7 @@ const CONFIG_BOOL_TABLE cleanup_bool_table[] = {
     VAR_AUTO_8BIT_ENC_HDR, DEF_AUTO_8BIT_ENC_HDR, &var_auto_8bit_enc_hdr,
     VAR_ALWAYS_ADD_HDRS, DEF_ALWAYS_ADD_HDRS, &var_always_add_hdrs,
     VAR_FORCE_MIME_ICONV, DEF_FORCE_MIME_ICONV, &var_force_mime_iconv,
+    VAR_CLEANUP_MASK_STRAY_CR_LF, DEF_CLEANUP_MASK_STRAY_CR_LF, &var_cleanup_mask_stray_cr_lf,
     0,
 };
 
index bd951f34447730ed256c5557f645db690f397722..0d31598c0901635dbabfeaa3fc39be0c26e0ce88 100644 (file)
@@ -924,6 +924,23 @@ static void cleanup_message_headerbody(CLEANUP_STATE *state, int type,
     const char *cp;
     char   *dst;
 
+    /*
+     * Replace each stray CR or LF with one space. These are not allowed in
+     * SMTP, and can be used to enable outbound (remote) SMTP smuggling.
+     * Replacing these early ensures that our later DKIM etc. signature will
+     * not be invalidated. Besides preventing SMTP smuggling, replacing stray
+     * <CR> or <LF> ensures that the result of signature validation by a
+     * later mail system will not depend on how that mail system handles
+     * those stray characters in an implementation-dependent manner.
+     * 
+     * The input length is not changed, therefore it is safe to overwrite the
+     * input.
+     */
+    if (var_cleanup_mask_stray_cr_lf)
+       for (dst = (char *) buf; dst < buf + len; dst++)
+           if (*dst == '\r' || *dst == '\n')
+               *dst = ' ';
+
     /*
      * Reject unwanted characters.
      * 
index d21e5bfe04fe8f308fa0c619f4dfd66d776893f9..1f03b0b34e7db79dc42f7557b701864ccbee0d0c 100644 (file)
@@ -4314,6 +4314,10 @@ extern char *var_smtpd_dns_re_filter;
 #define VAR_SMTPD_FORBID_BARE_LF_CODE  "smtpd_forbid_bare_newline_reject_code"
 #define DEF_SMTPD_FORBID_BARE_LF_CODE  550
 
+#define VAR_CLEANUP_MASK_STRAY_CR_LF   "cleanup_replace_stray_cr_lf"
+#define DEF_CLEANUP_MASK_STRAY_CR_LF   1
+extern int var_cleanup_mask_stray_cr_lf;
+
  /*
   * Share TLS sessions through tlsproxy(8).
   */
index d112501807d274110fc9d233617b37cd2e837c17..7fbbb715d5cda073c28c54e45b83efd908a1decf 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20240106"
+#define MAIL_RELEASE_DATE      "20240109"
 #define MAIL_VERSION_NUMBER    "3.9"
 
 #ifdef SNAPSHOT
index 769b9c08178702f5d782a8c1861e01de0a2215d9..07cba37adf2aaccdb0fccb9421e0537a8b94b8ee 100644 (file)
@@ -54,7 +54,7 @@
 /*     va_list ap;
 /*
 /*     int     smtp_forbid_bare_lf;
-/*     int     smtp_seen_bare_lf;
+/*     int     smtp_detected_bare_lf;
 /* AUXILIARY API
 /*     int     smtp_get_noexcept(vp, stream, maxlen, flags)
 /*     VSTRING *vp;
 /*     smtp_get_noexcept() implements the subset of smtp_get()
 /*     without timeouts and without making long jumps. Instead,
 /*     query the stream status with vstream_feof() etc.
-/*     This function will set smtp_seen_bare_lf when flagging
+/*     This function will set smtp_detected_bare_lf when flagging
 /*     input with a bare newline byte.
 /*
 /*     smtp_timeout_setup() is a backwards-compatibility interface
 /*     for programs that don't require deadline or data-rate support.
 /*
 /*     smtp_forbid_bare_lf controls whether smtp_get_noexcept()
-/*     will set smtp_seen_bare_lf when the line that was read last
-/*     ended with a bare newline byte.
+/*     will set smtp_detected_bare_lf when the line that was read
+/*     last ended with a bare newline byte.
 /* DIAGNOSTICS
 /* .fi
 /* .ad
   * body content one line at a time.
   */
 int     smtp_forbid_bare_lf;
-int     smtp_seen_bare_lf;
+int     smtp_detected_bare_lf;
 
 /* smtp_timeout_reset - reset per-stream error flags */
 
@@ -387,7 +387,7 @@ int     smtp_get_noexcept(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags
     int     last_char;
     int     next_char;
 
-    smtp_seen_bare_lf = 0;
+    smtp_detected_bare_lf = 0;
 
     /*
      * It's painful to do I/O with records that may span multiple buffers.
@@ -433,7 +433,7 @@ int     smtp_get_noexcept(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags
        vstring_truncate(vp, VSTRING_LEN(vp) - 1);
        if (smtp_forbid_bare_lf) {
            if (VSTRING_LEN(vp) == 0 || vstring_end(vp)[-1] != '\r')
-               smtp_seen_bare_lf = smtp_forbid_bare_lf;
+               smtp_detected_bare_lf = smtp_forbid_bare_lf;
            else
                vstring_truncate(vp, VSTRING_LEN(vp) - 1);
        } else {
index 1a894685c8b3acc0bc500d77549c5caaef0c7944..3e1f711086b1326fab8b16a95197a8590f3ad24c 100644 (file)
@@ -44,7 +44,7 @@ extern void smtp_fwrite(const char *, ssize_t len, VSTREAM *);
 extern void smtp_fread_buf(VSTRING *, ssize_t len, VSTREAM *);
 extern void smtp_fputc(int, VSTREAM *);
 extern int smtp_forbid_bare_lf;
-extern int smtp_seen_bare_lf;
+extern int smtp_detected_bare_lf;
 
 extern void smtp_vprintf(VSTREAM *, const char *, va_list);
 
index 86c7c84d612b9b4a060a104dc77a089b552467ed..6c94c67beb4e44566cd464b418c745d0224ecd39 100644 (file)
@@ -3622,8 +3622,8 @@ static void receive_data_message(SMTPD_STATE *state,
     int     curr_rec_type;
     int     prev_rec_type;
     int     first = 1;
-    int     prev_seen_bare_lf = 0;
-    int     expect_crlf_dot = IS_BARE_LF_REJECT(smtp_forbid_bare_lf);
+    int     prev_detected_bare_lf = 0;
+    int     require_crlf_dot_crlf = IS_BARE_LF_REJECT(smtp_forbid_bare_lf);
 
     /*
      * If deadlines are enabled, increase the time budget as message content
@@ -3645,14 +3645,16 @@ static void receive_data_message(SMTPD_STATE *state,
      * because sendmail permits it.
      */
     for (prev_rec_type = 0; /* void */ ; prev_rec_type = curr_rec_type,
-        expect_crlf_dot = (expect_crlf_dot || smtp_seen_bare_lf == 0),
-        prev_seen_bare_lf = smtp_seen_bare_lf) {
+        require_crlf_dot_crlf = (require_crlf_dot_crlf ||
+                                 (IS_BARE_LF_NORMALIZE(smtp_forbid_bare_lf)
+                                  && smtp_detected_bare_lf == 0)),
+        prev_detected_bare_lf = smtp_detected_bare_lf) {
        if (smtp_get(state->buffer, state->client, var_line_limit,
                     SMTP_GET_FLAG_NONE) == '\n')
            curr_rec_type = REC_TYPE_NORM;
        else
            curr_rec_type = REC_TYPE_CONT;
-       if (IS_BARE_LF_REJECT(smtp_seen_bare_lf))
+       if (IS_BARE_LF_REJECT(smtp_detected_bare_lf))
            state->err |= CLEANUP_STAT_BARE_LF;
        start = vstring_str(state->buffer);
        len = VSTRING_LEN(state->buffer);
@@ -3667,8 +3669,8 @@ static void receive_data_message(SMTPD_STATE *state,
                out_record(out_stream, REC_TYPE_NORM, "", 0);
        }
        if (prev_rec_type != REC_TYPE_CONT && *start == '.') {
-           if (len == 1 && expect_crlf_dot
-               && (smtp_seen_bare_lf || prev_seen_bare_lf))
+           if (len == 1 && require_crlf_dot_crlf
+               && (smtp_detected_bare_lf || prev_detected_bare_lf))
                continue;
            if (proxy == 0 ? (++start, --len) == 0 : len == 1)
                break;
@@ -4154,7 +4156,7 @@ static int bdat_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                /* Skip the out_record() and VSTRING_RESET() calls below. */
                break;
            }
-           if (IS_BARE_LF_REJECT(smtp_seen_bare_lf))
+           if (IS_BARE_LF_REJECT(smtp_detected_bare_lf))
                state->err |= CLEANUP_STAT_BARE_LF;
            start = vstring_str(state->bdat_get_buffer);
            len = VSTRING_LEN(state->bdat_get_buffer);
@@ -5851,7 +5853,7 @@ static void smtpd_proto(SMTPD_STATE *state)
            }
            watchdog_pat();
            smtpd_chat_query(state);
-           if (IS_BARE_LF_REJECT(smtp_seen_bare_lf)) {
+           if (IS_BARE_LF_REJECT(smtp_detected_bare_lf)) {
                log_whatsup(state, "reject", "bare <LF> received");
                state->error_mask |= MAIL_ERROR_PROTOCOL;
                smtpd_chat_reply(state, "%d 5.5.2 %s Error: bare <LF> received",