+[revisionflag="changed"]
+It is possible, however, to change the default behaviour so that all successful
+redirections count as successful verifications, however many new addresses are
+generated. This is specified by the %success_on_redirect% verification option.
+For example:
+
+[revisionflag="changed"]
+ require verify = recipient/success_on_redirect/callout=10s
+
+[revisionflag="changed"]
+In this example, verification succeeds if a router generates a new address, and
+the callout does not occur, because no address was routed to a remote host.
+
+
+
+
+
+[[SECTverifyCSA]]
+Client SMTP authorization (CSA)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+[revisionflag="changed"]
+cindex:[CSA,verifying]
+Client SMTP Authorization is a system that allows a site to advertise
+which machines are and are not permitted to send email. This is done by placing
+special SRV records in the DNS; these are looked up using the client's HELO
+domain. At the time of writing, CSA is still an Internet Draft. Client SMTP
+Authorization checks in Exim are performed by the ACL condition:
+
+ verify = csa
+
+[revisionflag="changed"]
+This fails if the client is not authorized. If there is a DNS problem, or if no
+valid CSA SRV record is found, or if the client is authorized, the condition
+succeeds. These three cases can be distinguished using the expansion variable
+$csa_status$, which can take one of the values ``fail'', ``defer'',
+``unknown'', or ``ok''. The condition does not itself defer because that would
+be likely to cause problems for legitimate email.
+
+[revisionflag="changed"]
+The error messages produced by the CSA code include slightly more
+detail. If $csa_status$ is ``defer'', this may be because of problems
+looking up the CSA SRV record, or problems looking up the CSA target
+address record. There are four reasons for $csa_status$ being ``fail'':
+
+[revisionflag="changed"]
+- The client's host name is explicitly not authorized.
+
+[revisionflag="changed"]
+- The client's IP address does not match any of the CSA target IP addresses.
+
+[revisionflag="changed"]
+- The client's host name is authorized but it has no valid target IP addresses
+(for example, the target's addresses are IPv6 and the client is using IPv4).
+
+[revisionflag="changed"]
+- The client's host name has no CSA SRV record but a parent domain has asserted
+that all subdomains must be explicitly authorized.
+
+[revisionflag="changed"]
+The %csa% verification condition can take an argument which is the domain to
+use for the DNS query. The default is:
+
+ verify = csa/$sender_helo_name
+
+[revisionflag="changed"]
+This implementation includes an extension to CSA. If the query domain
+is an address literal such as [192.0.2.95], or if it is a bare IP
+address, Exim searches for CSA SRV records in the reverse DNS as if
+the HELO domain was (for example) '95.2.0.192.in-addr.arpa'. Therefore it is
+meaningful to say:
+
+ verify = csa/$sender_host_address
+
+[revisionflag="changed"]
+In fact, this is the check that Exim performs if the client does not say HELO.
+This extension can be turned off by setting the main configuration option
+%dns_csa_use_reverse% to be false.
+
+[revisionflag="changed"]
+If a CSA SRV record is not found for the domain itself, a search
+is performed through its parent domains for a record which might be
+making assertions about subdomains. The maximum depth of this search is limited
+using the main configuration option %dns_csa_search_limit%, which is 5 by
+default. Exim does not look for CSA SRV records in a top level domain, so the
+default settings handle HELO domains as long as seven
+('hostname.five.four.three.two.one.com'). This encompasses the vast majority of
+legitimate HELO domains.
+
+[revisionflag="changed"]
+The 'dnsdb' lookup also has support for CSA. Although 'dnsdb' also supports
+direct SRV lookups, this is not sufficient because of the extra parent domain
+search behaviour of CSA, and (as with PTR lookups) 'dnsdb' also turns IP
+addresses into lookups in the reverse DNS space. The result of a successful
+lookup such as:
+
+[revisionflag="changed"]
+....
+${lookup dnsdb {csa=$sender_helo_name}}
+....
+
+[revisionflag="changed"]
+has two space-separated fields: an authorization code and a target host name.
+The authorization code can be ``Y'' for yes, ``N'' for no, ``X'' for explicit
+authorization required but absent, or ``?'' for unknown.
+
+
+
+
+[[SECTverifyPRVS]]
+Bounce address tag validation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+[revisionflag="changed"]
+cindex:[BATV,verifying]
+Bounce address tag validation (BATV) is a scheme whereby the envelope senders
+of outgoing messages have a cryptographic, timestamped ``tag'' added to them.
+Genuine incoming bounce messages should therefore always be addressed to
+recipients that have a valid tag. This scheme is a way of detecting unwanted
+bounce messages caused by sender address forgeries (often called ``collateral
+spam''), because the recipients of such messages will not include valid tags.
+
+[revisionflag="changed"]
+There are two expansion items to help with the implementation of the BATV
+``prvs'' (private signature) scheme in an Exim configuration. This scheme signs
+the original envelope sender address by using a simple shared key to add a hash
+of the address and some time-based randomizing information. The %prvs%
+expansion item creates a signed address, and the %prvscheck% expansion item
+checks one. The syntax of these expansion items is described in section
+<<SECTexpansionitems>>.
+
+[revisionflag="changed"]
+As an example, suppose the secret per-address keys are stored in an MySQL
+database. A query to look up the key for an address could be defined as a macro
+like this:
+
+[revisionflag="changed"]
+....
+PRVSCHECK_SQL = ${lookup mysql{SELECT secret FROM batv_prvs \
+ WHERE sender='${quote_mysql:$prvscheck_address}'\
+ }{$value}}
+....
+
+[revisionflag="changed"]
+Suppose also that the senders who make use of BATV are defined by an address
+list called %batv_senders%. Then, in the ACL for RCPT commands, you could
+use this:
+
+[revisionflag="changed"]
+....
+# Bounces: drop unsigned addresses for BATV senders
+deny message = This address does not send an unsigned reverse path.
+ senders = :
+ recipients = +batv_senders
+
+# Bounces: In case of prvs-signed address, check signature.
+deny message = Invalid reverse path signature.
+ senders = :
+ condition = ${prvscheck {$local_part@$domain}\
+ {PRVSCHECK_SQL}{1}}
+ !condition = $prvscheck_result
+....
+
+[revisionflag="changed"]
+The first statement rejects recipients for bounce messages that are addressed
+to plain BATV sender addresses, because it is known that BATV senders do not
+send out messages with plain sender addresses. The second statement rejects
+recipients that are prvs-signed, but with invalid signatures (either because
+the key is wrong, or the signature has timed out).
+
+[revisionflag="changed"]
+A non-prvs-signed address is not rejected by the second statement, because the
+%prvscheck% expansion yields an empty string if its first argument is not a
+prvs-signed address, thus causing the %condition% condition to be false. If the
+first argument is a syntactically valid prvs-signed address, the yield is the
+third string (in this case ``1''), whether or not the cryptographic and timeout
+checks succeed. The $prvscheck_result$ variable contains the result of the
+checks (empty for failure, ``1'' for success).
+
+[revisionflag="changed"]
+Of course, when you accept a prvs-signed address, you have to ensure that the
+routers accept it and deliver it correctly. The easiest way to handle this is
+to use a ^redirect^ router to remove the signature with a configuration along
+these lines:
+
+[revisionflag="changed"]
+....
+batv_redirect:
+ driver = redirect
+ data = ${prvscheck {$local_part@$domain}{PRVSCHECK_SQL}}
+....
+
+[revisionflag="changed"]
+This works because, if the third argument of %prvscheck% is empty, the result
+of the expansion of a prvs-signed address is the decoded value of the original
+address. This router should probably be the first of your routers that handles
+local addresses.
+
+[revisionflag="changed"]
+To create BATV-signed addresses in the first place, a transport of this form
+can be used:
+
+[revisionflag="changed"]
+....
+external_smtp_batv:
+ driver = smtp
+ return_path = ${prvs {$return_path} \
+ {${lookup mysql{SELECT \
+ secret FROM batv_prvs WHERE \
+ sender='${quote_mysql:$sender_address}'} \
+ {$value}fail}}}
+....
+
+[revisionflag="changed"]
+If no key can be found for the existing return path, no signing takes place.
+
+