Merge branch '4.next'
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 4 Nov 2023 14:20:45 +0000 (14:20 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 4 Nov 2023 14:29:25 +0000 (14:29 +0000)
12 files changed:
1  2 
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/acl.c
src/src/auths/get_data.c
src/src/daemon.c
src/src/macros.h
src/src/pdkim/pdkim.c
src/src/receive.c
src/src/smtp_in.c
src/src/tls-gnu.c
src/src/tls-openssl.c

index 2bdb2bbdf9b730af9f758428073de9688fa63700,70988384dca6f5e22fc46af00feade2059292b82..f856af346219587ee3183e046472cf55bb70e02a
@@@ -46,7 -46,7 +46,7 @@@
  . Update the Copyright year (only) when changing content.
  . /////////////////////////////////////////////////////////////////////////////
  
 -.set previousversion "4.96"
 +.set previousversion "4.97"
  .include ./local_params
  
  .set ACL "access control lists (ACLs)"
@@@ -55,7 -55,7 +55,7 @@@
  .set drivernamemax "64"
  
  .macro copyyear
 -2022
 +2023
  .endmacro
  
  . /////////////////////////////////////////////////////////////////////////////
@@@ -996,9 -996,12 +996,9 @@@ contains the number of seconds since th
  way of representing the date and time of day).
  .next
  After the first hyphen, the next
 -.new
  eleven
 -.wen
  characters are the id of the process that received the message.
  .next
 -.new
  There are two different possibilities for the final four characters:
  .olist
  .oindex "&%localhost_number%&"
@@@ -1014,6 -1017,7 +1014,6 @@@ If &%localhost_number%& is set, it is m
  500000 (250000) and added to
  the fractional part of the time, which in this case is in units of 2 us (4 us).
  .endlist
 -.wen
  .endlist
  
  After a message has been received, Exim waits for the clock to tick at the
@@@ -2842,11 -2846,13 +2842,11 @@@ of Exim is installed. It is not necessa
  referenced from the configuration (for example, alias files) are changed,
  because these are reread each time they are used.
  
 -.new
  Either a SIGTERM or a SIGINT signal should be used to cause the daemon
  to cleanly shut down.
  Subprocesses handling recceiving or delivering messages,
  or for scanning the queue,
  will not be affected by the termination of the daemon process.
 -.wen
  
  .cmdopt -bdf
  This option has the same effect as &%-bd%& except that it never disconnects
@@@ -2884,9 -2890,11 +2884,9 @@@ defined and macros will be expanded
  Because macros in the config file are often used for secrets, those are only
  available to admin users.
  
 -.new
  The word &"set"& at the start of a line, followed by a single space,
  is recognised specially as defining a value for a variable.
  The syntax is otherwise the same as the ACL modifier &"set ="&.
 -.wen
  
  .cmdopt -bem <&'filename'&>
  .cindex "testing" "string expansion"
@@@ -4442,6 -4450,7 +4442,6 @@@ It is only relevant when the &%-bd%& (s
  given.
  Normally the daemon creates this socket, unless a &%-oX%& and &*no*& &%-oP%&
  option is also present.
 -.new
  If this option is given then the socket will not be created.  This is required
  if the system is running multiple daemons, in which case it should
  be used on all.
@@@ -4455,6 -4464,7 +4455,6 @@@ caching compiled regexe
  .next
  obtaining a current queue size
  .endlist
 -.wen
  
  .cmdopt -pd
  .cindex "Perl" "starting the interpreter"
@@@ -4559,10 -4569,12 +4559,10 @@@ delivered down a single SMT
  .cindex "multiple SMTP deliveries"
  connection because of the hints that were set up during the first queue scan.
  
 -.new
  Two-phase queue runs should be used on systems which, even intermittently,
  have a large queue (such as mailing-list operators).
  They may also be useful for hosts that are connected to the Internet
  intermittently.
 -.wen
  
  .vitem &%-q[q]i...%&
  .oindex "&%-qi%&"
@@@ -4648,12 -4660,14 +4648,12 @@@ combined daemon at system boot time is 
  Such a daemon listens for incoming SMTP calls, and also starts a queue runner
  process every 30 minutes.
  
 -.new
  .cindex "named queues" "queue runners"
  It is possible to set up runners for multiple named queues within one daemon,
  For example:
  .code
  exim -qGhipri/2m -q10m -qqGmailinglist/1h
  .endd
 -.wen
  
  When a daemon is started by &%-q%& with a time value, but without &%-bd%&, no
  pid file is written unless one is explicitly requested by the &%-oP%& option.
@@@ -7395,8 -7409,10 +7395,8 @@@ For example, the way to write the NIS+ 
  [name="${quote_nisplus:$local_part}"]
  .endd
  .cindex "tainted data" "in lookups"
 -.new
  &*All*& tainted data used in a query-style lookup must be quoted
  using a mechanism appropriate for the lookup type.
 -.wen
  See chapter &<<CHAPexpand>>& for full coverage of string expansions. The quote
  operator can be used for all lookup types, but has no effect for single-key
  lookups, since no quoting is ever needed in their key strings.
@@@ -8218,7 -8234,7 +8218,7 @@@ daemon as in the other SQL databases
  .oindex &%sqlite_dbfile%&
  There are two ways of
  specifying the file.
 -The first is is by using the &%sqlite_dbfile%& main option.
 +The first is by using the &%sqlite_dbfile%& main option.
  The second, which allows separate files for each query,
  is to use an option appended, comma-separated, to the &"sqlite"&
  lookup type word.  The option is the word &"file"&, then an equals,
@@@ -9606,6 -9622,7 +9606,6 @@@ value. Nevertheless the &%-be%& option 
  database lookups, and the use of expansion operators such as &%sg%&, &%substr%&
  and &%nhash%&.
  
 -.new
  When reading lines from the standard input,
  macros can be defined and ACL variables can be set.
  For example:
@@@ -9614,6 -9631,7 +9614,6 @@@ MY_MACRO = fo
  set acl_m_myvar = bar
  .endd
  Such macros and variables can then be used in later input lines.
 -.wen
  
  Exim gives up its root privilege when it is called with the &%-be%& option, and
  instead runs under the uid and gid it was called with, to prevent users from
@@@ -9730,7 -9748,9 +9730,7 @@@ Example use (as an ACL modifier)
        add_header = :at_start:${authresults {$primary_hostname}}
  .endd
  This is safe even if no authentication results are available
 -.new
  and would generally be placed in the DATA ACL.
 -.wen
  
  
  .vitem "&*${certextract{*&<&'field'&>&*}{*&<&'certificate'&>&*}&&&
@@@ -9990,7 -10010,9 +9990,7 @@@ default, but the separator can be chang
  For each item
  in this list, its value is placed in &$item$&, and then the condition is
  evaluated.
 -.new
  Any modification of &$value$& by this evaluation is discarded.
 -.wen
  If the condition is true, &$item$& is added to the output as an
  item in a new list; if the condition is false, the item is discarded. The
  separator used for the output list is the same as the one used for the
@@@ -10611,7 -10633,7 +10611,7 @@@ expansion items
  This item inserts &"raw"& header lines. It is described with the &%header%&
  expansion item in section &<<SECTexpansionitems>>& above.
  
 -.vitem "&*${run<&'options'&> {*&<&'command&~arg&~list'&>&*}{*&<&'string1'&>&*}&&&
 +.vitem "&*${run<&'options'&> {*&<&'command&~string'&>&*}{*&<&'string1'&>&*}&&&
          {*&<&'string2'&>&*}}*&"
  .cindex "expansion" "running a command"
  .cindex "&%run%& expansion item"
@@@ -10620,8 -10642,8 +10620,8 @@@ One option is supported after the word 
  and without whitespace.
  
  If the option &'preexpand'& is not used,
 -the command string is split into individual arguments by spaces
 -and then each argument is expanded.
 +the command string before expansion is split into individual arguments by spaces
 +and then each argument is separately expanded.
  Then the command is run
  in a separate process, but under the same uid and gid.  As in other command
  executions from Exim, a shell is not used by default. If the command requires
@@@ -10633,9 -10655,9 +10633,9 @@@ potential attacker
  a careful assessment for security vulnerabilities should be done.
  
  If the option &'preexpand'& is used,
 -the command and its arguments are first expanded as one string. The result is
 -split apart into individual arguments by spaces, and then the command is run
 -as above.
 +the command string is first expanded as a whole.
 +The expansion result is split apart into individual arguments by spaces,
 +and then the command is run as above.
  Since the arguments are split by spaces, when there is a variable expansion
  which has an empty result, it will cause the situation that the argument will
  simply be omitted when the program is actually executed by Exim. If the
@@@ -11100,6 -11122,7 +11100,6 @@@ abbreviation &%h%& can be used when &%h
  
  
  
 -.new
  .vitem &*${headerwrap_*&<&'cols'&>&*_*&<&'limit'&>&*:*&<&'string'&>&*}*&
  .cindex header "wrapping operator"
  .cindex expansion "header wrapping"
@@@ -11113,6 -11136,7 +11113,6 @@@ column number is reached
  Whitespace at a chosen wrap point is removed.
  A line-wrap consists of a newline followed by a tab,
  and the tab is counted as 8 columns.
 -.wen
  
  
  
@@@ -13412,6 -13436,7 +13412,6 @@@ The main use of this variable is expect
  rejections of MAIL and rejections of RCPT.
  
  .tvar &$recipients$&
 -.new
  .tvar &$recipients_list$&
  These variables both contain the envelope recipients for a message.
  
@@@ -13420,6 -13445,7 +13420,6 @@@ The first uses a comma and a space sepa
  this variable is not intended for further processing.
  
  The second is a proper Exim list; colon-separated.
 -.wen
  
  However, the variables
  are not generally available, to prevent exposure of Bcc recipients in
@@@ -15728,8 -15754,10 +15728,8 @@@ by a setting such as this
  dns_again_means_nonexist = *.in-addr.arpa
  .endd
  This option applies to all DNS lookups that Exim does,
 -.new
  except for TLSA lookups (where knowing about such failures
  is security-relevant).
 -.wen
  It also applies when the
  &[gethostbyname()]& or &[getipnodebyname()]& functions give temporary errors,
  since these are most likely to be caused by DNS lookup problems. The
@@@ -16309,8 -16337,10 +16309,8 @@@ This option is obsolete, and retained o
  nowadays the ACL specified by &%acl_smtp_connect%& can also reject incoming
  connections immediately.
  
 -.new
  If the connection is on a TLS-on-connect port then the TCP connection is
  just dropped.  Otherwise, an SMTP error is sent first.
 -.wen
  
  The ability to give an immediate rejection (either by this option or using an
  ACL) is provided for use in unusual cases. Many hosts will just try again,
@@@ -16331,8 -16361,10 +16331,8 @@@ local processes, you must create a hos
  .code
  hosts_connection_nolog = :
  .endd
 -.new
  The hosts affected by this option also do not log "no MAIL in SMTP connection"
  lines, as may commonly be produced by a monitoring system.
 -.wen
  
  
  .option hosts_require_alpn main "host list&!!" unset
@@@ -17004,6 -17036,7 +17004,6 @@@ to be used in conjunction with &(oracle
  The option is available only if Exim has been built with Oracle support.
  
  
 -.new
  .option panic_coredump main boolean false
  This option is rarely needed but can help for some debugging investigations.
  If set, when an internal error is detected by Exim which is sufficient
@@@ -17014,6 -17047,7 +17014,6 @@@ then a coredump is requested
  Note that most systems require additional administrative configuration
  to permit write a core file for a setuid program, which is Exim's
  common installed configuration.
 -.wen
  
  .option percent_hack_domains main "domain list&!!" unset
  .cindex "&""percent hack""&"
@@@ -17796,8 -17830,10 +17796,8 @@@ positive response to an SMTP connection
  smtp_banner = $smtp_active_hostname ESMTP Exim \
    $version_number $tod_full
  .endd
 -.new
  Failure to expand the string causes a panic error;
  a forced fail just closes the connection.
 -.wen
  If you want to create a
  multiline response to the initial SMTP connection, use &"\n"& in the string at
  appropriate points, but not at the end. Note that the 220 code is not included
@@@ -18543,7 -18579,9 +18543,7 @@@ It has no effect when Exim is used wit
  &%tls_require_ciphers%& option).
  
  After expansion it must contain
 -.new
  one or (only for OpenSSL versiona 1.1.1 onwards) more
 -.wen
  EC curve names, such as &`prime256v1`&, &`secp384r1`&, or &`P-521`&.
  Consult your OpenSSL manual for valid curve names.
  
@@@ -18551,7 -18589,9 +18551,7 @@@ For OpenSSL versions before (and not in
  &`auto`& selects &`prime256v1`&. For more recent OpenSSL versions
  &`auto`& tells the library to choose.
  
 -.new
  If the option expands to an empty string, the effect is undefined.
 -.wen
  
  
  .option tls_ocsp_file main string&!! unset
@@@ -25743,9 -25783,11 +25743,9 @@@ Exim will request a Certificate Status 
  TLS session for any host that matches this list.
  &%tls_verify_certificates%& should also be set for the transport.
  
 -.new
  The default is &"**"& if DANE is not in use for the connection,
  or if DANE-TA us used.
  It is empty if DANE-EE is used.
 -.wen
  
  .option hosts_require_alpn smtp "host list&!!" unset
  .cindex ALPN "require negotiation in client"
@@@ -25891,12 -25933,16 +25891,12 @@@ has advertised support for IGNOREQUOTA 
  .option max_rcpt smtp integer&!! 100
  .cindex "RCPT" "maximum number of outgoing"
  This option,
 -.new
  after expansion,
 -.wen
  limits the number of RCPT commands that are sent in a single
  SMTP message transaction.
  A value setting of zero disables the limit.
  
 -.new
  If a constant is given,
 -.wen
  each set of addresses is treated independently, and
  so can cause parallel connections to the same host if &%remote_max_parallel%&
  permits this.
@@@ -27707,6 -27753,7 +27707,6 @@@ no successful authentication
  Successful authentication sets up information used by the
  &%authresults%& expansion item.
  
 -.new
  .cindex authentication "failure event, server"
  If an authenticator is run and does not succeed,
  an event (see &<<CHAPevents>>&) of type "auth:fail" is raised.
@@@ -27717,6 -27764,7 +27717,6 @@@ will be valid
  If the event is serviced and a string is returned then the string will be logged
  instead of the default log line.
  See <<CHAPevents>> for details on events.
 -.wen
  
  
  .section "Testing server authentication" "SECID169"
@@@ -27795,6 -27843,7 +27795,6 @@@ Exim abandons trying to send the messag
  try again later. If there are any backup hosts available, they are tried in the
  usual way.
  
 -.new
  .next
  .cindex authentication "failure event, client"
  If the response to authentication is a permanent error (5&'xx'& code),
@@@ -27804,6 -27853,7 +27804,6 @@@ While the event is being processed the 
  will be valid.
  If the event is serviced and a string is returned then the string will be logged.
  See <<CHAPevents>> for details on events.
 -.wen
  
  .next
  If the response to authentication is a permanent error (5&'xx'& code), Exim
@@@ -28383,9 -28433,11 +28383,9 @@@ dovecot_ntlm
    server_set_id = $auth1
  .endd
  
 -.new
  &*Note*&: plaintext authentication methods such as PLAIN and LOGIN
  should not be advertised on cleartext SMTP connections.
  See the discussion in section &<<SECTplain_TLS>>&.
 -.wen
  
  If the SMTP connection is encrypted, or if &$sender_host_address$& is equal to
  &$received_ip_address$& (that is, the connection is local), the &"secured"&
@@@ -29194,8 -29246,8 +29194,8 @@@ When using OpenSSL, this option is igno
  (If an API is found to let OpenSSL be configured in this way,
  let the Exim Maintainers know and we'll likely use it).
  .next
 -With GnuTLS, if an explicit list is used for the &%tls_privatekey%& main option
 -main option, it must be ordered to match the &%tls_certificate%& list.
 +With GnuTLS, if an explicit list is used for the &%tls_privatekey%& main option,
 +it must be ordered to match the &%tls_certificate%& list.
  .next
  Some other recently added features may only be available in one or the other.
  This should be documented with the feature.  If the documentation does not
@@@ -30289,7 -30341,7 +30289,7 @@@ DNSSEC
  .next
  Add TLSA DNS records.  These say what the server certificate for a TLS connection should be.
  .next
 -Offer a server certificate, or certificate chain, in TLS connections which is is anchored by one of the TLSA records.
 +Offer a server certificate, or certificate chain, in TLS connections which is anchored by one of the TLSA records.
  .endlist
  
  There are no changes to Exim specific to server-side operation of DANE.
@@@ -30618,9 -30670,11 +30618,9 @@@ accepted by an &%accept%& verb that ha
  the message override the banner message that is otherwise specified by the
  &%smtp_banner%& option.
  
 -.new
  For tls-on-connect connections, the ACL is run before the TLS connection
  is accepted; if the ACL does not accept then the TCP connection is dropped without
  any TLS startup attempt and without any SMTP response being transmitted.
 -.wen
  
  
  .subsection "The EHLO/HELO ACL" SECID192
@@@ -32157,6 -32211,7 +32157,6 @@@ DATA, MIME or DKIM ACLs for a message d
  
  More than one header can be removed at the same time by using a colon separated
  list of header specifiers.
 -.new
  If a specifier does not start with a circumflex (^)
  then it is treated as a header name.
  The header name matching is case insensitive.
@@@ -32170,6 -32225,7 +32170,6 @@@ Example
  .code
  remove_header = \N^(?i)Authentication-Results\s*::\s*example.org;\N
  .endd
 -.wen
  
  List expansion is not performed, so you cannot use hostlists to
  create a list of headers, however both connection and message variable expansion
@@@ -39131,10 -39187,12 +39131,10 @@@ only way to log such cases is to interp
  between the caller and Exim.
  .next
  .cindex "log" "connection identifier"
 -.new
  &%connection_identifier%&: An identifier for the accepted connection is added to
  connection start and end lines and to message accept lines.
  The identifier is tagged by Ci=.
  The value is PID-based, so will reset on reboot and will wrap.
 -.wen
  .next
  .cindex "log" "connection rejections"
  &%connection_reject%&: A log entry is written whenever an incoming SMTP
@@@ -41733,8 -41791,9 +41733,9 @@@ RFC 6376 lists these tags as RECOMMENDE
  
  Verification of DKIM signatures in SMTP incoming email is done for all
  messages for which an ACL control &%dkim_disable_verify%& has not been set.
  .cindex DKIM "selecting signature algorithms"
- Individual classes of signature algorithm can be ignored by changing
+ Individual classes of DKIM signature algorithm can be ignored by changing
  the main options &%dkim_verify_hashes%& or &%dkim_verify_keytypes%&.
  The &%dkim_verify_minimal%& option can be set to cease verification
  processing for a message once the first passing signature is found.
@@@ -41747,7 -41806,7 +41748,7 @@@ For most purposes the default option se
  of this section can be ignored.
  
  The results of verification are made available to the
- &%acl_smtp_dkim%& ACL, which can examine and modify them.
+ &%acl_smtp_dkim%& ACL, which (for complex needs) can examine and modify them.
  A missing ACL definition defaults to accept.
  By default, the ACL is called once for each
  syntactically(!) correct signature in the incoming message.
@@@ -41812,6 -41871,12 +41813,12 @@@ an identity. This is one of the list it
  &%dkim_verify_signers%& (see above).
  
  .vitem &%$dkim_verify_status%&
+ So long as a DKIM ACL is defined
+ (it need do no more than accept, which is the default),
+ after all the DKIM ACL runs have completed, the value becomes a
+ colon-separated list of the values after each run.
+ The value is maintained for the MIME, PRDR and DATA ACLs.
  Within the DKIM ACL,
  a string describing the general status of the signature. One of
  .ilist
@@@ -41840,11 -41905,6 +41847,6 @@@ hash-method or key-size
         set dkim_verify_reason = hash too weak or key too short
  .endd
  
- So long as a DKIM ACL is defined (it need do no more than accept),
- after all the DKIM ACL runs have completed, the value becomes a
- colon-separated list of the values after each run.
- This is maintained for the mime, prdr and data ACLs.
  .vitem &%$dkim_verify_reason%&
  A string giving a little bit more detail when &%$dkim_verify_status%& is either
  "fail" or "invalid". One of
@@@ -41969,13 -42029,15 +41971,15 @@@ option
  
  .endlist
  
- In addition, two ACL conditions are provided, usable only in a DKIM ACL:
+ In addition, two ACL conditions are provided:
  
  .vlist
  .vitem &%dkim_signers%&
  ACL condition that checks a colon-separated list of domains or identities
  for a match against the domain or identity that the ACL is currently verifying
- (reflected by &%$dkim_cur_signer%&). This is typically used to restrict an ACL
+ (reflected by &%$dkim_cur_signer%&).
+ This condition is only usable in a DKIM ACL.
+ This is typically used to restrict an ACL
  verb to a group of domains or identities. For example:
  
  .code
@@@ -41991,7 -42053,18 +41995,18 @@@ for that check for empty &$h_DKIM-Signa
  
  .vitem &%dkim_status%&
  ACL condition that checks a colon-separated list of possible DKIM verification
- results against the actual result of verification. This is typically used
+ results against the actual result of verification,
+ given by &$dkim_verify_status$& if that is non-empty or "none" if empty.
+ .new
+ This condition may be used in DKIM, MIME, PRDR and DATA ACLs.
+ .wen
+ A basic verification might be:
+ .code
+ deny !dkim_status = pass:none:invalid
+ .endd
+ A more complex use could be
  to restrict an ACL verb to a list of verification outcomes, for example:
  
  .code
@@@ -42004,6 -42077,12 +42019,12 @@@ deny sender_domains = paypal.com:paypal
  The possible status keywords are: 'none','invalid','fail' and 'pass'. Please
  see the documentation of the &%$dkim_verify_status%& expansion variable above
  for more information of what they mean.
+ The condition is true if the status
+ .new
+ (or any of the list of status values)
+ .wen
+ is any one of the supplied list.
  .endlist
  
  
@@@ -42256,9 -42335,11 +42277,9 @@@ return false
  If it is, the condition will return true and the variable
  &$srs_recipient$& will be set to the decoded (original) value.
  
 -.new
  If the second argument is empty then the condition returns true if
  the first argument is in valid SRS formet, else false.
  The variable &$srs_recipient$& is not set for this case.
 -.wen
  .endlist
  
  Example usage:
@@@ -42957,8 -43038,8 +42978,8 @@@ All other message types ignore the resu
  no other use is made of it.
  
  For a tcp:connect event, if the connection is being made to a proxy
 -then the address and port variables will be that of the proxy and not
 -the target system.
 +then the &$host_address$& and &$host_port$& variables
 +will be that of the proxy and not the target system.
  
  For tls:cert events, if GnuTLS is in use this will trigger only per
  chain element received on the connection.
diff --combined doc/doc-txt/ChangeLog
index 4306cabc0c7693313451ba43bc062c0ae6599e88,c1b577f6217fe84b00d7bc343837df9e3f45606d..990e72823a4b2b9465dd6aabe1631a8db95a11b2
@@@ -2,6 -2,17 +2,20 @@@ This document describes *changes* to pr
  affect Exim's operation, with an unchanged configuration file.  For new
  options, and new features, see the NewStuff file next to this ChangeLog.
  
 -Since 4.97
++Exim version 4.98
+ -----------------
 -JH/01 Handle error on close of the spool data file during reception.  Previously
++JH/01 Support list of dkim results in the dkim_status ACL condition, making
++      it more usable in the data ACL.
++
++JH/02 Handle error on close of the spool data file during reception.  Previously
+       This was only logged, on the assumption that errors would be seen for
+       a previous fflush().  However, a fuse filesystem has been reported as
+       showing this an error for the fclose().  The spool is now in an uncertain
+       state, and we have logged and responded acceptance.  Change this to
+       respond with a temp-reject, wipe spoolfiles, and log the error detail.
  Exim version 4.97
  -----------------
  
@@@ -88,7 -99,7 +102,7 @@@ JH/18 Fix a fencepost error in logging
  
  JH/19 Bug 2911: Fix a recursion in DNS lookups.  Previously, if the main option
        dns_again_means_nonexist included an element causing a DNS lookup which
 -      iteslf returned DNS_AGAIN, unbounded recursion occurred.  Possible results
 +      itself returned DNS_AGAIN, unbounded recursion occurred.  Possible results
        included (though probably not limited to) a process crash from stack
        memory limit, or from excessive open files.  Replace this with a paniclog
        whine (as this is likely a configuration error), and returning
@@@ -193,27 -204,10 +207,28 @@@ JH/38 Taint-track intermediate values f
  JH/39 Bug 3023: Fix crash induced by some combinations of zero-length strings
        and ${tr...}.  Found and diagnosed by Heiko Schlichting.
  
 -JH/40 Support list of dkim results in the dkim_status ACL condition, making
 -      it more usable in the data ACL.
 +JH/40 Bug 2999: Fix a possible OOB write in the external authenticator, which
 +      could be triggered by externally-supplied input.  Found by Trend Micro.
 +      CVE-2023-42115
 +
 +JH/41 Bug 3000: Fix a possible OOB write in the SPA authenticator, which could
 +      be triggered by externally-controlled input.  Found by Trend Micro.
 +      CVE-2023-42116
 +
 +JH/42 Bug 3001: Fix a possible OOB read in the SPA authenticator, which could
 +      be triggered by externally-controlled input.  Found by Trend Micro.
 +      CVE-2023-42114
 +
 +JH/43 Bug 2903: avoid exit on an attempt to rewrite a malformed address.
 +      Make the rewrite never match and keep the logging.  Trust the
 +      admin to be using verify=header-syntax (to actually reject the message).
 +
 +JH/44 Bug 3033: Harden dnsdb lookups against crafted DNS responses.
 +      CVE-2023-42219
 +
 +HS/02 Fix string_is_ip_address() CVE-2023-42117 (Bug 3031)
  
  Exim version 4.96
  -----------------
  
diff --combined doc/doc-txt/NewStuff
index af084448b51376f1d73310c80e619dab425b424b,beca9748c792914070d2e887243ba4271a6bf6ba..6aef41e50b53022180e0bdc9b1e4ce7aa8cfe2ef
@@@ -6,6 -6,10 +6,10 @@@ Before a formal release, there may be q
  test from the snapshots or the Git before the documentation is updated. Once
  the documentation is updated, this file is reduced to a short list.
  
 -Since 4.97
++Version 4.98
+ ------------
 - 1. The dkim_status ACL condition may not be used in data ACLs
++ 1. The dkim_status ACL condition may now be used in data ACLs
  Version 4.97
  ------------
  
@@@ -1190,7 -1194,7 +1194,7 @@@ Version 4.6
  
   9. There is a new ACL, specified by acl_smtp_notquit, which is run in most
      cases when an SMTP session ends without sending QUIT. However, when Exim
 -    itself is is bad trouble, such as being unable to write to its log files,
 +    itself is in bad trouble, such as being unable to write to its log files,
      this ACL is not run, because it might try to do things (such as write to
      log files) that make the situation even worse.
  
diff --combined src/src/acl.c
index 578cf32cb7e31a83412764db40fa7d71a42dfb43,8431efc84cb70a47c57871c72536c14bdbe0ebf6..cdf60bbb84084390a4a35b91e0e3f3d0512feca6
@@@ -2,7 -2,7 +2,7 @@@
  *     Exim - an Internet mail transport agent    *
  *************************************************/
  
 -/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 +/* Copyright (c) The Exim Maintainers 2020 - 2023 */
  /* Copyright (c) University of Cambridge 1995 - 2018 */
  /* See the file NOTICE for conditions of use and distribution. */
  /* SPDX-License-Identifier: GPL-2.0-or-later */
@@@ -203,7 -203,14 +203,14 @@@ static condition_def conditions[] = 
    [ACLC_DELAY] =              { US"delay",            TRUE, TRUE, ACL_BIT_NOTQUIT },
  #ifndef DISABLE_DKIM
    [ACLC_DKIM_SIGNER] =                { US"dkim_signers",     TRUE, FALSE, (unsigned int) ~ACL_BIT_DKIM },
-   [ACLC_DKIM_STATUS] =                { US"dkim_status",      TRUE, FALSE, (unsigned int) ~ACL_BIT_DKIM },
+   [ACLC_DKIM_STATUS] =                { US"dkim_status",      TRUE, FALSE,
+                                 (unsigned int)
+                                 ~(ACL_BIT_DKIM | ACL_BIT_DATA | ACL_BIT_MIME
+ # ifndef DISABLE_PRDR
+                                 | ACL_BIT_PRDR
+ # endif
+       ),
+   },
  #endif
  #ifdef SUPPORT_DMARC
    [ACLC_DMARC_STATUS] =               { US"dmarc_status",     TRUE, FALSE, (unsigned int) ~ACL_BIT_DATA },
@@@ -1434,7 -1441,6 +1441,7 @@@ for (rr = dns_next_rr(dnsa, &dnss, RESE
  
    /* Extract the numerical SRV fields (p is incremented) */
  
 +  if (rr_bad_size(rr, 3 * sizeof(uint16_t))) continue;
    GETSHORT(priority, p);
    GETSHORT(weight, p);
    GETSHORT(port, p);
@@@ -3764,8 -3770,14 +3771,14 @@@ for (; cb; cb = cb->next
        break;
  
      case ACLC_DKIM_STATUS:
-       rc = match_isinlist(dkim_verify_status,
-                         &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL);
+       {               /* return good for any match */
+       const uschar * s = dkim_verify_status ? dkim_verify_status : US"none";
+       int sep = 0;
+       for (uschar * ss; ss = string_nextinlist(&s, &sep, NULL, 0); )
+       if (   (rc = match_isinlist(ss, &arg,
+                                   0, NULL, NULL, MCL_STRING, TRUE, NULL))
+           == OK) break;
+       }
        break;
  #endif
  
diff --combined src/src/auths/get_data.c
index 4c67f17e23a2f39e367761e84b1f46eae314f215,b52de6aba266c8096755586dff0239b3cac34398..0c9fb37fe8455b86d7e3e17dc2f7d0f878730710
@@@ -2,8 -2,8 +2,8 @@@
  *     Exim - an Internet mail transport agent    *
  *************************************************/
  
 +/* Copyright (c) The Exim Maintainers 2020 - 2023 */
  /* Copyright (c) University of Cambridge 1995 - 2018 */
 -/* Copyright (c) The Exim Maintainers 2020 - 2021 */
  /* See the file NOTICE for conditions of use and distribution. */
  /* SPDX-License-Identifier: GPL-2.0-or-later */
  
@@@ -77,7 -77,7 +77,7 @@@ auth_get_data(uschar ** aptr, const usc
  {
  int c;
  int p = 0;
- smtp_printf("334 %s\r\n", FALSE, b64encode(challenge, challen));
+ smtp_printf("334 %s\r\n", SP_NO_MORE, b64encode(challenge, challen));
  while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF)
    {
    if (p >= big_buffer_size - 1) return BAD64;
diff --combined src/src/daemon.c
index 9709845e5f8abf8b4d9b0a91742b95ae29e506c3,b0938cbaa37124933ffb3fe57a7117abb71d85da..f2183c735f6acb3f9813cb8c01844491230cb9c0
@@@ -2,8 -2,8 +2,8 @@@
  *     Exim - an Internet mail transport agent    *
  *************************************************/
  
 -/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 -/* Copyright (c) University of Cambridge 1995 - 2023 */
 +/* Copyright (c) The Exim Maintainers 2020 - 2023 */
 +/* Copyright (c) University of Cambridge 1995 - 2018 */
  /* See the file NOTICE for conditions of use and distribution. */
  /* SPDX-License-Identifier: GPL-2.0-or-later */
  
@@@ -128,7 -128,7 +128,7 @@@ never_error(uschar *log_msg, uschar *sm
  uschar *emsg = was_errno <= 0
    ? US"" : string_sprintf(": %s", strerror(was_errno));
  log_write(0, LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg);
- if (smtp_out) smtp_printf("421 %s\r\n", FALSE, smtp_msg);
+ if (smtp_out) smtp_printf("421 %s\r\n", SP_NO_MORE, smtp_msg);
  }
  
  
@@@ -233,7 -233,7 +233,7 @@@ if (getsockname(accept_socket, (struct 
    {
    log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
      "getsockname() failed: %s", strerror(errno));
-   smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", FALSE);
+   smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", SP_NO_MORE);
    goto ERROR_RETURN;
    }
  
@@@ -263,7 -263,7 +263,7 @@@ if (smtp_accept_max > 0 && smtp_accept_
    DEBUG(D_any) debug_printf("rejecting SMTP connection: count=%d max=%d\n",
      smtp_accept_count, smtp_accept_max);
    smtp_printf("421 Too many concurrent SMTP connections; "
-     "please try again later.\r\n", FALSE);
+     "please try again later.\r\n", SP_NO_MORE);
    log_write(L_connection_reject,
              LOG_MAIN, "Connection from %Y refused: too many connections",
      whofrom);
@@@ -282,7 -282,7 +282,7 @@@ if (smtp_load_reserve >= 0
      {
      DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n",
        (double)load_average/1000.0);
-     smtp_printf("421 Too much load; please try again later.\r\n", FALSE);
+     smtp_printf("421 Too much load; please try again later.\r\n", SP_NO_MORE);
      log_write(L_connection_reject,
                LOG_MAIN, "Connection from %Y refused: load average = %.2f",
        whofrom, (double)load_average/1000.0);
@@@ -351,7 -351,7 +351,7 @@@ if (max_for_this_host > 0 && smtp_accep
        "IP address: count=%d max=%d\n",
        host_accept_count, max_for_this_host);
      smtp_printf("421 Too many concurrent SMTP connections "
-       "from this IP address; please try again later.\r\n", FALSE);
+       "from this IP address; please try again later.\r\n", SP_NO_MORE);
      log_write(L_connection_reject,
                LOG_MAIN, "Connection from %Y refused: too many connections "
        "from that IP address", whofrom);
@@@ -445,7 -445,7 +445,7 @@@ if (pid == 0
            "(smtp_active_hostname): %s", raw_active_hostname,
            expand_string_message);
          smtp_printf("421 Local configuration error; "
-           "please try again later.\r\n", FALSE);
+           "please try again later.\r\n", SP_NO_MORE);
          mac_smtp_fflush();
          search_tidyup();
          exim_underbar_exit(EXIT_FAILURE);
diff --combined src/src/macros.h
index 2658b9ab7d91f1a106ba6e68565ef80810cf81d3,250858ab4e9c97f94154d3357a076ebf2eddd915..9693935614c26b59be6b791dc94b4f00690f8bd7
@@@ -2,7 -2,7 +2,7 @@@
  *     Exim - an Internet mail transport agent    *
  *************************************************/
  
 -/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 +/* Copyright (c) The Exim Maintainers 2020 - 2023 */
  /* Copyright (c) University of Cambridge 1995 - 2018 */
  /* See the file NOTICE for conditions of use and distribution. */
  /* SPDX-License-Identifier: GPL-2.0-or-later */
@@@ -1159,4 -1159,12 +1159,12 @@@ typedef unsigned mcs_flags
  #define TSUC_ALLOW_TAINTED_ARGS       BIT(1)
  #define TSUC_ALLOW_RECIPIENTS BIT(2)
  
+ /* Flags for smtp_printf */
+ #define SP_MORE               TRUE
+ #define SP_NO_MORE    FALSE
+ /* Flags for smtp_respond */
+ #define SR_FINAL      TRUE
+ #define SR_NOT_FINAL  FALSE
  /* End of macros.h */
diff --combined src/src/pdkim/pdkim.c
index 36e559b59db292478da38104006b79c5a7037657,22b8502429a886cdaacc8eb8b26543975faf5176..c723ae6c876817b322f89b83c35d77d35cad919b
@@@ -1,9 -1,9 +1,9 @@@
  /*
   *  PDKIM - a RFC4871 (DKIM) implementation
   *
 - *  Copyright (c) The Exim Maintainers 2021 - 2022
 - *  Copyright (C) 2009 - 2016  Tom Kistner <tom@duncanthrax.net>
 + *  Copyright (c) The Exim Maintainers 2021 - 2023
   *  Copyright (C) 2016 - 2020  Jeremy Harris <jgh@exim.org>
 + *  Copyright (C) 2009 - 2016  Tom Kistner <tom@duncanthrax.net>
   *  SPDX-License-Identifier: GPL-2.0-or-later
   *
   *  http://duncanthrax.net/pdkim/
@@@ -1868,9 -1868,9 +1868,9 @@@ for (pdkim_signature * sig = ctx->sig; 
      if (*dkim_verify_min_keysizes)
        {
        unsigned minbits;
-       uschar * ss = expand_getkeyed(US pdkim_keytypes[sig->keytype],
+       const uschar * ss = expand_getkeyed(US pdkim_keytypes[sig->keytype],
                                    dkim_verify_min_keysizes);
-       if (ss &&  (minbits = atoi(CS ss)) > sig->keybits)
+       if (ss &&  (minbits = atoi(CCS ss)) > sig->keybits)
        {
        DEBUG(D_acl) debug_printf("Key too short: Actual: %s %u  Minima '%s'\n",
          pdkim_keytypes[sig->keytype], sig->keybits, dkim_verify_min_keysizes);
diff --combined src/src/receive.c
index 8a400caf0517f0a929eabcd67eb0efdcc8dab5e4,dbb43e7497e763d5497e60d1034db42390e2035d..8190c594130ab36f6735961fd119c8149648400f
@@@ -2,7 -2,7 +2,7 @@@
  *     Exim - an Internet mail transport agent    *
  *************************************************/
  
 -/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 +/* Copyright (c) The Exim Maintainers 2020 - 2023 */
  /* Copyright (c) University of Cambridge 1995 - 2018 */
  /* See the file NOTICE for conditions of use and distribution. */
  /* SPDX-License-Identifier: GPL-2.0-or-later */
@@@ -570,7 -570,7 +570,7 @@@ smtp_user_msg(uschar *code, uschar *use
  {
  int len = 3;
  smtp_message_code(&code, &len, &user_msg, NULL, TRUE);
- smtp_respond(code, len, TRUE, user_msg);
+ smtp_respond(code, len, SR_FINAL, user_msg);
  }
  #endif
  
@@@ -1457,7 -1457,7 +1457,7 @@@ if (!(mbox_file = spool_mbox(&mbox_size
  #ifdef EXPERIMENTAL_DCC
    dcc_ok = 0;
  #endif
-   smtp_respond(US"451", 3, TRUE, US"temporary local problem");
+   smtp_respond(US"451", 3, SR_FINAL, US"temporary local problem");
    message_id[0] = 0;            /* Indicate no message accepted */
    *smtp_reply_ptr = US"";       /* Indicate reply already sent */
    return FALSE;                 /* Indicate skip to end of receive function */
@@@ -2309,7 -2309,7 +2309,7 @@@ OVERSIZE
        sender_address,
        sender_fullhost ? " H=" : "", sender_fullhost ? sender_fullhost : US"",
        sender_ident ? " U=" : "",    sender_ident ? sender_ident : US"");
-     smtp_printf("552 Message header not CRLF terminated\r\n", FALSE);
+     smtp_printf("552 Message header not CRLF terminated\r\n", SP_NO_MORE);
      bdat_flush_data();
      smtp_reply = US"";
      goto TIDYUP;                             /* Skip to end of function */
@@@ -3251,10 -3251,9 +3251,9 @@@ if (!ferror(spool_data_file) && !(recei
        {
        Uunlink(spool_name);            /* Lose data file when closed */
        cancel_cutthrough_connection(TRUE, US"sender closed connection");
-       message_id[0] = 0;              /* Indicate no message_accepted */
        smtp_reply = handle_lost_connection(US"");
        smtp_yield = FALSE;
-       goto TIDYUP;                            /* Skip to end of function */
+       goto NOT_ACCEPTED;                              /* Skip to end of function */
        }
        break;
  
@@@ -3597,7 -3596,7 +3596,7 @@@ els
        int all_pass = OK;
        int all_fail = FAIL;
  
-       smtp_printf("353 PRDR content analysis beginning\r\n", TRUE);
+       smtp_printf("353 PRDR content analysis beginning\r\n", SP_MORE);
        /* Loop through recipients, responses must be in same order received */
        for (unsigned int c = 0; recipients_count > c; c++)
          {
      /* Check the recipients count again, as the MIME ACL might have changed
      them. */
  
-     if (acl_smtp_data != NULL && recipients_count > 0)
+     if (acl_smtp_data && recipients_count > 0)
        {
        rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg);
        add_acl_headers(ACL_WHERE_DATA, US"DATA");
@@@ -3922,7 -3921,7 +3921,7 @@@ els
    if (smtp_input)
      if (!smtp_batched_input)
        {
-       smtp_respond(smtp_code, 3, TRUE, errmsg);
+       smtp_respond(smtp_code, 3, SR_FINAL, errmsg);
        smtp_reply = US"";            /* Indicate reply already sent */
        goto NOT_ACCEPTED;                      /* Skip to end of function */
        }
@@@ -4030,11 -4029,6 +4029,6 @@@ els
  
  receive_messagecount++;
  
- /* Add data size to written header size. We do not count the initial file name
- that is in the file, but we do add one extra for the notional blank line that
- precedes the data. This total differs from message_size in that it include the
- added Received: header and any other headers that got created locally. */
  if (fflush(spool_data_file))
    {
    errmsg = string_sprintf("Spool write error: %s", strerror(errno));
      /* Does not return */
      }
    }
- fstat(data_fd, &statbuf);
  
+ /* Add data size to written header size. We do not count the initial file name
+ that is in the file, but we do add one extra for the notional blank line that
+ precedes the data. This total differs from message_size in that it include the
+ added Received: header and any other headers that got created locally. */
+ fstat(data_fd, &statbuf);
  msg_size += statbuf.st_size - spool_data_start_offset(message_id) + 1;
  
  /* Generate a "message received" log entry. We do this by building up a dynamic
@@@ -4349,9 -4348,9 +4348,9 @@@ if(!smtp_reply
  #endif
    {
    log_write(0, LOG_MAIN |
-     (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
-     (LOGGING(received_sender) ? LOG_SENDER : 0),
-     "%Y", g);
+               (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
+               (LOGGING(received_sender) ? LOG_SENDER : 0),
+           "%Y", g);
  
    /* Log any control actions taken by an ACL or local_scan(). */
  
@@@ -4389,9 -4388,16 +4388,16 @@@ a queue-runner could grab it in the win
  
  A fflush() was done earlier in the expectation that any write errors on the
  data file will be flushed(!) out thereby. Nevertheless, it is theoretically
- possible for fclose() to fail - but what to do? What has happened to the lock
- if this happens?  We can at least log it; if it is observed on some platform
- then we can think about properly declaring the message not-received. */
+ possible for fclose() to fail - and this has been seen on obscure filesystems
+ (probably one that delayed the actual media write as long as possible)
+ but what to do? What has happened to the lock if this happens?
+ It's a mes because we already logged the acceptance.
+ We can at least log the issue, try to remove spoolfiles and respond with
+ a temp-reject.  We do not want to close before logging acceptance because
+ we want to hold the lock until we know that logging worked.
+ Could we make this less likely by doing an fdatasync() just after the fflush()?
+ That seems like a good thing on data-security grounds, but how much will it hit
+ performance? */
  
  
  goto TIDYUP;
@@@ -4404,8 -4410,27 +4410,27 @@@ process_info[process_info_len] = 0;                   /
  if (spool_data_file && cutthrough_done == NOT_TRIED)
    {
    if (fclose(spool_data_file))                                /* Frees the lock */
-     log_write(0, LOG_MAIN|LOG_PANIC,
-       "spoolfile error on close: %s", strerror(errno));
+     {
+     log_msg = string_sprintf("spoolfile error on close: %s", strerror(errno));
+     log_write(0, LOG_MAIN|LOG_PANIC |
+                 (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
+                 (LOGGING(received_sender) ? LOG_SENDER : 0),
+             "%s", log_msg);
+     log_write(0, LOG_MAIN |
+                 (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) |
+                 (LOGGING(received_sender) ? LOG_SENDER : 0),
+             "rescind the above message-accept");
+     Uunlink(spool_name);
+     Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
+     Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
+     /* Claim a data ACL temp-reject, just to get reject logging and resposponse */
+     smtp_handle_acl_fail(ACL_WHERE_DATA, rc, NULL, log_msg);
+     smtp_reply = US"";                /* Indicate reply already sent */
+     message_id[0] = 0;                /* no message accepted */
+     }
    spool_data_file = NULL;
    }
  
@@@ -4434,7 -4459,7 +4459,7 @@@ if (smtp_input
        {
        if (fake_response != OK)
          smtp_respond(fake_response == DEFER ? US"450" : US"550",
-         3, TRUE, fake_response_text);
+         3, SR_FINAL, fake_response_text);
  
        /* An OK response is required; use "message" text if present. */
  
          uschar *code = US"250";
          int len = 3;
          smtp_message_code(&code, &len, &user_msg, NULL, TRUE);
-         smtp_respond(code, len, TRUE, user_msg);
+         smtp_respond(code, len, SR_FINAL, user_msg);
          }
  
        /* Default OK response */
  
      else if (smtp_reply[0] != 0)
        if (fake_response != OK && smtp_reply[0] == '2')
-         smtp_respond(fake_response == DEFER ? US"450" : US"550", 3, TRUE,
-           fake_response_text);
+         smtp_respond(fake_response == DEFER ? US"450" : US"550",
+                     3, SR_FINAL, fake_response_text);
        else
-         smtp_printf("%.1024s\r\n", FALSE, smtp_reply);
+         smtp_printf("%.1024s\r\n", SP_NO_MORE, smtp_reply);
  
      switch (cutthrough_done)
        {
diff --combined src/src/smtp_in.c
index 8cc9f74bf6c9635432a0e90c3b8ca12487810623,ffc7779f80694c18ef71e2677e7dcef149126c22..c565d522d9a27779a85ae73695ee3937fc2b1d2d
@@@ -2,7 -2,7 +2,7 @@@
  *     Exim - an Internet mail transport agent    *
  *************************************************/
  
 -/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 +/* Copyright (c) The Exim Maintainers 2020 - 2023 */
  /* Copyright (c) University of Cambridge 1995 - 2018 */
  /* See the file NOTICE for conditions of use and distribution. */
  /* SPDX-License-Identifier: GPL-2.0-or-later */
@@@ -764,7 -764,7 +764,7 @@@ for(;;
      return EOD;
      }
  
-   smtp_printf("250 %u byte chunk received\r\n", FALSE, chunking_datasize);
+   smtp_printf("250 %u byte chunk received\r\n", SP_NO_MORE, chunking_datasize);
    chunking_state = CHUNKING_OFFERED;
    DEBUG(D_receive) debug_printf("chunking state %d\n", (int)chunking_state);
  
@@@ -802,7 -802,7 +802,7 @@@ next_cmd
  
      case NOOP_CMD:
        HAD(SCH_NOOP);
-       smtp_printf("250 OK\r\n", FALSE);
+       smtp_printf("250 OK\r\n", SP_NO_MORE);
        goto next_cmd;
  
      case BDAT_CMD:
@@@ -1298,7 -1298,7 +1298,7 @@@ smtp_closedown(uschar * message
  {
  if (!smtp_in || smtp_batched_input) return;
  receive_swallow_smtp();
- smtp_printf("421 %s\r\n", FALSE, message);
+ smtp_printf("421 %s\r\n", SP_NO_MORE, message);
  
  for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED))
    {
  
    case QUIT_CMD:
      f.smtp_in_quit = TRUE;
-     smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
+     smtp_printf("221 %s closing connection\r\n", SP_NO_MORE, smtp_active_hostname);
      mac_smtp_fflush();
      return;
  
    case RSET_CMD:
-     smtp_printf("250 Reset OK\r\n", FALSE);
+     smtp_printf("250 Reset OK\r\n", SP_NO_MORE);
      break;
  
    default:
-     smtp_printf("421 %s\r\n", FALSE, message);
+     smtp_printf("421 %s\r\n", SP_NO_MORE, message);
      break;
    }
  }
@@@ -2266,7 -2266,7 +2266,7 @@@ if (!f.sender_host_unknown
          {
          log_write(0, LOG_MAIN, "getsockopt() failed from %s: %s",
            host_and_ident(FALSE), strerror(errno));
-         smtp_printf("451 SMTP service not available\r\n", FALSE);
+         smtp_printf("451 SMTP service not available\r\n", SP_NO_MORE);
          return FALSE;
          }
        }
        log_write(0, LOG_MAIN|LOG_REJECT,
          "connection from %s refused (IP options)", host_and_ident(FALSE));
  
-       smtp_printf("554 SMTP service not available\r\n", FALSE);
+       smtp_printf("554 SMTP service not available\r\n", SP_NO_MORE);
        return FALSE;
        }
  
  #ifndef DISABLE_TLS
      if (!tls_in.on_connect)
  #endif
-       smtp_printf("554 SMTP service not available\r\n", FALSE);
+       smtp_printf("554 SMTP service not available\r\n", SP_NO_MORE);
      return FALSE;
      }
  
        log_write(L_connection_reject,
                  LOG_MAIN|LOG_REJECT, "refused connection from %s "
                  "(tcp wrappers)", host_and_ident(FALSE));
-       smtp_printf("554 SMTP service not available\r\n", FALSE);
+       smtp_printf("554 SMTP service not available\r\n", SP_NO_MORE);
        }
      else
        {
        log_write(L_connection_reject,
                  LOG_MAIN|LOG_REJECT, "temporarily refused connection from %s "
                  "(tcp wrappers errno=%d)", host_and_ident(FALSE), save_errno);
-       smtp_printf("451 Temporary local problem - please try later\r\n", FALSE);
+       smtp_printf("451 Temporary local problem - please try later\r\n", SP_NO_MORE);
        }
      return FALSE;
      }
          host_and_ident(FALSE), smtp_accept_count - 1, smtp_accept_max,
          smtp_accept_reserve, (rc == DEFER)? " (lookup deferred)" : "");
        smtp_printf("421 %s: Too many concurrent SMTP connections; "
-         "please try again later\r\n", FALSE, smtp_active_hostname);
+         "please try again later\r\n", SP_NO_MORE, smtp_active_hostname);
        return FALSE;
        }
      reserved_host = TRUE;
        LOG_MAIN, "temporarily refused connection from %s: not in "
        "reserve list and load average = %.2f", host_and_ident(FALSE),
        (double)load_average/1000.0);
-     smtp_printf("421 %s: Too much load; please try again later\r\n", FALSE,
+     smtp_printf("421 %s: Too much load; please try again later\r\n", SP_NO_MORE,
        smtp_active_hostname);
      return FALSE;
      }
@@@ -2681,7 -2681,7 +2681,7 @@@ if (!check_sync()
        "synchronization error (input sent without waiting for greeting): "
        "rejected connection from %s input=\"%s\"", host_and_ident(TRUE),
        string_printing(string_copyn(smtp_inptr, n)));
-     smtp_printf("554 SMTP synchronization error\r\n", FALSE);
+     smtp_printf("554 SMTP synchronization error\r\n", SP_NO_MORE);
      return FALSE;
      }
  
@@@ -2692,7 -2692,7 +2692,7 @@@ smtp_printf("%Y"
  #ifndef DISABLE_PIPE_CONNECT
    fl.pipe_connect_acceptable && pipeline_connect_sends(),
  #else
-   FALSE,
+   SP_NO_MORE,
  #endif
    ss);
  
@@@ -2751,10 -2751,10 +2751,10 @@@ if (++synprot_error_count > smtp_max_sy
  
  if (code > 0)
    {
-   smtp_printf("%d%c%s%s%s\r\n", FALSE, code, yield == 1 ? '-' : ' ',
+   smtp_printf("%d%c%s%s%s\r\n", SP_NO_MORE, code, yield == 1 ? '-' : ' ',
      data ? data : US"", data ? US": " : US"", errmess);
    if (yield == 1)
-     smtp_printf("%d Too many syntax or protocol errors\r\n", FALSE, code);
+     smtp_printf("%d Too many syntax or protocol errors\r\n", SP_NO_MORE, code);
    }
  
  return yield;
@@@ -2781,7 -2781,7 +2781,7 @@@ Returns:        nothin
  */
  
  void
- smtp_respond(uschar* code, int codelen, BOOL final, uschar *msg)
+ smtp_respond(uschar * code, int codelen, BOOL final, uschar * msg)
  {
  int esclen = 0;
  uschar *esc = US"";
@@@ -2830,7 -2830,7 +2830,7 @@@ for (;;
      }
    else
      {
-     smtp_printf("%.3s-%.*s%.*s\r\n", TRUE, code, esclen, esc, (int)(nl - msg), msg);
+     smtp_printf("%.3s-%.*s%.*s\r\n", SP_MORE, code, esclen, esc, (int)(nl - msg), msg);
      msg = nl + 1;
      Uskip_whitespace(&msg);
      }
@@@ -2936,7 -2936,7 +2936,7 @@@ Returns:     0 in most case
  */
  
  int
- smtp_handle_acl_fail(int where, int rc, uschar *user_msg, uschar *log_msg)
+ smtp_handle_acl_fail(int where, int rc, uschar * user_msg, uschar * log_msg)
  {
  BOOL drop = rc == FAIL_DROP;
  int codelen = 3;
@@@ -3022,7 -3022,7 +3022,7 @@@ if (sender_verified_failed &
        string_sprintf(": %s", sender_verified_failed->message));
  
    if (rc == FAIL && sender_verified_failed->user_message)
-     smtp_respond(smtp_code, codelen, FALSE, string_sprintf(
+     smtp_respond(smtp_code, codelen, SR_NOT_FINAL, string_sprintf(
          testflag(sender_verified_failed, af_verify_pmfail)?
            "Postmaster verification failed while checking <%s>\n%s\n"
            "Several RFCs state that you are required to have a postmaster\n"
@@@ -3054,7 -3054,7 +3054,7 @@@ always a 5xx one - see comments at the 
  rc was FAIL_DROP we drop the connection and yield 2. */
  
  if (rc == FAIL)
-   smtp_respond(smtp_code, codelen, TRUE,
+   smtp_respond(smtp_code, codelen, SR_FINAL,
      user_msg ? user_msg : US"Administrative prohibition");
  
  /* Send temporary failure response to the command. Don't give any details,
         && sender_verified_failed
         && sender_verified_failed->message
         )
-       smtp_respond(smtp_code, codelen, FALSE, sender_verified_failed->message);
+       smtp_respond(smtp_code, codelen, SR_NOT_FINAL, sender_verified_failed->message);
  
-     smtp_respond(smtp_code, codelen, TRUE, user_msg);
+     smtp_respond(smtp_code, codelen, SR_FINAL, user_msg);
      }
    else
-     smtp_respond(smtp_code, codelen, TRUE,
+     smtp_respond(smtp_code, codelen, SR_FINAL,
        US"Temporary local problem - please try later");
  
  /* Log the incident to the logs that are specified by log_reject_target
@@@ -3194,7 -3194,7 +3194,7 @@@ responses are all internal, they shoul
  if (code && defaultrespond)
    {
    if (user_msg)
-     smtp_respond(code, 3, TRUE, user_msg);
+     smtp_respond(code, 3, SR_FINAL, user_msg);
    else
      {
      gstring * g;
      va_start(ap, defaultrespond);
      g = string_vformat(NULL, SVFMT_EXTEND|SVFMT_REBUFFER, CS defaultrespond, ap);
      va_end(ap);
-     smtp_printf("%s %Y\r\n", FALSE, code, g);
+     smtp_printf("%s %Y\r\n", SP_NO_MORE, code, g);
      }
    mac_smtp_fflush();
    }
@@@ -3360,7 -3360,7 +3360,7 @@@ smtp_user_msg(uschar *code, uschar *use
  {
  int len = 3;
  smtp_message_code(&code, &len, &user_msg, NULL, TRUE);
- smtp_respond(code, len, TRUE, user_msg);
+ smtp_respond(code, len, SR_FINAL, user_msg);
  }
  
  
@@@ -3495,7 -3495,7 +3495,7 @@@ if (f.allow_unqualified_recipient || st
    *recipient = US rewrite_address_qualify(*recipient, TRUE);
    return rd;
    }
- smtp_printf("501 %s: recipient address must contain a domain\r\n", FALSE,
+ smtp_printf("501 %s: recipient address must contain a domain\r\n", SP_NO_MORE,
    smtp_cmd_data);
  log_write(L_smtp_syntax_error,
    LOG_MAIN|LOG_REJECT, "unqualified %s rejected: <%s> %s%s",
@@@ -3523,9 -3523,9 +3523,9 @@@ if (  acl_smtp_qui
  #endif
  
  if (*user_msgp)
-   smtp_respond(US"221", 3, TRUE, *user_msgp);
+   smtp_respond(US"221", 3, SR_FINAL, *user_msgp);
  else
-   smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
+   smtp_printf("221 %s closing connection\r\n", SP_NO_MORE, smtp_active_hostname);
  
  #ifdef SERVERSIDE_CLOSE_NOWAIT
  # ifndef DISABLE_TLS
@@@ -3554,7 -3554,7 +3554,7 @@@ smtp_rset_handler(void
  {
  HAD(SCH_RSET);
  incomplete_transaction_log(US"RSET");
- smtp_printf("250 Reset OK\r\n", FALSE);
+ smtp_printf("250 Reset OK\r\n", SP_NO_MORE);
  cmd_list[CL_RSET].is_mail_cmd = FALSE;
  if (chunking_state > CHUNKING_OFFERED)
    chunking_state = CHUNKING_OFFERED;
@@@ -3809,7 -3809,7 +3809,7 @@@ while (done <= 0
          {
          int rc = smtp_in_auth(au, &smtp_resp, &errmsg);
  
-         smtp_printf("%s\r\n", FALSE, smtp_resp);
+         smtp_printf("%s\r\n", SP_NO_MORE, smtp_resp);
          if (rc != OK)
            {
            uschar * logmsg = NULL;
  
        if (!check_helo(smtp_cmd_data))
        {
-       smtp_printf("501 Syntactically invalid %s argument(s)\r\n", FALSE, hello);
+       smtp_printf("501 Syntactically invalid %s argument(s)\r\n", SP_NO_MORE, hello);
  
        log_write(0, LOG_MAIN|LOG_REJECT, "rejected %s from %s: syntactically "
          "invalid argument(s): %s", hello, host_and_ident(FALSE),
            {
            if (fl.helo_verify_required)
              {
-             smtp_printf("%d %s argument does not match calling host\r\n", FALSE,
+             smtp_printf("%d %s argument does not match calling host\r\n", SP_NO_MORE,
                tempfail? 451 : 550, hello);
              log_write(0, LOG_MAIN|LOG_REJECT, "%srejected \"%s %s\" from %s",
                tempfail? "temporarily " : "",
          done = synprot_error(L_smtp_syntax_error, resp, NULL, errmsg);
        else
          {
-         smtp_printf("%d %s\r\n", FALSE, resp, errmsg);
+         smtp_printf("%d %s\r\n", SP_NO_MORE, resp, errmsg);
          log_write(0, LOG_MAIN|LOG_REJECT, "rejected XCLIENT from %s: %s",
            host_and_ident(FALSE), errmsg);
          }
        We require that we do; the following HELO/EHLO handling will set
        sender_helo_name as normal. */
  
-       smtp_printf("%s XCLIENT success\r\n", FALSE, smtp_code);
+       smtp_printf("%s XCLIENT success\r\n", SP_NO_MORE, smtp_code);
        }
        break; /* XCLIENT */
        }
        if (  fl.helo_verify_required
           || verify_check_host(&hosts_require_helo) == OK)
          {
-         smtp_printf("503 HELO or EHLO required\r\n", FALSE);
+         smtp_printf("503 HELO or EHLO required\r\n", SP_NO_MORE);
          log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no "
            "HELO/EHLO given", host_and_ident(FALSE));
          break;
  
        if (smtp_mailcmd_max > 0 && smtp_mailcmd_count > smtp_mailcmd_max)
        {
-       smtp_printf("421 too many messages in this connection\r\n", FALSE);
+       smtp_printf("421 too many messages in this connection\r\n", SP_NO_MORE);
        log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many "
          "messages in one connection", host_and_ident(TRUE));
        break;
  
        if (thismessage_size_limit > 0 && message_size > thismessage_size_limit)
        {
-       smtp_printf("552 Message size exceeds maximum permitted\r\n", FALSE);
+       smtp_printf("552 Message size exceeds maximum permitted\r\n", SP_NO_MORE);
        log_write(L_size_reject,
            LOG_MAIN|LOG_REJECT, "rejected MAIL FROM:<%s> %s: "
            "message too big: size%s=%d max=%d",
           smtp_check_spool_space && message_size >= 0
              ? message_size + 5000 : 0))
        {
-       smtp_printf("452 Space shortage, please try later\r\n", FALSE);
+       smtp_printf("452 Space shortage, please try later\r\n", SP_NO_MORE);
        sender_address = NULL;
        break;
        }
          }
        else
          {
-         smtp_printf("501 %s: sender address must contain a domain\r\n", FALSE,
+         smtp_printf("501 %s: sender address must contain a domain\r\n", SP_NO_MORE,
            smtp_cmd_data);
          log_write(L_smtp_syntax_error,
            LOG_MAIN|LOG_REJECT,
        {
        if (f.smtp_in_pipelining_advertised && last_was_rej_mail)
          {
-         smtp_printf("503 sender not yet given\r\n", FALSE);
+         smtp_printf("503 sender not yet given\r\n", SP_NO_MORE);
          was_rej_mail = TRUE;
          }
        else
        if (recipients_max_reject)
          {
          rcpt_fail_count++;
-         smtp_printf("552 too many recipients\r\n", FALSE);
+         smtp_printf("552 too many recipients\r\n", SP_NO_MORE);
          if (!toomany)
            log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: message "
              "rejected: sender=<%s> %s", sender_address, host_and_ident(TRUE));
        else
          {
          rcpt_defer_count++;
-         smtp_printf("452 too many recipients\r\n", FALSE);
+         smtp_printf("452 too many recipients\r\n", SP_NO_MORE);
          if (!toomany)
            log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: excess "
              "temporarily rejected: sender=<%s> %s", sender_address,
        if (user_msg)
          smtp_user_msg(US"250", user_msg);
        else
-         smtp_printf("250 Accepted\r\n", FALSE);
+         smtp_printf("250 Accepted\r\n", SP_NO_MORE);
        rcpt_fail_count++;
        discarded = TRUE;
        log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: "
          {
          uschar *code = US"503";
          int len = Ustrlen(rcpt_smtp_response);
-         smtp_respond(code, 3, FALSE, US"All RCPT commands were rejected with "
+         smtp_respond(code, 3, SR_NOT_FINAL, US"All RCPT commands were rejected with "
            "this error:");
          /* Responses from smtp_printf() will have \r\n on the end */
          if (len > 2 && rcpt_smtp_response[len-2] == '\r')
            rcpt_smtp_response[len-2] = 0;
-         smtp_respond(code, 3, FALSE, rcpt_smtp_response);
+         smtp_respond(code, 3, SR_NOT_FINAL, rcpt_smtp_response);
          }
        if (f.smtp_in_pipelining_advertised && last_was_rcpt)
-         smtp_printf("503 Valid RCPT command must precede %s\r\n", FALSE,
+         smtp_printf("503 Valid RCPT command must precede %s\r\n", SP_NO_MORE,
            smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]]);
        else
          done = synprot_error(L_smtp_protocol_error, 503, NULL,
        {
        sender_address = NULL;  /* This will allow a new MAIL without RSET */
        sender_address_unrewritten = NULL;
-       smtp_printf("554 Too many recipients\r\n", FALSE);
+       smtp_printf("554 Too many recipients\r\n", SP_NO_MORE);
  
        if (chunking_state > CHUNKING_OFFERED)
          {
          smtp_user_msg(US"354", user_msg);
        else
          smtp_printf(
-           "354 Enter message, ending with \".\" on a line by itself\r\n", FALSE);
+           "354 Enter message, ending with \".\" on a line by itself\r\n", SP_NO_MORE);
        }
  
        if (f.bdat_readers_wanted)
        if (!(address = parse_extract_address(smtp_cmd_data, &errmess,
              &start, &end, &recipient_domain, FALSE)))
        {
-       smtp_printf("501 %s\r\n", FALSE, errmess);
+       smtp_printf("501 %s\r\n", SP_NO_MORE, errmess);
        break;
        }
  
            break;
          }
  
-       smtp_printf("%s\r\n", FALSE, s);
+       smtp_printf("%s\r\n", SP_NO_MORE, s);
        }
        break;
        }
  
        if (rc == DEFER)
        {
-       smtp_printf("454 TLS currently unavailable\r\n", FALSE);
+       smtp_printf("454 TLS currently unavailable\r\n", SP_NO_MORE);
        break;
        }
  
              log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s",
                log_msg);
          if (user_msg)
-           smtp_respond(US"221", 3, TRUE, user_msg);
+           smtp_respond(US"221", 3, SR_FINAL, user_msg);
          else
-           smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
+           smtp_printf("221 %s closing connection\r\n", SP_NO_MORE, smtp_active_hostname);
          log_close_event(US"by QUIT");
          done = 2;
          break;
  
        default:
-         smtp_printf("554 Security failure\r\n", FALSE);
+         smtp_printf("554 Security failure\r\n", SP_NO_MORE);
          break;
        }
        tls_close(NULL, TLS_SHUTDOWN_NOWAIT);
  
      case NOOP_CMD:
        HAD(SCH_NOOP);
-       smtp_printf("250 OK\r\n", FALSE);
+       smtp_printf("250 OK\r\n", SP_NO_MORE);
        break;
  
  
  
      case HELP_CMD:
        HAD(SCH_HELP);
-       smtp_printf("214-Commands supported:\r\n214", TRUE);
-       smtp_printf(" AUTH", TRUE);
+       smtp_printf("214-Commands supported:\r\n214", SP_MORE);
+       smtp_printf(" AUTH", SP_MORE);
  #ifndef DISABLE_TLS
        if (tls_in.active.sock < 0 &&
          verify_check_host(&tls_advertise_hosts) != FAIL)
-       smtp_printf(" STARTTLS", TRUE);
+       smtp_printf(" STARTTLS", SP_MORE);
  #endif
-       smtp_printf(" HELO EHLO MAIL RCPT DATA BDAT", TRUE);
-       smtp_printf(" NOOP QUIT RSET HELP", TRUE);
-       if (acl_smtp_etrn) smtp_printf(" ETRN", TRUE);
-       if (acl_smtp_expn) smtp_printf(" EXPN", TRUE);
-       if (acl_smtp_vrfy) smtp_printf(" VRFY", TRUE);
+       smtp_printf(" HELO EHLO MAIL RCPT DATA BDAT", SP_MORE);
+       smtp_printf(" NOOP QUIT RSET HELP", SP_MORE);
+       if (acl_smtp_etrn) smtp_printf(" ETRN", SP_MORE);
+       if (acl_smtp_expn) smtp_printf(" EXPN", SP_MORE);
+       if (acl_smtp_vrfy) smtp_printf(" VRFY", SP_MORE);
  #ifdef EXPERIMENTAL_XCLIENT
        if (proxy_session || verify_check_host(&hosts_xclient) != FAIL)
-       smtp_printf(" XCLIENT", TRUE);
+       smtp_printf(" XCLIENT", SP_MORE);
  #endif
-       smtp_printf("\r\n", FALSE);
+       smtp_printf("\r\n", SP_NO_MORE);
        break;
  
  
          {
          log_write(0, LOG_MAIN|LOG_PANIC, "failed to set up ETRN command: %s",
            error);
-         smtp_printf("458 Internal failure\r\n", FALSE);
+         smtp_printf("458 Internal failure\r\n", SP_NO_MORE);
          break;
          }
        }
          debug_printf("ETRN command is: %s\n", etrn_command);
          debug_printf("ETRN command execution skipped\n");
          }
-       if (user_msg == NULL) smtp_printf("250 OK\r\n", FALSE);
+       if (user_msg == NULL) smtp_printf("250 OK\r\n", SP_NO_MORE);
          else smtp_user_msg(US"250", user_msg);
        break;
        }
  
        if (smtp_etrn_serialize && !enq_start(etrn_serialize_key, 1))
        {
-       smtp_printf("458 Already processing %s\r\n", FALSE, smtp_cmd_data);
+       smtp_printf("458 Already processing %s\r\n", SP_NO_MORE, smtp_cmd_data);
        break;
        }
  
        {
        log_write(0, LOG_MAIN|LOG_PANIC, "fork of process for ETRN failed: %s",
          strerror(errno));
-       smtp_printf("458 Unable to fork process\r\n", FALSE);
+       smtp_printf("458 Unable to fork process\r\n", SP_NO_MORE);
        if (smtp_etrn_serialize) enq_end(etrn_serialize_key);
        }
        else
        if (!user_msg)
-         smtp_printf("250 OK\r\n", FALSE);
+         smtp_printf("250 OK\r\n", SP_NO_MORE);
        else
          smtp_user_msg(US"250", user_msg);
  
        done = synprot_error(L_smtp_syntax_error, 0, NULL,       /* Just logs */
        US"NUL character(s) present (shown as '?')");
        smtp_printf("501 NUL characters are not allowed in SMTP commands\r\n",
-                 FALSE);
+                 SP_NO_MORE);
        break;
  
  
  
  #ifdef SUPPORT_PROXY
      case PROXY_FAIL_IGNORE_CMD:
-       smtp_printf("503 Command refused, required Proxy negotiation failed\r\n", FALSE);
+       smtp_printf("503 Command refused, required Proxy negotiation failed\r\n", SP_NO_MORE);
        break;
  #endif
  
diff --combined src/src/tls-gnu.c
index efa6004a38d1b7af1b45530c1d82cd7abfd0ebee,afb59c33f6f5e53853b1f00c7a7f780a0710eabc..a17597e8bf3a68ab8eed83754bd364f0104f7fc9
@@@ -2,7 -2,7 +2,7 @@@
  *     Exim - an Internet mail transport agent    *
  *************************************************/
  
 -/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 +/* Copyright (c) The Exim Maintainers 2020 - 2023 */
  /* Copyright (c) University of Cambridge 1995 - 2018 */
  /* Copyright (c) Phil Pennock 2012 */
  /* See the file NOTICE for conditions of use and distribution. */
@@@ -3000,7 -3000,7 +3000,7 @@@ exim_gnutls_state_st * state = NULL
  if (tls_in.active.sock >= 0)
    {
    tls_error(US"STARTTLS received after TLS started", US "", NULL, errstr);
-   smtp_printf("554 Already in TLS\r\n", FALSE);
+   smtp_printf("554 Already in TLS\r\n", SP_NO_MORE);
    return FAIL;
    }
  
@@@ -3079,7 -3079,7 +3079,7 @@@ mode, the fflush() happens when smtp_ge
  
  if (!state->tlsp->on_connect)
    {
-   smtp_printf("220 TLS go ahead\r\n", FALSE);
+   smtp_printf("220 TLS go ahead\r\n", SP_NO_MORE);
    fflush(smtp_out);
    }
  
diff --combined src/src/tls-openssl.c
index b02605eae6bbb83334390f7a5fee1e337dd688cb,a5e782ef73d5296eddf4634416844a2823fedeec..ef11de593590b313eb581537693b64650085feff
@@@ -2,7 -2,7 +2,7 @@@
  *     Exim - an Internet mail transport agent    *
  *************************************************/
  
 -/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 +/* Copyright (c) The Exim Maintainers 2020 - 2023 */
  /* Copyright (c) University of Cambridge 1995 - 2019 */
  /* See the file NOTICE for conditions of use and distribution. */
  /* SPDX-License-Identifier: GPL-2.0-or-later */
@@@ -1438,7 -1438,7 +1438,7 @@@ SNI handling
  
  Separately we might try to replace using OCSP_basic_verify() - which seems to not
  be a public interface into the OpenSSL library (there's no manual entry) -
 -(in 3.0.0 + is is public)
 +(in 3.0.0 + it is public)
  But what with?  We also use OCSP_basic_verify in the client stapling callback.
  And there we NEED it; we must verify that status... unless the
  library does it for us anyway?  */
@@@ -3504,7 -3504,7 +3504,7 @@@ static uschar peerdn[256]
  if (tls_in.active.sock >= 0)
    {
    tls_error(US"STARTTLS received after TLS started", NULL, US"", errstr);
-   smtp_printf("554 Already in TLS\r\n", FALSE);
+   smtp_printf("554 Already in TLS\r\n", SP_NO_MORE);
    return FAIL;
    }
  
@@@ -3624,7 -3624,7 +3624,7 @@@ mode, the fflush() happens when smtp_ge
  SSL_set_session_id_context(ssl, sid_ctx, Ustrlen(sid_ctx));
  if (!tls_in.on_connect)
    {
-   smtp_printf("220 TLS go ahead\r\n", FALSE);
+   smtp_printf("220 TLS go ahead\r\n", SP_NO_MORE);
    fflush(smtp_out);
    }