]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.0.0-20021222
authorWietse Venema <wietse@porcupine.org>
Sun, 22 Dec 2002 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:28:37 +0000 (06:28 +0000)
122 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/Makefile.in
postfix/README_FILES/SENDER_VERIFICATION_README [new file with mode: 0644]
postfix/RELEASE_NOTES
postfix/RELEASE_NOTES-1.1 [new file with mode: 0644]
postfix/RELEASE_NOTES-2.0 [new file with mode: 0644]
postfix/conf/main.cf
postfix/conf/master.cf
postfix/conf/post-install
postfix/conf/postfix-files
postfix/conf/postfix-script
postfix/conf/sample-smtpd.cf
postfix/conf/sample-verify.cf [new file with mode: 0644]
postfix/html/Makefile.in
postfix/html/backstage.html
postfix/html/bounce.8.html
postfix/html/postsuper.1.html
postfix/html/sendmail.1.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/html/trace.8.html [new symlink]
postfix/html/uce.html
postfix/html/verify.8.html [new file with mode: 0644]
postfix/man/Makefile.in
postfix/man/man1/postsuper.1
postfix/man/man1/sendmail.1
postfix/man/man8/bounce.8
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/man/man8/trace.8 [new file with mode: 0644]
postfix/man/man8/verify.8 [new file with mode: 0644]
postfix/proto/Makefile.in
postfix/src/bounce/Makefile.in
postfix/src/bounce/bounce.c
postfix/src/bounce/bounce_append_service.c
postfix/src/bounce/bounce_notify_service.c
postfix/src/bounce/bounce_notify_util.c
postfix/src/bounce/bounce_notify_verp.c
postfix/src/bounce/bounce_one_service.c
postfix/src/bounce/bounce_service.h
postfix/src/bounce/bounce_trace_service.c [new file with mode: 0644]
postfix/src/bounce/bounce_warn_service.c [new file with mode: 0644]
postfix/src/cleanup/Makefile.in
postfix/src/error/error.c
postfix/src/global/Makefile.in
postfix/src/global/bounce.c
postfix/src/global/bounce.h
postfix/src/global/bounce_log.c
postfix/src/global/bounce_log.h
postfix/src/global/defer.c
postfix/src/global/defer.h
postfix/src/global/deliver_request.h
postfix/src/global/log_adhoc.c [new file with mode: 0644]
postfix/src/global/log_adhoc.h [new file with mode: 0644]
postfix/src/global/mail_params.c
postfix/src/global/mail_params.h
postfix/src/global/mail_proto.h
postfix/src/global/mail_queue.h
postfix/src/global/mail_version.h
postfix/src/global/post_mail.c
postfix/src/global/post_mail.h
postfix/src/global/sent.c
postfix/src/global/sent.h
postfix/src/global/trace.c [new file with mode: 0644]
postfix/src/global/trace.h [new file with mode: 0644]
postfix/src/global/verify.c [new file with mode: 0644]
postfix/src/global/verify.h [new file with mode: 0644]
postfix/src/global/verify_clnt.c [new file with mode: 0644]
postfix/src/global/verify_clnt.h [new file with mode: 0644]
postfix/src/lmtp/lmtp_chat.c
postfix/src/lmtp/lmtp_proto.c
postfix/src/lmtp/lmtp_trouble.c
postfix/src/local/Makefile.in
postfix/src/local/alias.c
postfix/src/local/command.c
postfix/src/local/dotforward.c
postfix/src/local/file.c
postfix/src/local/forward.c
postfix/src/local/include.c
postfix/src/local/indirect.c
postfix/src/local/local.c
postfix/src/local/local.h
postfix/src/local/mailbox.c
postfix/src/local/maildir.c
postfix/src/local/recipient.c
postfix/src/local/resolve.c
postfix/src/local/token.c
postfix/src/local/unknown.c
postfix/src/nqmgr/Makefile.in
postfix/src/nqmgr/qmgr.h
postfix/src/nqmgr/qmgr_active.c
postfix/src/nqmgr/qmgr_deliver.c
postfix/src/nqmgr/qmgr_message.c
postfix/src/pickup/pickup.c
postfix/src/pipe/pipe.c
postfix/src/postsuper/postsuper.c
postfix/src/qmgr/Makefile.in
postfix/src/qmgr/qmgr.h
postfix/src/qmgr/qmgr_active.c
postfix/src/qmgr/qmgr_deliver.c
postfix/src/qmgr/qmgr_message.c
postfix/src/sendmail/Makefile.in
postfix/src/sendmail/sendmail.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_chat.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_trouble.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_chat.c
postfix/src/smtpd/smtpd_check.c
postfix/src/trivial-rewrite/resolve.c
postfix/src/trivial-rewrite/transport.c
postfix/src/verify/.indent.pro [new symlink]
postfix/src/verify/Makefile.in [new file with mode: 0644]
postfix/src/verify/verify.c [new file with mode: 0644]
postfix/src/virtual/Makefile.in
postfix/src/virtual/mailbox.c
postfix/src/virtual/maildir.c
postfix/src/virtual/unknown.c
postfix/src/virtual/virtual.h

index e66ba4755d6bdebeddb0e02f0104ba4a6e6c5793..16ca497d1ef6f3fe22df2848fe45f408b44988c9 100644 (file)
 -TPIPE_ATTR
 -TPIPE_PARAMS
 -TPLMYSQL
+-TPOST_MAIL_STATE
 -TQMGR_ENTRY
 -TQMGR_JOB
 -TQMGR_MESSAGE
index ab10336ee6a9a2906a4f2a8dd13922b7758ac2a8..900f0a54fd2d5bf10011446426f588a0394cce98 100644 (file)
@@ -7226,15 +7226,81 @@ Apologies for any names omitted.
        code had grown into a monster and needed to be replaced.
        trivial-rewrite/transport.c.
 
+20021115
+
+       Start implementing recipient verification. For now this is
+       done by adding trace flags to queue files. In case of a
+       verification request, a delivery agent does not deliver,
+       deliver, it just records what would happen.
+
+       This required instrumenting the bounce/defer/sent logging
+       routines to send their data to the right place depending
+       on the type of delivery request.
+
+20021116
+
+       New trace service. This is used for reporting if a recipient
+       is deliverable (sendmail -bv) and for producing a record
+       of delivery attempts (sendmail -v). The report is sent via
+       email, using the bounce daemon. Files: global/trace.[hc].
+
+       This required replacing the bounce/defer logfile format by
+       an extensible name=value format. Files: global/bounce_log.c,
+       bounce/bounce_append_service.c.
+
+20021117
+
+       New address verification service with simple expiration
+       and refresh policy. Storage can be in-core or in permanent
+       table. The daemon is appropriately called "verify". Files:
+       global/verify_clnt.[hc], verify/verify.c.
+
+20021118
+
+       Cleaning up the code for tracing and verification. Files:
+       global/{log_adhoc,bounce,defer,trace,verify}.[hc].
+
+20021119
+
+       New address_verification_negative_cache = yes/no parameter
+       controls whether Postfix stores the result of negatieve
+       address verification probes. This reduces cache pollution
+       but causes Postfix to send a probe for each address
+       verification service query. File: verify/verify.c.
+
+       Added optimistic caching to the verify daemon, so that one
+       failed probe will not clobber a known to be good address.
+       As long as some probes succeeed, a good address will stay
+       cached as OK.
+
+       Cleaning up of the bounce daemon's code for bounce, delayed
+       mail warning and trace notification.  Files: bounce/*.[hc],
+       global/bounce_log.c.
+
+20021120
+
+       Changed the probe's sender address to "postmaster" so that
+       we get better information about the address we're testing.
+       File: verify/verify.c.
+
+       Added some paranoia to the routine that reads data from
+       the address verification cache. Ignore data that is obviously
+       bogus. File: verify/verify.c.
+
 20021121
 
        Bugfix: garbage in "user@garbage"@domain address forms may
        cause the SMTP or LMTP client to terminate with a fatal
        error exit because garbage/tcp is not an existing service.
        This cannot be abused to cause the SMTP or LMTP client to
-       send data into unauthorized ports.  Files:  *qmgr/qmgr_message.c,
+       send data into unauthorized ports.  Files: *qmgr/qmgr_message.c,
        trivial-rewrite/resolve.c.
 
+20021124
+
+       Bugfix: don't use same VSTRING buffer for reading and writing.
+       File: verify/verify.c.
+
 20021128
 
        Feature: hashed hold queue support, with hashing turned on
@@ -7251,6 +7317,15 @@ Apologies for any names omitted.
        SMTP clients. Files: smtp/smtp_connect.c, lmtp/lmtp_connect.c,
        util/host_port.[hc].
 
+20021130
+
+       Cleanup: defer mail when recipient verification takes too
+       long. File: smtpd/smtpd_proto.c.
+
+       Feature: new reject_multi_recipient_bounce restriction, to
+       reject "MAIL FROM: <>" with multiple recipients.  File:
+       smtpd/smtpd_check.c.
+
 20021201
 
        Compatibility: ignore the new Sendmail -A option. File:
@@ -7276,6 +7351,12 @@ Apologies for any names omitted.
        not prepend X-Original-To: addresses to maildir files.
        Omission spotted by Matthias Andree.
 
+       Specify "address_verify_sender=" or "address_verify_sender=<>"
+       to use a null sender address while doing address verification
+       probes.  Beware, doing so may trigger false negatives
+       because some sites reject mail from the null sender, even
+       though this is required by RFC standards.
+
        Bugfix: too many levels of dereferencing while testing for
        missing reject_rbl_mumble domain names. Patrik Rak.  File:
        smtpd/smtpd_check.c.
@@ -7382,11 +7463,22 @@ Apologies for any names omitted.
        suddenly lose all their mail because local_recipient_maps
        is now turned on by default.
 
+20021210
+
+       Feature: recipient address verification, using the code
+       that already implements sender address verification.  Based
+       on suggestion by Matthias Andree.  Files: src/smtpd/smtpd.c,
+       src/smtpd/smtpd_check.c.
+
 20021211
 
        Performance: doubled the default process limit (50->100)
        and default queue manager active queue message/recipient
-       limits (10k->20k).  File: global/mail_params.h.
+       limits  (10k->20k).  File:  global/mail_params.h.
+
+       Bugfix: the change that begot us multiple trivial-rewrite
+       processes (good) also gave us multiple verify daemons (bad).
+       File: conf/post-install.
 
 20021212
 
@@ -7395,6 +7487,9 @@ Apologies for any names omitted.
        and do transport map lookups before relocated map lookups.
        Files:  trivial-rewrite/resolve.c, trivial-rewrite/transport.c.
 
+       Shortened the verify server's negative cache refresh time
+       from 12 hours to 2 hours. File:  global/mail_params.h.
+
        Admin friendliness: the SMTP server now reports "User
        unknown in {local recipient | virtual alias | virtual
        mailbox | relay recipient} table". This will make trouble
@@ -7425,6 +7520,10 @@ Apologies for any names omitted.
        error transport without updating the nexthop information.
        File:  trivial-rewrite/resolve.c.
 
+       Robustness: don't probe the sender address when probed for
+       our own address verification probe sender address. File:
+       smtpd/smtpd_check.c.
+
        Performance: don't do UCE checks (which may result in 4xx
        SMTP reply codes, and thus, repeated delivery attempts)
        when we already know that the recipient does not exist.
@@ -7479,6 +7578,12 @@ Apologies for any names omitted.
        site already ran Postfix with local_recipient_maps enabled.
        Files:  smtpd/smtpd.c, smtpd/smtpd_check.c, conf/post-install.
 
+20021218
+
+       Feature: specify unverified_recipient_reject_code=250 or
+       unverified_sender_reject_code=250 to accept mail for an
+       address that is known to bounce. File: smtpd/smtpd_check.c.
+
 20021219
 
        Bugfix: longjmp() while sending "go away" without setjmp()
@@ -7511,6 +7616,12 @@ Apologies for any names omitted.
        shooting easier but also reveals information that is nobody
        elses business.
 
+20021221
+
+       Workaround: don't allow the transport map to override the
+       virtual alias class (error:User unknown) result.  File:
+       trivial-rewrite/transport.c.
+
 Open problems:
 
        Low: after successful delivery, per-queue window += 1/window,
index 7395b3a253b2b0e05e27a7327bcc61e5bd0c89e5..882c8206f54b804209a8fe37df534d5ba6fa8c0e 100644 (file)
@@ -6,7 +6,8 @@ DIRS    = src/util src/global src/dns src/master src/postfix src/smtpstone \
        src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \
        src/showq src/postalias src/postcat src/postconf src/postdrop \
        src/postkick src/postlock src/postlog src/postmap src/postqueue \
-       src/postsuper src/nqmgr src/qmqpd src/spawn src/flush src/virtual
+       src/postsuper src/nqmgr src/qmqpd src/spawn src/flush src/verify \
+       src/virtual
 MANDIRS        = proto man html
 
 default: update
diff --git a/postfix/README_FILES/SENDER_VERIFICATION_README b/postfix/README_FILES/SENDER_VERIFICATION_README
new file mode 100644 (file)
index 0000000..c1454f7
--- /dev/null
@@ -0,0 +1,109 @@
+Sender address verification
+===========================
+
+Sender address verification blocks mail from an unknown sender
+address until after the address is verified.  An address is verified
+by probing the nearest MTA for that address, without actually
+delivering mail to it (SMTP interruptus). Probe messages are like
+normail mail, but are discarded instead of being deferred or bounced.
+
+Normal mail will suffer only a short one-time delay of up to 9
+seconds while address verification happens for the first time.
+When verification takes longer than 9 seconds, the Postfix SMTP
+server defers the message with a 450 reply. Normal mail clients
+will connect again after some delay.  Once an address status is
+known, the status is cached and Postfix replies immediately.
+
+Address verification is turned on with the "reject_unverified_sender"
+sender restriction.  To find out how this would affect your mail,
+specify "warn_if_reject reject_unverified_sender" so that you can
+see what mail would be blocked:
+
+    smtpd_sender_restrictions = 
+       ... 
+       check_sender_access hash:/etc/postfix/sender_access
+       reject_unknown_sender_domain
+       warn_if_reject reject_unverified_sender 
+       ...
+
+This is also a good way to populate your cache with address
+verification results before you start to actually reject mail.
+
+The sender_access restriction is needed to whitelist domains that
+are known to be OK. See the section titled "Limitations" at the
+end of this document.
+
+The "reject_unknown_sender_domain" restriction blocks mail from
+non-existent domains. Putting this before "reject_unverified_sender"
+avoids the overhead of generating unnecessary probe messages.
+
+The unverified_sender_reject_code parameter (default 450) specifies
+how Postfix replies when a sender address is known to bounce.
+Change this setting into 550 when you trust Postfix's judgments.
+
+Caching
+=======
+
+NOTE: By default, address verification information is not stored
+in a persistent file. You have to specify one in main.cf (see
+below). Persistent storage is off by default because it may need
+more disk space than is available in your root file system.
+
+Address verification information is cached by the Postfix verify
+daemon.  Postfix has a bunch of parameters that control the caching
+of positive and negative results. Refer to the verify(8) manual
+page or the sample-verify.cf file for details.
+
+The address_verify_map (NOTE: singular) configuration parameter
+specifies an optional persistent database for sender address
+verification results.  If you don't specify a file, all address
+verification information is lost after "postfix reload" or "postfix
+stop".
+
+If your root file system has sufficient space, try:
+
+    address_verify_map = btree:/etc/postfix/verify
+
+NOTE: Do not put this file in a file system that fills up. When
+the address verification table gets corrupted the world comes to
+an end and YOU will have to MANUALLY fix things as described in
+the next section. Meanwhile you will not receive mail via SMTP.
+
+The verify daemon process will create a new database when none
+exists, and will open/create the file before it enters the chroot
+jail or before it drops root privileges.
+
+Managing the address verification database
+==========================================
+
+Right now, no tools are provided to manage the address verification
+database. If the file gets too big, or if it gets corrupted, you
+can manually delete the file and run "postfix reload".  The new
+verify daemon process will then create a new, empty, database.
+
+Limitations
+===========
+
+Postfix probes the nearest MTA for the sender domain without actually
+sending mail. If that MTA accepts the recipient, then Postfix
+assumes that the address is deliverable, even when the address will
+bounce AFTER that MTA accepts it.
+
+You will probably want to put a whitelist before the address
+verification restriction, so that you can exclude known to be OK
+domains or addresses from verification. Although Postfix will not
+mark a known-to-be-good address as bad after a probe fails, it is
+better to be safe than sorry.
+
+    smtpd_sender_restrictions =
+       ...
+       check_sender_access hash:/etc/postfix/sender_access
+       reject_unknown_sender_domain
+       reject_unverified_sender
+       ...
+
+NOTE: You will have to whitelist sites such as securityfocus.com
+and other sites that operate mailing lists that use a different
+sender address for each posting (VERP).  Such addresses pollute
+the address verification cache quickly, and generate unnecessary
+sender verification probes.
index e9f8e9f937ea88a801840d8a19f28146aaa2d8e1..5ab2ba5e20c5b08f1cc604c7171e7c2bd36772e2 100644 (file)
@@ -1,3 +1,13 @@
+===============================================================
+WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+===============================================================
+The sender/recipient address verification code is lightly documented
+and has been tested lightly. The code is proof-of-concept quality
+and must not be used on high-volume sites.  Use at your own risk.
+===============================================================
+WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+===============================================================
+
 In the text below, incompatible changes are labeled with the Postfix
 snapshot that introduced the change. If you upgrade from a later
 Postfix version, then you do not have to worry about that particular
@@ -12,1795 +22,57 @@ snapshot release).  Patches change the patchlevel and the release
 date. Snapshots change only the release date, unless they include
 the same bugfixes as a patch release.
 
-Incompatible changes with Postfix snapshot 1.1.12-20021219
-==========================================================
-
-The use of the XVERP extension in the SMTP MAIL FROM command is
-now limited to SMTP clients that match the hostnames, domains or
-networks listed with the authorized_verp_clients parameter (default:
-$mynetworks).
-
-Incompatible changes with Postfix snapshot 1.1.12-20021209
-==========================================================
-
-This release adds a new "relay" service to the Postfix master.cf
-file.  If your Postfix is unable to connect to the "relay" service
-then you have not properly followed the installation procedure.
-
-The Postfix SMTP server now rejects mail for $mydestination domain
-recipients that it does not know about. This keeps undeliverable
-mail out of your queue.
-
-To avoid losing mail when upgrading from Postfix 1.1, you need to
-review the LOCAL_RECIPIENT_README file if one of the following is
-true:
-
-- You define $mydestination domain recipients in files other than
-  /etc/passwd or /etc/aliases.  For example, you define $mydestination
-  domain recipients in the $virtual_mailbox_maps files.
-- You run the Postfix SMTP server chrooted (see master.cf).
-- You redefined the local delivery agent in master.cf.
-- You redefined the "local_transport" setting in main.cf.
-- You use the mailbox_transport feature of the Postfix local delivery agent.
-- You use the fallback_transport feature of the Postfix local delivery agent.
-- You use the luser_relay feature of the Postfix local delivery agent.
-
-Postfix no longer defaults to the "smtp" transport for all non-local
-destinations. This may affect your defer_transports settings. In
-particular, Postfix now uses the "relay" mail delivery transport
-for delivery to domains matching $relay_domains.  The old "smtp"
-transport is now the default mail delivery transport for non-local
-domains that do not match relay_domains.
-
-The "virtual_maps" configuration parameter is now called
-"virtual_alias_maps", for consistency with "virtual_mailbox_maps".
-Default settings are backwards compatible with Postfix 1.1.
-
-Postfix-style virtual domains are now called virtual alias domains.
-Sendmail-style virtual domains are no longer documented.  This part
-of Postfix was too confusing.
-
-The default queue directory hash_queue_depth setting is reduced to
-1 level of subdirectories per Postfix queue. This improves "mailq"
-performance on most systems, but can result in poorer worst-case
-performance on systems with lots of mail in the queue.
-
-The "reject_maps_rbl" restriction is going away. The SMTP server
-logs a warning and suggests using the more flexible "reject_rbl_client"
-instead.
-
-The "check_relay_domains" restriction is going away. The SMTP server
-logs a warning and suggests using "reject_unauth_destination"
-instead.
-
-The Postfix SMTP client no longer expands CNAMEs in MAIL FROM or
-RCPT TO addresses (as permitted by RFC 2821).
-
-The Postfix installation procedure no longer sets the "chattr +S"
-bit on Linux queue directories. Wietse has gotten too annoyed with
-naive reviewers who complain about performance without having a
-clue of what they are comparing.
-
-Major changes with Postfix snapshot 1.1.12-20021209
-===================================================
-
-This release introduces separation of lookup tables for addresses
-and for domain names of virtual domains.
-
-- virtual_maps is replaced by virtual_alias_maps (for address
-  lookups) and virtual_alias_domains (for the names of what were
-  formerly called "Postfix-style virtual domains").
-
-  For backwards compatibility with Postfix version 1.1, the new
-  virtual_alias_maps parameter defaults to $virtual_maps, and the
-  new virtual_alias_domains parameter defaults to $virtual_alias_maps.
-
-- virtual_mailbox_maps now has a companion parameter called
-  virtual_mailbox_domains (for the names of domains served by the
-  virtual delivery agent). virtual_mailbox_maps is now used for
-  address lookups only.
-
-  For backwards compatibility with Postfix version 1.1,, the new
-  virtual_mailbox_domains parameter defaults to $virtual_mailbox_maps.
-
-This release introduces the concept of address domain classes, each
-having its own default mail delivery transport:
-
-  Destination matches      Default transport       Default name
-  --------------------------------------------------------------
-  $mydestination or
-     $inet_interfaces      $local_transport        local
-  $virtual_alias_domains   (not applicable)        (not applicable)
-  $virtual_mailbox_domains $virtual_transport      virtual
-  $relay_domains           $relay_transport        relay
-  other                    $default_transport      smtp
-
-The benefits of these changes are:
-
-- You no longer need to specify all the virtual(8) domains in the
-  Postfix transport map. The virtual(8) delivery agent has
-  become a first-class citizen just like local(8) or smtp(8).
-
-- On mail gateway systems, separation of inbound mail relay traffic
-  from outbound traffic. This eliminates a problem where inbound
-  mail deliveries could become resource starved in the presence of
-  a high volume of outbound mail.
-
-- The SMTP server rejects unknown recipients in a more consistent
-  manner than was possible with previous Postfix versions.
-
-See the ADDRESS_CLASS_README file for a description of address
-classes, their benefits, and their incompatibilities.
-
-Finally, regular expression maps are now allowed with local delivery
-agent alias tables and with all virtual delivery agent lookup tables.
-However, regular expression substitution of $1 etc. is still
-forbidden for security reasons.
-
-Incompatible changes with Postfix snapshot 1.1.11-20021108
-==========================================================
-
-The behavior of the SMTP server's defer_if_permit flag has changed,
-in order to maximize the opportunity to permanently reject mail
-without opening opportunities for losing legitimate mail.
-
-The flag is still set when an UCE reject restriction fails due to
-a temporary (DNS) problem, to prevent unwanted mail from slipping
-through. However, the flag is no longer tested at the end of client,
-helo or sender restrictions. Instead, the flag is now tested at
-the end of the ETRN and recipient restrictions only.
-
-The behavior of the warn_if_reject restriction has changed.  It no
-longer activates any pending defer_if_permit or defer_if_reject
-decisions (the defer_if_reject flag is set when some UCE permit
-restriction fails due to a temporary (DNS) problem, to avoid loss
-of legitimate mail).
-
-Instead of setting the defer_if_permit flag, a failing reject
-restriction after warn_if_reject now merely logs that it would have
-caused mail to be deferred.
-
-A failing permit restriction after warn_if_reject still raises the
-defer_if_reject flag, to avoid loss of legitimate mail.
-
-Incompatible changes with Postfix snapshot 1.1.11-20021028
-==========================================================
-
-Logfile formats have changed. This may affect logfile processing
-software. The queue file format is still compatible with Postfix
-version 1.1 (stable release).
-
-- The Postfix SMTP server UCE reject etc. logging now includes the
-queue ID, the mail protocol (SMTP or ESMTP), and the hostname that
-was received with the HELO or EHLO command, if available.
-
-- The Postfix header/body_checks logging now includes the mail
-protocol (SMTP, ESMTP, QMQP) and the hostname that was received
-with the SMTP HELO or EHLO command, if available.
-
-The Postfix status=sent/bounced/deferred logging now shows the
-original recipient address (as received before any address rewriting
-or aliasing).  The original recipient address is logged only when
-it differs from the final recipient address.
-
-Major changes with Postfix snapshot 1.1.11-20021028
-===================================================
-
-Postfix logs more information, as described in the "incompatibilities"
-section above.
-
-The local(8) and virtual(8) delivery agents now record the original
-recipient address in the X-Original-To: message header. This header
-can also be emitted by the pipe(8) delivery agent.
-
-Major changes with Postfix snapshot 1.1.11-20021024
-===================================================
-
-New proxy_interfaces parameter, for sites behind a network address
-translation gateway or other type of proxy. Specify all the proxy
-network addresses here, to avoid avoid mail delivery loops.
-
-Incompatible changes with Postfix snapshot 1.1.11-20021015
-==========================================================
-
-The Postfix LMTP client no longer lowercases email addresses in
-MAIL FROM and RCPT TO commands.
-
-Incompatible changes with Postfix snapshot 1.1.11-20021013
-==========================================================
-
-The default Linux kernel lock style for mailbox delivery is changed
-from flock() to fcntl(). This has no impact if your system uses
-procmail for local delivery, if you use maildir-style mailboxes,
-or when mailbox access software locks mailboxes with username.lock
-files (which is usually the case with non-maildir mailboxes).
-
-Major changes with Postfix snapshot 1.1.11-20021013
-===================================================
-
-The body_checks_max_size parameter limits the amount of text per
-message body segment (or attachment, if you prefer to use that
-term) that is subjected to body_checks inspection.  The default
-limit is 50 kbytes. This speeds up the processing of mail with
-large attachments.
-
-Updated MacOS X support by Gerben Wierda. See the auxiliary/MacOSX
-directory.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020923
-==========================================================
-
-Subtle change in ${name?result} macro expansions:  the expansion
-no longer happens when $name is an empty string. This probably
-makes more sense than the old behavior.
-
-The default RBL "reject" server reply now includes an indication
-of *what* is being rejected: Client host, Helo command, Sender
-address, or Recipient address.
-
-Major changes with Postfix snapshot 1.1.11-20020923
-===================================================
-
-Complete rewrite of the RBL blacklisting code. The names of RBL
-restrictions are now based on a suggestion that was made by Liviu
-Daia in October 2001. See conf/sample-smtpd.cf or html/uce.html
-for details.
-
-Feature: "reject_rbl_client rbl.domain.tld" for client IP address
-blacklisting. Based on code by LaMont Jones.  The old "reject_maps_rbl"
-is now implemented as a wrapper around the reject_rbl_client code.
-
-Feature: "reject_rhsbl_sender rbl.domain.tld" for sender domain
-blacklisting. Also: reject_rhsbl_client and reject_rhsbl_recipient
-for client and recipient domain blacklisting.
-
-"rbl_reply_maps" configuration parameter for lookup tables with
-template responses per RBL server. Based on code by LaMont Jones.
-If no reply template is found the default template is used as
-specified with the default_rbl_reply configuration parameter.  The
-template responses support $name expansion of client, helo, sender,
-recipient and RBL related attributes.
-
-"smtpd_expansion_filter" configuration parameter to control what
-characters are allowed in the expansion of template reply $name
-macros. Characters outside the allowed set are replaced by "_".
-
-Incompatible changes with Postfix snapshot 1.1.11-20020917
-==========================================================
-
-The relayhost setting now behaves as documented, i.e. you can no
-longer specify multiple destinations.
-
-In regexp lookup tables, the form /pattern1/!/pattern2/ is going
-away. Use the cleaner and more flexible "if !/pattern2/..endif"
-form.  The old form still exists but is no longer documented.
-
-Major changes with Postfix snapshot 1.1.11-20020917
-===================================================
-
-Speedups of regexp table lookups by optimizing for the $number
-substitutions that are actually present in the right-hand side.
-Based on a suggestion by Liviu Daia.
-
-Speedups of regexp and pcre tables, using IF..ENDIF support. Based
-on an idea by Bert Driehuis.  To protect a block of patterns, use:
-
-    if /pattern1/
-    /pattern2/ result2
-    /pattern3/ result3
-    endif
-
-IF..ENDIF can nest. Don't specify blanks at the beginning of lines
-inside IF..ENDIF, because lines beginning with whitespace are
-appended to the previous line. More details about the syntax are
-given in the pcre_table(5) and regexp_table(5) manual pages.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020906
-==========================================================
-
-The permit_mx_backup restriction is made more strict. With older
-versions, some DNS failures would cause mail to be accepted anyway,
-and some DNS failures would cause mail to be rejected by later
-restrictions in the same restriction list.  The improved version
-will defer delivery when Postfix could make the wrong decision.
-
-Major changes with Postfix snapshot 1.1.11-20020906
-===================================================
-
-More sophisticated handling of UCE-related DNS lookup errors.
-These cause Postfix to not give up so easily, so that some deliveries
-will not have to be deferred after all.  This affects the following
-restrictions:
-
-- After DNS lookup failure, permit_mx_backup will now accept the
-request if a subsequent restriction would cause the request to be
-accepted anyway, and will defer the request if a subsequent
-restriction would cause the request to be rejected.
-
-- After DNS lookup failure, reject_unknown_hostname (the hostname
-given in HELO/EHLO commands) reject_unknown_sender_domain and
-reject_unknown_recipient_domain will now reject the request if a
-subsequent restriction would cause the request to be rejected
-anyway, and will defer the request if a subsequent restriction
-would cause the request to be accepted.
-
-Specify "smtpd_data_restrictions = reject_unauth_pipelining" to
-block mail from SMTP clients that send message content before
-Postfix has replied to the SMTP DATA command.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020819
-==========================================================
-
-The qmgr_site_hog_factor feature is gone (this would defer mail
-delivery for sites that occupy too much space in the active queue,
-and be a real performance drain due to excessive disk I/O).  The
-new qmgr_clog_warn_time feature (see below) provides more useful
-suggestions for dealing with Postfix congestion.
-
-LDAP API version 1 is no longer supported. The memory allocation
-and deallocation strategy has changed too much to maintain both
-version 1 and 2 at the same time.
-
-In mailq output, the queue ID is followed by the ! character when
-the message is in the "hold" queue (see below). This may break
-programs that process mailq output.
-
-The "permit_naked_ip_address" restriction on HELO command syntax
-is unsafe when used with most smtpd_XXX_restrictions, and will go
-away. The user is now requested to use "permit_mynetworks" instead.
-
-The smtpd_sasl_local_domain setting now defaults to the null string,
-rather than $myhostname. This seems to work better with Cyrus SASL
-version 2. This change may cause incompatibility with the saslpasswd2
-command.
-
-Major changes with Postfix snapshot 1.1.11-20020819
-===================================================
-
-When the Postfix local delivery agent detects a mail delivery loop
-(usually the result of mis-configured mail pickup software), the
-undeliverable mail is now sent to the mailing list owner instead
-of the envelope sender address (usually the original poster who
-has no guilt, and who cannot fix the problem).
-
-New "hold" queue for mail that should not be delivered.  "postsuper
--h" puts mail on hold, and "postsuper -H" releases mail, moving
-mail that was "on hold" to the deferred queue.
-
-New header/body HOLD action that causes mail to be placed on the
-"hold" queue. Presently, all you can do with mail "on hold" is to
-examine it with postcat, to take it "off hold" with "postsuper -H",
-or to destroy it with "postsuper -d". See conf/sample-filter.cf.
-
-The Postfix queue manager now warns when mail for some destination
-is piling up in the active queue, and suggests a variety of remedies
-to speed up delivery (increase per-destination concurrency limit,
-increase active queue size, use a separate delivery transport,
-increase per-transport process limit).  The qmgr_clog_warn_time
-parameter controls the time between warnings.  To disable these
-warnings, specify "qmgr_clog_warn_time = 0".
-
-Incompatible changes with Postfix snapshot 1.1.11-20020717
-==========================================================
-
-The default timeout for establishing an SMTP connection has been
-reduced to 30 seconds, because many systems have an atrociously
-large default timeout value.
-
-The Postfix SMTP client now logs a warning when the same domain is
-listed in main.cf:mydestination as well as a Postfix-style virtual
-map. Such a mis-configuration may cause mail for users to be rejected
-with "user unknown".
-
-Postfix no longer strips multiple '.' characters from the end of
-an email address or domain name. Only one '.' is tolerated.
-
-The SMTP server reject_unknown_{sender,recipient}_domain etc.
-restrictions now also attempt to look up AAAA (IPV6 address) records.
-
-Major changes with Postfix snapshot 1.1.11-20020717
-===================================================
-
-The masquerade_domains feature now supports exceptions.  Prepend
-a ! character to a domain name in order to not strip its subdomain
-structure.  More information in conf/sample-rewrite.cf.
-
-The Postfix virtual delivery agent supports catch-all entries
-(@domain.tld) in lookup tables. These match users that do not
-have a specific user@domain.tld entry. The virtual delivery agent
-now ignores address extensions (user+foo@domain.tld) when searching
-its lookup tables, but displays the extensions in Delivered-To:
-message headers.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020610
-==========================================================
-
-Regexp-based transport maps now see the entire recipient address
-instead of only the destination domain name.
+Incompatible changes with Postfix snapshot 1.1.11-trace-20021119
+================================================================
 
-Major changes with Postfix snapshot 1.1.11-20020610
-===================================================
+After upgrading an existing system you must use "postfix reload".
+This is because many internal protocols have changed.
 
-A bizarre feature, sender-based routing, that could be useful in
-combination with user@domain address lookups in the transport map.
+The file format of bounce/defer logfiles has changed from the old
+one-line ad-hoc format to a more structured multi-line format. For
+backwards compatibility, Postfix now creates bounce/defer logfile
+entries that contain both the old and the new format, so that you
+can go back to an older Postfix release without losing information.
+Old Postfix versions will warn about malformed logfile entries,
+but should work properly. To disable backwards compatibility specify
+"backwards_bounce_logfile_compatibility = no" in main.cf.
 
-An actually useful feature, user@domain address lookups in the
-transport map.  This feature also understands address extensions.
-Transport maps still support lookup keys in the form of domain
-names, but only with non-regexp tables.  Specify <> in order to
-match the null address. More in the transport(5) manual page.
+The behavior of "sendmail -v" has changed. One -v option now sends
+an email report with the status of each delivery attempt.  Multiple
+-v options behave as before: turn on verbose logging in the sendmail
+and and postdrop commands.
 
-Together with sender-based routing, and a dual Postfix setup.
-user@domain transport map lookups could fulfill people's wishes to
-have multiple SMTP personalities for sending and receiving mail,
-including bounce processing.  Details will have to be hammered out
-by users, as Wietse is now completely tied up by other business
-for the next three weeks.
+The Postfix upgrade procedure will add two new services to your
+master.cf file: "trace" and "verify". These servers can run inside
+a chroot jail, have no interaction with users, and don't talk to
+the network.
 
-Incompatible changes with Postfix snapshot 1.1.11-20020528
-==========================================================
-
-With PCRE pattern matching, the `.' metacharacter now matches all
-characters including newline characters. This makes PCRE pattern
-matching more convenient to use with multi-line message headers,
-and also makes PCRE more compatible with regexp pattern matching.
-The pcre_table(5) manual page has been greatly revised.
-
-Major changes with Postfix snapshot 1.1.11-20020528
-===================================================
-
-Postfix can enforce specific aspects of the MIME standards while
-receiving mail.
-
-* Specify "strict_7bit_headers = yes" to disallow 8-bit characters
-  in message headers.  These are always illegal.
-
-* Specify "strict_8bitmime_body = yes" to block mail with 8-bit
-  content that is not properly labeled as 8-bit MIME. This blocks
-  mail from poorly written mail software, including (bounces from
-  qmail, bounces from Postfix before snapshot 20020514, and Majordomo
-  approval requests) that contain valid 8BITMIME mail.
-
-* Specify "strict_8bitmime = yes" to turn on both strict_7bit_headers
-  and strict_8bitmime_body.
-
-* Specify "strict_mime_encoding_domain = yes" to block mail from
-  poorly written mail software. More details in conf/sample-mime.cf.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020527
-==========================================================
-
-Message headers in MIME attachments etc. are no longer matched by
-body_checks, one input line at a time. They are now by default
-matched by header_checks, one multi-line header at a time.  To get
-the old behavior, specify "disable_mime_input_processing = yes",
-or specify separate patterns for header_checks, mime_header_checks
-and nested_header_checks. See conf/sample-mime.cf for details.
-
-Postfix now rejects mail if the MIME multipart structure is nested
-more than mime_nesting_limit levels (default: 20) when MIME input
-processing is enabled while receiving mail, or when Postfix is
-performing 8BITMIME to 7BIT conversion while delivering mail.
-
-Postfix now recognizes "name :" as a valid message header, but
-normalizes it to "name:" for consistency (actually, there is so
-much code in Postfix that would break with "name :" that there is
-little choice, except to not recognize "name :" headers).
-
-Queue files created with the header/body_checks "FILTER" feature
-are not compatible with "postqueue -r" (move queue files back to
-the maildrop directory) of previous Postfix releases.
-
-Major changes with Postfix snapshot 1.1.11-20020527
-===================================================
-
-Postfix now has real MIME support. This improves content filtering
-efficiency and accuracy, and improves inter-operability with mail
-systems that cannot receive 8-bit mail. See conf/sample-mime.cf
-for details.
-
-Postfix header_checks now properly recognize MIME headers in
-attachments. This is much more efficient than previous versions
-that recognized MIME headers via body_checks.  MIME headers are
-now processed one multi-line header at a time, instead of one body
-line at a time.
-
-In fact, Postfix now has three classes of header patterns:
-header_checks (for primary message headers except MIME headers),
-mime_header_checks (for MIME headers), and nested_header_checks
-(for headers of attached email messages except MIME headers).  By
-default, all headers are matched with header_checks.  To get the
-the old behavior, specify "disable_mime_input_processing = yes".
-More details in conf/sample-filter.cf.
-
-Selective content filtering. In header/body_check patterns, specify
-"FILTER transport:nexthop" for mail that needs filtering. This
-requires different cleanup servers before and after the filter,
-with header/body checks turned off in the second cleanup server.
-More info about content filtering is in the Postfix FILTER_README
-file. Examples for this new feature still need to be developed.
-This feature overrides the main.cf content_filter setting.
-
-The Postfix SMTP client will now convert 8BITMIME mail to 7BIT when
-delivering to an SMTP server that does not announce 8BITMIME support.
-To disable, specify "disable_mime_output_conversion = yes". However,
-this conversion is required by RFC standards.
-
-Incompatible changes with Postfix snapshot 1.1.10-20020514
-==========================================================
-
-For safety reasons, the permit_mx_backup restriction no longer
-accepts mail for user@domain@domain. To recover the old behavior,
-specify "resolve_dequoted_address = no" which opens up a completely
-different can of worms as described a few paragraphs down in this
-document.
-
-Major changes with Postfix snapshot 1.1.9-20020513
-==================================================
-
-Updated LDAP client module with better handling of dead LDAP servers,
-and with configurable filtering of query results.
-
-In order to allow user@domain@domain addresses from untrusted
-systems, specify "resolve_dequoted_address = no" in main.cf (when
-resolving mail, quote the address localpart as per RFC 822, so that
-@ or % or !  operators in the address localpart remain invisible).
-Although this behavior is technically more correct, it also opens
-opportunities for mail relay attacks when Postfix provides backup
-MX service for Sendmail systems.
-
-Incompatible changes with Postfix snapshot 1.1.9-20020512
+Major changes with Postfix snapshot 1.1.11-trace-20021119
 =========================================================
 
-The Postfix SMTP client no longer uses the CNAME expanded recipient
-address when logging delivery or when bouncing mail. This makes
-trouble shooting somewhat easier.
-
-Postfix snapshot 1.1.9-20020512 queue files contain records that
-are incompatible with "postqueue -r" on all Postfix versions prior
-to 1.1 and release candidates. This happens whenever the sender
-specifies MIME body type information via the SMTP `MAIL FROM'
-command, via the `sendmail -B' command line option, or via the
-Content-Transfer-Encoding:  message header.
-
-Postfix snapshot 1.1.9-20020512 queue files may contain records
-that are incompatible with "postqueue -r" on previous 1.1 Postfix
-versions and release candidates. This happens whenever the sender
-specifies the MIME body type only via the Content-Transfer-Encoding:
-message header, and not via `MAIL FROM' or `sendmail -B'.
-
-Major changes with Postfix snapshot 1.1.9-20020512
-==================================================
-
-The Postfix SMTP and LMTP clients now properly pass on the MIME
-body type information (7BIT or 8BITMIME), provided that the sender
-properly specifies MIME body type information via the SMTP MAIL
-FROM command, via the sendmail -B command line option, or via MIME
-message headers. This includes mail that is returned as undeliverable.
-Implementing MIME body type propagation was a low priority because
-qmail didn't implement this, either. However, Postfix will not
-convert 8BITMIME content into 7BIT, and probably never will.
-
-Incompatible changes with Postfix snapshot 1.1.9-20020509
-=========================================================
-
-The Postfix SMTP server no longer honors OK access rules for
-user@domain@postfix-style.virtual.domain, to close a relaying
-loophole with postfix-style virtual domains that have @domain.name
-catch-all patterns.
-
-The appearance of user@domain1@domain2 addresses has changed.  In
-mail headers, such addresses are now properly quoted as
-"user@domain1"@domain2. As a side effect, this quoted form is now
-also expected on the left-hand side of virtual and canonical lookup
-tables, but only by some of the Postfix components.  For now, it
-is better not to use user@domain1@domain2 address forms on the
-left-hand side of lookup tables.
-
-Incompatible changes with Postfix snapshot 1.1.8-20020508
-=========================================================
-
-The Postfix SMTP server by default no longer accepts mail for
-user@domain@postfix-style.virtual.domain, to close a relaying
-loophole with postfix-style virtual domains that have @domain.name
-catch-all patterns.
-
-Incompatible changes with Postfix snapshot 1.1.8-20020505
-=========================================================
-
-In the Postfix transport table, the meaning of null delivery
-transport and nexhop information fields has changed. As of now, a
-null delivery transport or nexthop information field means "do not
-modify": use the delivery transport or nexthop information that
-would be used if no transport table did not exist.  This change
-results in the following incompatible changes in behavior:
-
-- A null delivery transport field no longer defaults to
-$default_transport.  It now defaults to $local_transport or
-$default_transport depending on the destination.
-
-- A null nexthop information field no longer overrides the main.cf
-relayhost setting. To override the relayhost, specify explicit
-nexthop information in the Postfix transport table.
-
-The postalias command now copies the source file read permissions
-to the result file when creating a table for the first time. Until
-now, the result file was created with default read permissions.
-This change makes postalias more similar to postmap.
-
-The postalias and postmap commands now drop super-user privileges
-when processing a non-root source file. The file is now processed
-as the source file owner, and the owner must therefore have permission
-to update the result file. Specify the "-o" flag to get the old
-behavior (process non-root files with root privileges).
-
-The read buffer size for Berkeley DB lookup tables was decreased
-from 1MByte to 256kByte. Specify "berkeley_db_read_buffer_size =
-1048576" to get the old read buffer size.
-
-Major changes with Postfix snapshot 1.1.8-20020505
-==================================================
-
-Friendlier behavior of Postfix transport tables. There is a new
-"*" wildcard pattern that matches any domain. The meaning of a null
-delivery transport or nexhop information field has changed to "do
-not modify": use the information that would be used if the transport
-table did not exist. This change makes it easier to route internal
-mail (everything under my.domain) directly: you no longer need to
-specify explicit "local" transport table entries for the local
-machine.  For more information, including examples, see the updated
-transport(5) manual page.
-
-Finer control over Berkeley DB memory usage, and more efficient
-usage of memory in applications that open lots of tables. The
-parameter "berkeley_db_create_buffer_size" (default: 16 MBytes)
-specifies the buffer size for the postmap and postalias commands.
-The parameter "berkeley_db_read_buffer_size" (default: 256 kBytes)
-speficies the buffer size for all other applications. For more
-information, see the last paragraphs of the DB_README file.
-
-Major changes with Postfix snapshot 1.1.7-20020331
-==================================================
-
-Support for the Cyrus SASL version 2 library, contributed by Jason
-Hoos. This adds some new functionality that was not available in
-Cyrus SASL version 1, and provides bit-rot insurance for the time
-when Cyrus SASL version 1 eventually stops working.
-
-A new smtp_helo_name parameter that specifies the hostname to be
-used in HELO or EHLO commands; this can be more convenient than
-changing the myhostname parameter setting.
-
-Choice between multiple instances of internal services:  bounce,
-cleanup, defer, error, flush, pickup, queue, rewrite, showq.  This
-allows you to use different cleanup server settings for different
-SMTP server instances.  For example, specify in the master.cf file:
-
-    localhost:10025 ... smtpd -o cleanup_service_name=cleanup2 ...
-    cleanup2        ... cleanup -o header_checks= body_checks= ...
-
-Incompatible changes with Postfix version 1.1.6 (released 20020326)
-===================================================================
-
-The Postfix SMTP client now breaks message header or body lines
-that are longer than $smtp_line_length_limit characters (default:
-990). Earlier Postfix versions broke lines at $line_length_limit
-characters (default: 2048). Postfix versions before 20010611 did
-not break long lines at all.  Reportedly, some mail servers refuse
-to receive mail with lines that exceed the 1000 character limit
-that is specified by the SMTP standard.
-
-The Postfix SMTP client now breaks long message header or body
-lines by inserting <CR> <LF> <SPACE>.  Earlier Postfix versions
-broke long lines by inserting <CR> <LF> only. This broke MIME
-encapsulation, causing MIME attachments to "disappear" with Postfix
-versions after 20010611.
-
-Postfix now discards text when a logical message header exceeds
-$header_size_limit characters (default: 102400). Earlier Postfix
-versions would place excess text, and all following text, in the
-message body. The same thing was done when a physical header line
-exceeded $line_length_limit characters (default: 2048).  Both
-behaviors broke MIME encapsulation, causing MIME attachments to
-"disappear" with all previous Postfix versions.
-
-Incompatible changes with Postfix version 1.1.3 (released 20020201)
-===================================================================
-
-In Postfix SMTPD access tables, Postfix now uses <> as the default
-lookup key for the null address, in order to work around bugs in
-some Berkeley DB implementations. This behavior is controlled with
-the smtpd_null_access_lookup_key configuration parameter.
-
-On SCO 3.2 UNIX, the input rate flow control is now turned off by
-default, because of limitations in the SCO UNIX kernel.
-
-Incompatible changes with Postfix version 1.1.2 (released 20020125)
-===================================================================
-
-Postfix now detects if the run-time Berkeley DB library routines
-do not match the major version number of the compile-time include
-file that was used for compiling Postfix. The software issues a
-warning and aborts in case of a discrepancy. If it didn't, the
-software was certain to crash with a segmentation violation.
-
-Incompatible changes with Postfix version 1.1.1 (released 20020122)
-===================================================================
-
-When the postmap command creates a non-existent result file, the
-new file inherits the group/other read permissions of the source
-file.
-
-Incompatible changes with Postfix version 1.1.0 (released 20020117)
-===================================================================
-
-Changes are listed in order of decreasing importance, not release
-date.
-
-[snapshot-20010709] This release introduces a new queue file record
-type that is used only for messages that actually use VERP (variable
-envelope return path) support.  With this sole exception, the queue
-file format is entirely backwards compatible with the previous
-official Postfix release (20010228, a.k.a. Postfix 1.0.0).
-
-[snapshot-20020106] This release modifies the existing master.cf
-file. The local pickup service is now unprivileged, and the cleanup
-and flush service are now "public". Should you have to back out to
-a previous release, then you must 1) edit the master.cf file, make
-the pickup service "privileged", and make the cleanup and flush
-services "private"; 2) "chmod 755 /var/spool/postfix/public".  To
-revert to a world-writable mail submission directory, "chmod 1733
-/var/spool/postfix/maildrop".
-
-[snapshot-20020106, snapshot-20010808, snapshot-20011103,
-snapshot-20011121] You must stop and restart Postfix because of
-incompatible changes in the local Postfix security model and in
-the Postfix internal protocols. Old and new components will not
-work together.
-
-[snapshot-20020106] Simpler local Postfix security model.
-
-- No world-writable maildrop directory. Postfix now always uses
-  the set-gid postdrop command for local mail submissions.  The
-  local mail pickup daemon is now an unprivileged process.
-
-- No world-accessible pickup and queue manager server FIFOs.
-
-- New set-gid postqueue command for the queue list/flush operations
-  that used to implemented by the Postfix sendmail command.
-
-[snapshot-20020106..15] Simpler Postfix installation and upgrading.
-
-- All installation settings are now kept in the main.cf file, and
-  better default settings are now generated for system dependent
-  pathnames such as sendmail_path etc. The install.cf file is no
-  longer used, except when upgrading from an older Postfix version.
-
-- Non-default installation parameter settings can (but do not have
-  to) be specified on the "make install" or "make upgrade" command
-  line as name=value arguments.
-
-- New postfix-files database (in /etc/postfix) with (pathname,
-  owner, permission) information about all Postfix-related files.
-
-- New postfix-install script replaces the awkward INSTALL.sh script.
-  This is driven by the postfix-files database. It has better
-  support for building packages for distribution to other systems.
-  See PACKAGE_README for details.
-
-- New post-install script (in /etc/postfix) for post-installation
-  maintenance of directory/file permissions and ownership (this is
-  used by "postfix check"). Example:
-
-    # postfix stop
-    # post-install set-permissions mail_owner=username setgid_group=groupname
-    # postfix start
-
-[snapshot-20020106] Postfix will not run if it detects that the
-postfix user or group ID are shared with other accounts on the
-system. The checks aren't exhaustive (that would be too resource
-consuming) but should be sufficient to encourage packagers and
-developers to do the right thing. To fix the problem, use the above
-post-install command, after you have created the appropriate new
-mail_owner or setgid_group user or group IDs.
-
-[snapshot-20020106] If you run multiple Postfix instances on the
-same machine you now have to specify their configuration directories
-in the default main.cf file as "alternate_config_directories =
-/dir1 /dir2 ...".  Otherwise, some Postfix commands will no longer
-work: the set-group ID postdrop command for mail submission and
-the set-group ID postqueue command for queue listing/flushing.
-
-[snapshot-20010808] The default setting for the maps_rbl_domains
-parameter is now "empty", because mail-abuse.org has become a
-subscription-based service. The names of the RBL parameters haven't
-changed.
-
-[snapshot-20020106] Postfix SMTP access maps will no longer return
-OK for non-local multi-domain recipient mail addresses (user@dom1@dom2,
-user%dom1@dom2, etcetera); the lookup now returns DUNNO (undetermined).
-Non-local multi-domain recipient addresses were already prohibited
-from matching the permit_mx_backup and the relay_domains-based
-restrictions.
-
-[snapshot-20011210] Stricter checking of Postfix chroot configurations.
-The Postfix startup procedure now warns if "system" directories
-(etc, bin, lib, usr) under the Postfix top-level queue directory
-are not owned by the super-user (usually the result of well-intended,
-but misguided, applications of "chown -R postfix /var/spool/postfix).
-
-[snapshot-20011008] The Postfix SMTP server now rejects requests
-with a generic "try again later" status (451 Server configuration
-error) when it detects an error in smtp_{client, helo, sender,
-recipient, etrn}_restrictions settings.  More details about the
-problem are logged to the syslogd; sending such information to
-random clients would be inappropriate.
-
-[snapshot-20011008] Postfix no longer flushes the entire mail queue
-after receiving an ETRN request for a random domain name. Requests
-for domains that do not match $fast_flush_domains are now rejected
-instead.
-
-[snapshot-20011226] Postfix configuration file comments no longer
-continue on the next line when that next line starts with whitespace.
-This change avoids surprises, but it may cause unexpected behavior
-with existing, improperly formatted, configuration files. Caveat
-user. Comment lines are allowed to begin with whitespace. Multi-line
-input is no longer terminated by a comment line, by an all whitespace
-line, or by an empty line.
-
-[snapshot-20010714] Postfix delivery agents now refuse to create
-a missing maildir or mail spool subdirectory when its parent
-directory is world writable.  This is necessary to prevent security
-problems with maildirs or with hashed mailboxes under a world
-writable mail spool directory.
-
-[snapshot-20010525] As per RFC 2821, the Postfix SMTP client now
-always sends EHLO at the beginning of an SMTP session. Specify
-"smtp_always_send_ehlo = no" for the old behavior, which is to send
-EHLO only when the server greeting banner contains the word ESMTP.
-
-[snapshot-20010525] As per RFC 2821, an EHLO command in the middle
-of an SMTP session resets the Postfix SMTP server state just like
-RSET. This behavior cannot be disabled.
-
-[snapshot-20010709] The SMTP client now by default breaks lines >
-2048 characters, to avoid mail delivery problems with fragile SMTP
-server software.  To get the old behavior back, specify "smtp_break_lines
-= no" in the Postfix main.cf file.
-
-[snapshot-20010709] With recipient_delimiter=+ (or any character
-other than -) Postfix will now recognize address extensions even
-with owner-foo+extension addresses. This change was necessary to
-make VERP useful for mailing list bounce processing.
-
-[snapshot-20010610] The Postfix pipe delivery agent no longer
-automatically case-folds the expansion of $user, $extension or
-$mailbox command-line macros.  Specify the 'u' flag to get the old
-behavior.
-
-[snapshot-20011210] The Postfix sendmail command no longer exits
-with status 1 when mail submission fails, but instead returns a
-sendmail-compatible status code as defined in /usr/include/sysexits.h.
-
-Major changes with Postfix version 1.1.0 (Released 20020117)
-============================================================
-
-Changes are listed in order of decreasing importance, not release
-date.
-
-The nqmgr queue manager is now bundled with Postfix. It implements
-a smarter scheduling strategy that allows ordinary mail to slip
-past mailing list mail, resulting in better response. This queue
-manager is expected to become the default queue manager shortly.
-
-[snapshot-20010709, snapshot-20010808] VERP (variable envelope
-return path) support.  This is enabled by default, including in
-the SMTP server. See the VERP_README file for instructions.  Specify
-"disable_verp_bounces = yes" to have Postfix send one RFC-standard,
-non-VERP, bounce report for multi-recipient mail, even when VERP
-style delivery was requested.  This reduces the explosive behavior
-of bounces when sending mail to a list.
-
-[snapshot-20010709] QMQP server support, so that Postfix can be
-used as a backend mailer for the ezmlm-idx mailing list manager.
-You still need qmail to drive ezmlm and to process mailing list
-bounces. The QMQP service is disabled by default. To enable, follow
-the instructions in the QMQP_README file.
-
-[snapshot-20010709] You can now reject unknown virtual(8) recipients
-at the SMTP port by specifying a "domain.name whatever" entry in
-the tables specified with virtual_mailbox_maps, similar to Postfix
-virtual(5) domains.  [virtual(8) is the Postfix virtual delivery
-agent, virtual(5) is the Postfix virtual map. The two implement
-virtual domains in a very different manner.]
-
-[snapshot-20011121] Configurable host/domain name wildcard matching
-behavior: choice between "pattern `domain.name' matches string
-`host.domain.name'" (this is to be deprecated in the future) and
-"pattern `.domain.name' matches string `host.domain.name'" (this
-is to be preferred in the future).  The configuration parameter
-"parent_domain_matches_subdomains" specifies which Postfix features
-use the behavior that will become deprecated.
-
-[snapshot-20010808] Variable coupling between message receiving
-rates and message delivery rates. When the message receiving rate
-exceeds the message delivery rate, an SMTP server will pause for
-$in_flow_delay seconds before accepting a message.  This delay
-gives Postfix a chance catch up and access the disk, while still
-allowing new mail to arrive.  This feature currently has effect
-only when mail arrives via a small number of SMTP clients.
-
-[snapshot-20010610, snapshot-20011121, snapshot-20011210] Workarounds
-for a bug in old versions of the CISCO PIX firewall software that
-caused mail to be resent repeatedly.  The workaround has no effect
-for other mail deliveries. The workaround is turned off when mail
-is queued for less than $smtp_pix_workaround_threshold_time seconds
-(default:  500 seconds) so that the workaround is normally enabled
-only for deferred mail.  The delay before sending .<CR><LF> is now
-controlled by the $smtp_pix_workaround_delay_time setting (default:
-10 seconds).
-
-[snapshot-20011226] Postfix will now do null address lookups in
-SMTPD access maps.  If your access maps cannot store or look up
-null string key values, specify "smtpd_null_access_lookup_key =
-<>" and the null sender address will be looked up as <> instead.
-
-[snapshot-20011210] More usable virtual delivery agent, thanks to
-a new "static" map type by Jeff Miller that always returns its map
-name as the lookup result. This eliminates the need for per-recipient
-user ID and group ID tables.  See the VIRTUAL_README file for more
-details.
-
-[snapshot-20011125] Anti-sender spoofing. New main.cf parameter
-smtpd_sender_login_maps that specifies the (SASL) login name that
-owns a MAIL FROM sender address.  Specify a regexp table in order
-to require a simple one-to-one mapping.  New SMTPD restriction
-reject_sender_login_mismatch that refuses a MAIL FROM address when
-$smtpd_sender_login_maps specifies an owner but the client is not
-(SASL) logged in as the MAIL FROM address owner, or when a client
-is (SASL) logged in but does not own the address according to
-$smtpd_sender_login_maps.
-
-[snapshot-20011121] The mailbox_command_maps parameter allows you
-to configure the external delivery command per user (local delivery
-agent only).  This feature has precedence over the mailbox_command
-and home_mailbox settings.
-
-[snapshot-20011121] New "warn_if_reject" smtpd UCE restriction that
-only warns if the restriction that follows would reject mail.  Look
-for file records that contain the string "reject_warning".
-
-[snapshot-20011127] New header/body_check result "WARN" to make
-Postfix log a warning about a header/body line without rejecting
-the content.
-
-[snapshot-20011103] In header/body_check files, REJECT can now be
-followed by text that is sent to the originator. That feature was
-stuck waiting for years, pending the internal protocol revision.
-
-[snapshot-20011008] The permit_mx_backup feature allows you to
-specify network address blocks via the permit_mx_backup_networks
-parameter.  This requires that the primary MX hosts for the given
-destination match the specified network blocks. When no value is
-given for permit_mx_backup_networks, Postfix will accept mail
-whenever the local MTA is listed in the DNS as an MX relay host
-for a destination, even when you never gave permission to do so.
-
-[snapshot-20010709] Specify "mail_spool_directory = /var/mail/"
-(note the trailing "/" character) to enable maildir format for
-/var/mail/username.
-
-[snapshot-20010808] Finer control over address masquerading. The
-masquerade_classes parameter now controls header and envelope sender
-and recipient addresses.  With earlier Postfix versions, address
-masquerading rewrote all addresses except for the envelope recipient.
-
-[snapshot-20010610] The pipe mail delivery agent now supports proper
-quoting of white space and other special characters in the expansions
-of the $sender and $recipient command-line macros. This was necessary
-for correct operation of the "simple" content filter, and is also
-recommended for delivery via UUCP or BSMTP.
-
-[snapshot-20010610] The pipe mail delivery agent now supports case
-folding the localpart and/or domain part of expansions of the
-$nexthop, $recipient, $user, $extension or $mailbox command-line
-macros. This is recommended for mail delivery via UUCP. Bug: $nexthop
-is always case folded because of problems in the queue manager
-code.
-
-[snapshot-20010525] This release contains many little revisions of
-little details in the light of the new RFC 2821 and RFC 2822
-standards. Changes that may affect interoperability are listed
-above under "incompatible changes".  Other little details are
-discussed in comments in the source code.
-
-[snapshot-20010502] The Postfix SMTP client now by default randomly
-shuffles destination IP addresses of equal preference (whether
-obtained via MX lookup or otherwise). Reportedly, this is needed
-for sites that use Bernstein's dnscache program. Specify
-"smtp_randomize_addresses = no" to disable this behavior. Based on
-shuffling code by Aleph1.
-
-[snapshot-20011127] New parameter smtpd_noop_commands to specify
-a list of commands that the Postfix SMTP server treats as NOOP
-commands (no syntax check, no state change). This is a workaround
-for misbehaving clients that send unsupported commands such as
-ONEX.
-
-[snapshot-20010502] "postmap -q -" and "postmap -d -" read key
-values from standard input, which makes it easier to drive them
-from another program.  The same feature was added to the postalias
-command.
-
-[snapshot-20010502] The postsuper command now has a command-line
-option to delete queue files.  In principle this command can be
-used while Postfix is running, but there is a possibility of deleting
-the wrong queue file when Postfix deletes a queue file and reuses
-the queue ID for a new message.  In that case, postsuper will delete
-the new message.
-
-[snapshot-20010525] The postsuper queue maintenance tool now renames
-files whose name (queue ID) does not match the message file inode
-number. This is necessary after a Postfix mail queue is restored
-from another machine or from backups.  The feature is selected with
-the -s option, which is the default, and runs whenever Postfix is
-started.
-
-[snapshot-20010525] The postsuper queue maintenance tool has a new
--r (requeue) option for subjecting some or all queue files to
-another iteration of address rewriting. This is useful after the
-virtual or canonical maps have changed.
-
-[snapshot-20010525] The postsuper queue maintenance tool was extended
-with options to read queue IDs from standard input. This makes the
-tool easier to drive from scripts.
-
-[snapshot-20010329] Better support for running multiple Postfix
-instances on one machine. Each instance can be recognized by its
-logging (defaults:  "syslog_name = postfix", "syslog_facility =
-mail").
-
-Major incompatible changes with release-20010228 Patch 01 (a.k.a. Postfix 1.0.1)
-================================================================================
-
-This release changes the names of the "fast ETRN" logfiles with
-delayed mail per destination. These files are maintained by the
-Postfix "fast flush" daemon. The old scheme failed with addresses
-of the form user@[ip.address] and user@a.domain.name.  In order to
-populate the new "fast ETRN" logfiles, execute the command "sendmail
--q".  The old "fast ETRN" logfiles go away by themselves (default:
-after 7 days).
-
-Major incompatible changes with release-20010228 (a.k.a. Postfix 1.0.0)
-=======================================================================
-
-[snapshot-20010225] POSTFIX NO LONGER RELAYS MAIL FOR CLIENTS IN
-THE ENTIRE CLASS A/B/C NETWORK. To get the old behavior, specify
-"mynetworks_style = class" in the main.cf file. The default
-(mynetworks_style = subnet) is to relay for clients in the local
-IP subnet. See conf/main.cf.
-
-[snapshot-20001005, snapshot-20010225] You must execute "postfix
-stop" before installing this release.  Some recommended parameter
-settings have changed, and a new entry must be added to the master.cf
-file before you can start Postfix again.
-
-1 - The recommended Postfix configuration no longer uses flat
-    directories for the "incoming" "active", "bounce", and "defer"
-    queue directories.  The "flush" directory for the new "flush"
-    service directory should not be flat either.
-
-    Upon start-up, Postfix checks if the hash_queue_names configuration
-    parameter is properly set up, and will add any queue directory
-    names that are missing.
-
-2 - In order to improve performance of one-to-one mail deliveries
-    the queue manager will now look at up to 10000 queue files
-    (was: 1000).  The default qmgr_message_active_limit setting
-    was changed accordingly.
-
-    If you have a non-default qmgr_message_active_limit in main.cf,
-    you may want adjust it.
-
-3 - The new "flush" service needs to be configured in master.cf.
-
-    Upon start-up, Postfix checks if the new "flush" service is
-    configured in the master.cf file, and will add an entry if it
-    is missing.
-
-Should you wish to back out to a previous Postfix release there is
-no need to undo the above queue configuration changes.
-
-[snapshot-20000921] The protocol between queue manager and delivery
-agents has changed.  This means that you cannot mix the Postfix
-queue manager or delivery agents with those of Postfix versions
-prior to 20000921. This change does not affect Postfix queue file
-formats.
-
-[snapshot-20000529] This release introduces an incompatible queue
-file format change ONLY when content filtering is enabled (see text
-in FILTER_README). Old Postfix queue files will work fine, but
-queue files with the new content filtering info will not work with
-Postfix versions before 20000529.  Postfix logs a warning and moves
-incompatible queue files to the "corrupt" mail queue subdirectory.
-
-Minor incompatible changes with release-20010228
-================================================
-
-[snapshot-20010225] The incoming and deferred queue directories
-are now hashed by default.  This improves the performance considerably
-under heavy load, at the cost of a small but noticeable slowdown
-when one runs "mailq" on an unloaded system.
-
-[snapshot-20010222] Postfix no longer automatically delivers
-recipients one at a time when their domain is listed in $mydestination.
-This change solves delivery performance problems with delivery via
-LMTP, with virus scanning, and with firewall relays that forward
-all mail for $mydestination to an inside host.
-
-The "one recipient at a time" delivery behavior is now controlled
-by the per-transport recipient limit (xxx_destination_recipient_limit,
-where xxx is the name of the delivery mechanism).  This parameter
-controls the number of recipients that can be sent in one delivery
-(surprise).
-
-The setting of the per-transport recipient limit also controls the
-meaning of the per-transport destination concurrency limit (named
-xxx_destination_concurrency_limit, where xxx is again the name of
-the delivery mechanism):
-
- 1) When the per-transport recipient limit is 1 (i.e., send one
-    recipient per delivery), the per-transport destination concurrency
-    limit controls the number of simultaneous deliveries to the
-    same recipient.  This is the default behavior for delivery via
-    the Postfix local delivery agent.
-
- 2) When the per-transport recipient limit is > 1 (i.e., send
-    multiple recipients per delivery), the per-transport destination
-    concurrency limit controls the number of simultaneous deliveries
-    to the same domain.  This is the default behavior for all other
-    Postfix delivery agents.
-
-[snapshot-20010128] The Postfix local delivery agent now enforces
-mailbox file size limits (default: mailbox_size_limit = 51200000).
-This limit affects all file write access by the local delivery
-agent or by a process run by the local delivery agent. The purpose
-of this parameter is to act as a safety for run-away software. It
-cannot be a substitute for a file quota management system. Specify
-a limit of 0 to disable.
-
-[snapshot-20010128] REJECT in header/body_checks is now flagged as
-policy violation rather than bounce, for consistency in postmaster
-notifications.
-
-[snapshot-20010128] The default RBL (real-time blackhole lists)
-domain examples have been changed from *.vix.com to *.mail-abuse.org.
-
-[snapshot-20001210] Several interfaces of libutil and libglobal
-routines have changed.  This may break third-party code written
-for Postfix. In particular, the safe_open() routine has changed,
-the way the preferred locking method is specified in the sys_defs.h
-file, as well as all routines that perform file locking. When
-compiling third-party code written for Postfix, the incompatibilities
-will be detected by the compiler provided that #include file
-dependencies are properly maintained.
-
-[snapshot-20001210] When delivering to /file/name (as directed in
-an alias or .forward file), the local delivery agent now logs a
-warning when it is unable to create a /file/name.lock file. Mail
-is still delivered as before.
-
-[snapshot-20001210] The "sun_mailtool_compatibility" feature is
-going away (a compatibility mode that turns off kernel locks on
-mailbox files). It still works, but a warning is logged. Instead
-of using "sun_mailtool_compatibility", specify the mailbox locking
-strategy as "mailbox_delivery_lock = dotlock".
-
-[snapshot-20001210] The Postfix SMTP client now skips SMTP server
-replies that do not start with "CODE SPACE" or with "CODE HYPHEN"
-and flags them as protocol errors. Older Postfix SMTP clients
-silently treated "CODE TEXT" as "CODE SPACE TEXT", i.e. as a valid
-SMTP reply.
-
-[snapshot-20001121] On RedHat Linux 7.0, you must install the
-db3-devel RPM before you can compile the Postfix source code.
-
-[snapshot-20000924] The postmaster address in the "sorry" text at
-the top of bounced mail is now just postmaster, not postmaster@machine.
-The idea is to refer users to their own postmaster.
-
-[snapshot-20000921] The notation of [host:port] in transport tables
-etc. is going away but it is still supported. The preferred form
-is now [host]:port.  This change is necessary to support IPV6
-address forms which use ":" as part of a numeric IP address. In a
-future release, Postfix will log a warning when it encounters the
-[host:port] form.
-
-[snapshot-20000921] In mail headers, Errors-To:, Reply-To: and
-Return-Receipt:  addresses are now rewritten as a sender address
-(was: recipient).
-
-[snapshot-20000921] Postfix no longer inserts Sender: message
-headers.
-
-[snapshot-20000921] The queue manager now logs the original number
-of recipients when opening a queue file (example: from=<>, size=3502,
-nrcpt=1).
-
-[snapshot-20000921] The local delivery agent no longer appends a
-blank line to mail that is delivered to external command.
-
-[snapshot-20000921] The pipe delivery agent no longer appends a
-blank line when the F flag is specified (in the master.cf file).
-Specify the B flag if you need that blank line.
-
-[snapshot-20000507] As required by RFC 822, Postfix now inserts a
-generic destination message header when no destination header is
-present.  The text is specified via the undisclosed_recipients_header
-configuration parameter (default:  "To: undisclosed-recipients:;").
-
-[snapshot-20000507] The Postfix sendmail command treats a line with
-only `.' as the end of input, for the sake of sendmail compatibility.
-To disable this feature, specify the sendmail-compatible `-i' or
-`-oi' flags on the sendmail command line.
-
-[snapshot-20000507] For the sake of Sendmail compatibility, the
-Postfix SMTP client skips over SMTP servers that greet with a 4XX
-or 5XX reply code, treating them as unreachable servers.  To obtain
-prior behavior (4XX=retry, 5XX=bounce), specify "smtp_skip_4xx_greeting
-= no" and "smtp_skip_5xx_greeting = no".
-
-Major changes with release-20010228
-===================================
-
-Postfix produces DSN formatted bounced/delayed mail notifications.
-The human-readable text still exists, so that users will not have
-to be unnecessarily confused by all the ugliness of RFC 1894.  Full
-DSN support will be later.
-
-This release introduces full content filtering through an external
-process. This involves an incompatible change in queue file format.
-Mail is delivered to content filtering software via an existing
-mail delivery agent, and is re-injected into Postfix via an existing
-mail submission agent.  See examples in the FILTER_README file.
-Depending on how the filter is implemented, you can expect to lose
-a factor of 2 to 4 in delivery performance of SMTP transit mail,
-more if the content filtering software needs lots of CPU or memory.
-
-Specify "body_checks = regexp:/etc/postfix/body_checks" for a quick
-and dirty emergency content filter that looks at non-header lines
-one line at a time (including MIME headers inside the message body).
-Details in conf/sample-filter.cf.
-
-The header_checks and body_checks features can be used to strip
-out unwanted data. Specify IGNORE on the right-hand side and the
-data will disappear from the mail.
-
-Support for SASL (RFC 2554) authentication in the SMTP server and
-in the SMTP and LMTP clients. See the SASL_README file for more
-details. This file still needs better examples.
-
-Postfix now ships with an LMTP delivery agent that can deliver over
-local/remote TCP sockets and over local UNIX-domain sockets.  The
-LMTP_README file gives example, but still needs to be revised.
-
-Fast "ETRN" and "sendmail -qR".  Postfix maintains per-destination
-logfiles with information about what mail is queued for selected
-destinations.  See the file ETRN_README for details.
-
-The mailbox locking style is now fully configurable at runtime.
-The new configuration parameter is called "mailbox_delivery_lock".
-Depending on the operating system type, mailboxes can be locked
-with one or more of "flock", "fcntl" or "dotlock".  The command
-"postconf -l" shows the available locking styles.  The default
-mailbox locking style is system dependent.  This change affects
-all mailbox and all "/file/name" deliveries by the Postfix local
-delivery agent.
-
-Minor changes with release-20010228
-===================================
-
-You can now specify multiple SMTP destinations in the relayhost
-and fallback_relay configuration parameters. The destinations are
-tried in the specified order. Specify host or host:port (perform
-MX record lookups), [host] or [host]:port (no MX record lookups),
-[address] or [address]:port (numerical IP address).
-
-The "mailbox_transport" and "fallback_transport" parameters now
-understand the form "transport:nexthop", with suitable defaults
-when either transport or nexthop are omitted, just like in the
-Postfix transport map. This allows you to specify for example,
-"mailbox_transport = lmtp:unix:/file/name".
-
-The local_transport and default_transport configuration parameters
-can now be specified in transport:destination notation, just like
-the mailbox_transport and fallback_transport parameters.  The
-:destination part is optional.  However, these parameters take only
-one destination, unlike relayhost and fallback-relay which take
-any number of destinations.
-
-More general virtual domain support.  Postfix now supports both
-Sendmail-style virtual domains and Postfix-style virtual domains.
-Details and examples are given in the revised virtual manual page.
-
-- With Sendmail-style virtual domains, local users/aliases/mailing
-  lists are visible as localname@virtual.domain. This is convenient
-  if you want to host mailing lists under virtual domains.
-
-- With Postfix-style virtual domains, local users/aliases/mailing
-  lists are not visible as localname@virtual.domain. Each virtual
-  domain has its own separate name space.
-
-More general "soft bounce" feature.  Specify "soft_bounce = yes"
-in main.cf to prevent the SMTP server from bouncing mail while you
-are testing configurations. Until this release the SMTP server was
-not aware of soft bounces.
-
-Workarounds for non-standard RFC 2554 (AUTH command) implementations.
-Specify "broken_sasl_auth_clients = yes" to enable SMTP server
-support for old Microsoft client applications. The Postfix SMTP
-client supports non-standard RFC 2554 servers by default.
-
-All time-related configuration parameters now accept a one-letter
-suffix to indicate the time unit (s: second, m: minute, h: hour,
-d: day, w: week). The exceptions are the LDAP and MYSQL modules
-which are maintained separately.
-
-New "import_environment" and "export_environment" configuration
-parameters provide explicit control over what environment variables
-Postfix will import, and what environment variables Postfix will
-pass on to a non-Postfix process.
-
-In order to improve performance of one-to-one deliveries, Postfix
-by default now looks at up to 10000 messages at a time (was: 1000).
-
-Specify "syslog_facility = log_local1" etc. to separate the logging
-from multiple Postfix instances. However, a non-default logging
-facility takes effect only after process initialization. Errors
-during command-line parsing are still logged with the default syslog
-facility, as are errors while processing the main.cf file.
-
-Postfix now strips out Content-Length: headers in incoming mail to
-avoid confusion in mail user agents.
-
-Specify "require_home_directory = yes" to prevent mail from being
-delivered to a user whose home directory is not mounted. This
-feature is implemented by the Postfix local delivery agent.
-
-The pipe mailer has a size limit (size=nnn) command-line argument.
-
-The pipe delivery agent has a configurable end-of-line attribute.
-Specify "pipe ... eol=\r\n" for delivery mechanisms that require
-CRLF record delimiters. The eol attribute understands the following
-C-style escape sequences:  \a \b \f \n \r \t \v \nnn \\.
-
-In master.cf you can selectively override main.cf configuration
-parameters, for example: "smtpd -o myhostname=foo.com".
-
-In main.cf, specify "smtp_bind_address=x.x.x.x" to bind SMTP
-connections to a specific local interface. Or override the default
-setting in master.cf with "smtp -o smtp_bind_address=x.x.x.x".
-For now, you must specify a numeric IP address.
-
-Questionable feature: with "smtp_always_send_ehlo = yes", the SMTP
-client sends EHLO regardless of the content of the SMTP server's
-greeting.
-
-Specify "-d key" to postalias or postmap in order to remove one
-key. This still needs to be generalized to multi-key removal (e.g.,
-read keys from stdin).
-
-Comments in Postfix configuration files no longer contain troff
-formatting codes.  The text is now generated from prototype files
-in a new "proto" subdirectory.
-
-Major changes with postfix-19991231:
-====================================
-
-- It is now much more difficult to configure Postfix as an open
-relay. The SMTP server requires that "smtpd_recipient_restrictions"
-contains at least one restriction that by default refuses mail (as
-is the default).  There were too many accidents with changes to
-the UCE restrictions.
-
-- The relay_domains parameter no longer needs to contain $virtual_maps.
-
-- Overhauled FAQ (html/faq.html) with many more examples.
-
-- Updated UCE documentation (html/uce.html) with more examples.
-More UCE configuration examples in sample configuration files.
-
-- Several little improvements to the installation procedure:
-relative symlinks, configurable directory for scratch files so the
-installation can be done without write access to the build tree.
-
-- Updated LDAP client code (John Hensley).
-
-- Updated mysql client code (Scott Cotton).
-
-- The SMTP server now rejects mail for unknown users in virtual
-domains that are defined by Postfix virtual maps.
-
-- The SMTP server can reject mail for unknown local users.  Specify
-"local_recipient_maps = $alias_maps, unix:passwd.byname" if your
-local mail is delivered by a UNIX-style local delivery agent.  See
-example in conf/main.cf.
-
-- Use "disable_vrfy_command = yes" to disable the SMTP VRFY command.
-This prevents some forms of address harvesting.
-
-- The sendmail "-f" option now understands <user> and even understands
-forms with RFC 822-style comments.
-
-- New "qmgr_fudge_factor" parameter allows you to balance mailing
-list performance against response time for one-to-one mail.  The
-fudge factor controls what percentage of delivery resources Postfix
-will devote to one message.  With 100%, delivery of one message
-does not begin before delivery of the previous message is completed.
-This is good for list performance, bad for one-to-one mail. With
-10%, response time for one-to-one mail improves much, but list
-performance suffers: in the worst case, people near the start of a
-mailing list get a burst of postings today, while people near the
-end of the list get that same burst of postings a whole day later.
-
-- It is now relatively safe to configure 550 status codes for the
-main.cf unknown_address_reject_code or unknown_client_reject_code
-parameters.  The SMTP server now always sends a 450 (try again)
-reply code when an UCE restriction fails due to a soft DNS error,
-regardless of what main.cf specifies.
-
-- The RBL checks now show the content of TXT records (Simon J Mudd).
-
-- The Postfix SMTP server now understands a wider range of illegal
-address forms in MAIL FROM and RCPT TO commands. In order to disable
-illegal forms, specify "strict_rfc821_envelopes = yes". This also
-disables support for MAIL FROM and RCPT TO addresses without <>.
-
-- Per-client/helo/sender/recipient UCE restrictions (fully-recursive
-UCE restriction parser). See the RESTRICTION_CLASS file for details.
-
-- Use "postmap -q key" or "postalias -q key" for testing Postfix
-lookup tables or alias files.
-
-- Use "postconf -e name=value..." to edit the main.cf file.  This
-is easier and safer than editing the main.cf file by hand. The
-edits are done on a temporary copy that is renamed into place.
-
-- Use "postconf -m" to display all supported lookup table types
-(Scott Cotton).
-
-- New "permit_auth_destination" UCE restriction for finer-grained
-access control (Jesper Skriver).
-
-Incompatible changes with postfix-19990906
-==========================================
-
-- On systems that use user.lock files to protect system mailboxes
-against simultaneous updates, Postfix now uses /file/name.lock
-files while delivering to files specified in aliases/forward/include
-files. This is a no-op when the recipient lacks directory write
-permission.
-
-- The LDAP client code no longer looks up a name containing "*"
-because it could be abused.  See the LDAP_README file for how to
-restore previous behavior.
-
-- The Postfix to PCRE interface now expects PCRE version 2.08.
-Postfix is no longer compatible with PCRE versions prior to 2.06.
-
-Major changes with postfix-19990906
-===================================
-
-Several bugfixes, none related to security.  See the HISTORY file
-for a complete list of changes.
-
-- Postfix is now distributed under IBM Public License Version 1.0
-which does not carry the controversial termination clause. The new
-license does have a requirement that contributors make source code
-available.
-
-- INSTALL.sh install/upgrade procedure that replaces existing
-programs and shell scripts instead of overwriting them, and that
-leaves existing queue files and configuration files alone.
-
-- The ugly Delivered-To: header can now be turned off selectively.
-The default setting is:  "prepend_delivered_header = command, file,
-forward".  Turning off the Delivered-To:  header when forwarding
-mail is not recommended.
-
-- mysql client support by Scott Cotton and Joshua Marcus, Internet
-Consultants Group, Inc. See the file MYSQL_README for instructions.
-
-- reject_unauth_destination SMTP recipient restriction that rejects
-destinations not in $relay_domains. Unlike the check_relay_domains
-restriction, reject_unauth_destination ignores the client hostname.
-By Lamont Jones of Hewlett-Packard.
-
-- reject_unauth_pipelining SMTP *anything* restriction to stop mail
-from spammers that improperly use SMTP command pipelining to speed
-up their deliveries.
-
-- Postfix "sendmail" now issues a warning and drops privileges if
-installed set-uid root.
-
-- No more duplicate delivery when "postfix reload" is immediately
-followed by "sendmail -q".
-
-- No more "invalid argument" errors when a Postfix daemon opens a
-DB/DBM file while some other process is changing the file.
-
-- Portability to the Mac OS X Server, Reliant Unix, AIX 3.2.5 and
-Ultrix 4.3.
-
-Incompatible changes with postfix-19990601:
-===========================================
-
-- The SMTP server now delays all UCE restrictions until the RCPT
-TO, VRFY or ETRN command. This makes the restrictions more useful,
-because many SMTP clients do not expect negative responses earlier
-in the protocol.  In order to restore the old behavior, specify
-"smtpd_delay_reject = no" in /etc/postfix/main.cf.
-
-- The Postfix local delivery agent no longer automatically propagates
-address extensions to aliases/include/forward addresses.  Specify
-"propagate_unmatched_extensions = canonical, virtual, alias, forward,
-include" to restore the old behavior.
-
-- The Postfix local delivery agent no longer does $name expansion
-on words found in the mailbox_command configuration parameter. This
-makes it easier to specify shell syntax. See conf/main.cf.
-
-- The luser_relay syntax has changed. You can specify one address;
-it is subjected to $user, etc. expansions. See conf/main.cf.
-
-- File system reorganization: daemon executables are now in the
-libexec subdirectory, command executables in the bin subdirectory.
-The INSTALL instructions now recommend installing daemons and
-commands into separate directories.
-
-Major changes with postfix-19990601:
-=====================================
-
-- New USER, EXTENSION, LOCAL, DOMAIN and RECIPIENT environment
-variables for delivery to command (including mailbox_command) by
-the local delivery agent. As you might expect, the information is
-censored. The list of acceptable characters is specified with the
-command_expansion_filter configuration parameter.  Unacceptable
-characters are replaced by underscores. See html/local.8.html.
-
-- Specify "forward_path = /var/forward/$user" to avoid looking up
-.forward files in user home directories.  The default value is
-$home/.forward$recipient_delimiter$extension, $home/.forward.
-Initial code by Philip A.  Prindeville, Mirapoint, Inc., USA.
-
-- Conditional $name expansion in forward_path and luser_relay.
-Available names are: $user (bare user name) $shell (user login
-shell), $home (user home directory), $local (everything to the left
-of @), $extension (optional address extension), $domain (everything
-to the right of @), $recipient (the complete address) and
-$recipient_delimiter.  A simple $name expands as usual.  ${name?value}
-expands to value when $name is defined.  ${name:value} expands to
-value when $name is not defined. With ${name?value} and ${name:value},
-the value is subject to another iteration of $name expansion.
-
-- POSIX regular expression support, enabled by default on 4.4BSD,
-LINUX, HP-UX, and Solaris 2.5 and later. See conf/sample-regexp.cf.
-Initial code by Lamont Jones, Hewlett-Packard, borrowing heavily
-from the PCRE implementation by Andrew McNamara, connect.com.au
-Pty. Ltd., Australia.
-
-- Regular expression checks for message headers.  This requires
-support for POSIX or for PCRE regular expressions.  Specify
-"header_checks = regexp:/file/name" or "header_checks = pcre:/file/name",
-and specify "/^header-name:  badstuff/ REJECT" in the pattern file
-(patterns are case-insensitive by default).  Code by Lamont Jones,
-Hewlett-Packard.  It is to be expected that full content filtering
-will be delegated to an external command.
-
-- Regular expression support for all lookup tables, including access
-control (full mail addresses only), address rewriting (canonical/virtual,
-full mail addresses only) and transport tables (full domain names
-only).  However, regular expressions are not allowed for aliases,
-because that would open up security exposures.
-
-- Automatic detection of changes to DB or DBM lookup tables.  This
-eliminates the need to run "postfix reload" after each change to
-the SMTP access table, or to the canonical, virtual, transport or
-aliases tables.
-
-- New error mailer. Specify ".domain.name error:domain is undeliverable"
-in the transport table to bounce mail for entire domains.
-
-- No more Postfix lockups on Solaris (knock on wood). The code no
-longer uses Solaris UNIX-domain sockets, because they are still
-broken, even with Solaris 7.
-
-- Workaround for the Solaris mailtool, which keeps an exclusive
-kernel lock on the mailbox while its window is not iconified (specify
-"sun_mailtool_compatibility = yes" in main.cf).
-
-- Questionable workaround for Solaris, which reportedly loses
-long-lived exclusive locks that are held by the master daemon.
-
-- New reject_unknown_{sender,recipient}_domain restrictions for
-sender and recipient mail addresses that distinguish between soft
-errors (always 450) and hard errors (unknown_address_reject_code,
-default 450).
-
-- MIME-encapsulated bounce messages, making it easier to recover
-bounced mail. Initial implementation by Philip A.  Prindeville,
-Mirapoint, Inc., USA. Support for RFC 1892 (multipart/report) and
-RFC 1894 (DSN) will have to wait until Postfix internals have been
-revised to support RFC 1893.
-
-- Separately configurable "postmaster" addresses for single bounces
-(bounce_notice_recipient), double bounces (2bounce_notice_recipient),
-delayed mail (delay_notice_recipient), and for mailer error reports
-(error_notice_recipient). See conf/main.cf.
-
-- Questionable feature: specify "best_mx_transport = local" if
-this machine is the best MX host for domains not in mydestinations.
-
-Incompatible changes with postfix-19990317:
-===========================================
-
-- You MUST install the new version of /etc/postfix/postfix-script.
-
-- The pipe mailer "flags" syntax has changed. You now explicitly
-MUST specify the R flag in order to generate a Return-Path:  message
-header (as needed by, for example, cyrus).
-
-Major changes with postfix-19990317:
-====================================
-
-A detailed record of changes is given in the HISTORY file.
-
-- Less postmaster mail. Undeliverable bounce messages (double
-bounces) are now discarded. Specify "notify_classes = 2bounce..."
-to get copies of double bounces. Specify "notify_classes = bounce..."
-to get copies of normal and double bounces.
-
-- Improved LDAP client code by John Hensley of Merit Network, USA.
-See LDAP_README for details.
-
-- Perl-compatible regular expression support for lookup maps by
-Andrew McNamara, connect.com.au Pty. Ltd., Australia..  Example:
-"check_recipient_access pcre:/etc/postfix/sample-pcre.cf". Regular
-expressions provide a powerful tool not only for SMTP access control
-but also for address rewriting. See PCRE_README for details.
-
-- Automatic notification of delayed mail (disabled by default).
-With "delay_warning_time = 4", Postfix informs senders when mail
-has not been delivered after 4 hours. Initial version of the code
-by Daniel Eisenbud, University of California at Berkeley. In order
-to get postmaster copies of such warnings, specify "notify_classes
-= delay...".
-
-- More configurable local delivery: "mail_spool_directory" to
-specify the UNIX mail spool directory; "mailbox_transport" to
-delegate all mailbox delivery to, for example, cyrus, and
-"fallback_transport" to delegate delivery of only non-UNIX users.
-And all this without losing local aliases and local .forward
-processing.  See config/main.cf and config/master.cf.
-
-- Several changes to improve Postfix behavior under worst-case
-conditions (frequent Postfix restarts/reloads combined with lots
-if inbound mail, intermittent connectivity problems, SMTP servers
-that become comatose after receiving QUIT).
-
-- More NFS-friendly mailbox delivery. The local delivery agent
-now avoids using root privileges where possible.
-
-- For sites that do not receive mail at all, mydestination can now
-be an empty string. Be sure to set up a transport table entry to
-prevent mail from looping.
-
-- New "postsuper" utility to clean up stale files from Postfix
-queues.
-
-- Workaround for BSD select() collisions that cause performance
-problems on large BSD systems.
-
-- Several questionable but useful features to capture mail:
-"always_bcc = address" to capture a copy of every message that
-enters the system, and "luser_relay = address" to capture mail for
-unknown recipients (does not work when mailbox_transport or
-fallback_transport are being used).
-
-- Junk mail controls: new reject_non_fqdn_{hostname,sender,recipient}
-restrictions to reject non-FQDN arguments in HELO, MAIL FROM and
-RCPT TO commands, and stricter checking of numeric HELO arguments.
-
-- "fallback_relay" feature for sites that use DNS but that can't
-talk to the entire world. The fall-back relay gets the mail when
-a destination is not found in the DNS or when the destination is
-found but not reachable.
-
-- Several questionable controls that can help to keep mail going:
-specify "smtp_skip_4xx_greeting = yes" to skip SMTP servers that
-greet with 4XX, "ignore_mx_lookup_error = yes" to look up an A
-record when a DNS server does not respond to an MX query.
-
-Incompatible changes with postfix-beta-19990122-pl01:
-=====================================================
-
-None.
-
-Major changes with postfix-beta-19990122-pl01:
-==============================================
-
-- Restrict who may use ETRN and what domains may be specified.
-Example:  "smtpd_etrn_restrictions = permit_mynetworks, reject".
-
-- BIFF notifications.  For compatibility reasons this feature is
-on by default.  Specify "biff = no" in main.cf if your machine has
-lots of shell users.
-
-- With "soft_bounce = yes", defer delivery instead of bouncing
-mail. This is a safety net for configuration errors with delivery
-agents. It has no effect on errors in virtual maps, canonical maps,
-or in junk mail restrictions.
-
-- Specify "owner_request_special = no" to turn off special treatment
-of owner-foo and foo-request addresses.
-
-Incompatible changes with postfix-beta-19990122:
-================================================
-
-- The syntax of the transport table has changed. An entry like:
-
-       customer.org    smtp:[gateway.customer.org]
-
-  no longer forwards mail for anything.customer.org. For that you
-  need to specify:
-
-       customer.org    smtp:[gateway.customer.org]
-       .customer.org   smtp:[gateway.customer.org]
-
-  This change makes transport tables more compatible with
-  sendmail mailer tables.
-
-- The format of syslog records has changed. A client is now always
-logged as hostname[address]; the pickup daemon logs queue file uid
-and sender address.
-
-Major changes with postfix-beta-19990122:
-=========================================
-
-- Junk mail restrictions can now be postponed to the RCPT TO command.
-Specify: "smtpd_recipient_restrictions = reject_maps_rbl...".
-
-- More flexible interface for delivery to e.g., cyrus IMAP without
-need for PERL scripts to munge recipient addresses. In addition to
-$sender, $nexthop and $recipient, the pipe mailer now also supports
-$user, $extension and $mailbox.
-
-- New mail now has precedence over deferred mail, plus some other
-tweaks to make bulk mail go faster. But it ain't no cure for massive
-network outages.
-
-- Watchdog timer for systems that cause the Postfix queue manager
-to lock up, so it recovers without human intervention.
-
-- Delivery to qmail-style maildir files, which is good for NFS
-environments.  Specify "home_mailbox = Maildir/", or specify
-/file/name/ in aliases or in .forward files. The trailing / is
-required to turn on maildir delivery.
+New sender address verification blocks mail from addresses that
+are not deliverable.  This is turned on with the reject_unverified_sender
+UCE restriction. Addresses are verified by probing, that is, by
+sending mail that is not actually delivered (SMTP interruptus).
+Detailed information is in the SENDER_VERIFICATION_README file
+and sample-verify.cf.
 
-- Incremental updates of aliases and maps. Specify "postmap -i
-mapname" and it will read new entries from stdin.
+Address verification uses the new "verify" daemon that maintains
+a database. The necessary entry is automatically added to master.cf
+when you upgrade.
 
-- Newaliases will now update more than one alias database.
-Specify the names with the main.cf "alias_database" parameter.
+New "sendmail -bv" option. Postfix probes the specified recipient
+addresses without actually delivering mail, and sends back an email
+delivery report.  This is useful for testing address rewriting and
+address routing of both envelope and header addresses. This feature
+currently does not access or update the sender address verification
+database.
 
-- Address masquerading exceptions to prevent users from being
-masqueraded. Specify "masquerade_exceptions = root".
+Improved "sendmail -v" behavior. Postfix delivers mail as usual,
+and emails a report of all the delivery attempts to the originator.
 
-- A pipelined SMTP client. Deliveries to Postfix, qmail, LSOFT,
-zmailer, and exim (once it's fixed) speed up by some 30% for short
-messages with one recipient, with more for multi-recipient mails.
+Bounce reports now show the original recipient information in
+addition to the final recipient that was already available.
 
-- Hook for local delivery to "|command" via the smrsh restricted
-shell, to restrict what commands may be used in .forward etc. files.
-Specify "local_command_shell = /some/where/smrsh -c".
+Both "sendmail -bv" and "sendmail -v" use the new "trace" daemon
+that is automatically added to master.cf when you upgrade.
diff --git a/postfix/RELEASE_NOTES-1.1 b/postfix/RELEASE_NOTES-1.1
new file mode 100644 (file)
index 0000000..c6f4611
--- /dev/null
@@ -0,0 +1,1087 @@
+In the text below, incompatible changes are labeled with the Postfix
+snapshot that introduced the change. If you upgrade from a later
+Postfix version, then you do not have to worry about that particular
+incompatibility.
+
+Official Postfix releases are called a.b.c where a=major release
+number, b=minor release number, c=patchlevel.  Snapshot releases
+are now called a.b.c-yyyymmdd where yyyymmdd is the release date
+(yyyy=year, mm=month, dd=day).  The mail_release_date configuration
+parameter contains the release date (both for official release and
+snapshot release).  Patches change the patchlevel and the release
+date. Snapshots change only the release date, unless they include
+the same bugfixes as a patch release.
+
+Incompatible changes with Postfix version 1.1.0 (released 20020117)
+===================================================================
+
+Changes are listed in order of decreasing importance, not release
+date.
+
+[snapshot-20010709] This release introduces a new queue file record
+type that is used only for messages that actually use VERP (variable
+envelope return path) support.  With this sole exception, the queue
+file format is entirely backwards compatible with the previous
+official Postfix release (20010228, a.k.a. Postfix 1.0.0).
+
+[snapshot-20020106] This release modifies the existing master.cf
+file. The local pickup service is now unprivileged, and the cleanup
+and flush service are now "public". Should you have to back out to
+a previous release, then you must 1) edit the master.cf file, make
+the pickup service "privileged", and make the cleanup and flush
+services "private"; 2) "chmod 755 /var/spool/postfix/public".  To
+revert to a world-writable mail submission directory, "chmod 1733
+/var/spool/postfix/maildrop".
+
+[snapshot-20020106, snapshot-20010808, snapshot-20011103,
+snapshot-20011121] You must stop and restart Postfix because of
+incompatible changes in the local Postfix security model and in
+the Postfix internal protocols. Old and new components will not
+work together.
+
+[snapshot-20020106] Simpler local Postfix security model.
+
+- No world-writable maildrop directory. Postfix now always uses
+  the set-gid postdrop command for local mail submissions.  The
+  local mail pickup daemon is now an unprivileged process.
+
+- No world-accessible pickup and queue manager server FIFOs.
+
+- New set-gid postqueue command for the queue list/flush operations
+  that used to implemented by the Postfix sendmail command.
+
+[snapshot-20020106..15] Simpler Postfix installation and upgrading.
+
+- All installation settings are now kept in the main.cf file, and
+  better default settings are now generated for system dependent
+  pathnames such as sendmail_path etc. The install.cf file is no
+  longer used, except when upgrading from an older Postfix version.
+
+- Non-default installation parameter settings can (but do not have
+  to) be specified on the "make install" or "make upgrade" command
+  line as name=value arguments.
+
+- New postfix-files database (in /etc/postfix) with (pathname,
+  owner, permission) information about all Postfix-related files.
+
+- New postfix-install script replaces the awkward INSTALL.sh script.
+  This is driven by the postfix-files database. It has better
+  support for building packages for distribution to other systems.
+  See PACKAGE_README for details.
+
+- New post-install script (in /etc/postfix) for post-installation
+  maintenance of directory/file permissions and ownership (this is
+  used by "postfix check"). Example:
+
+    # postfix stop
+    # post-install set-permissions mail_owner=username setgid_group=groupname
+    # postfix start
+
+[snapshot-20020106] Postfix will not run if it detects that the
+postfix user or group ID are shared with other accounts on the
+system. The checks aren't exhaustive (that would be too resource
+consuming) but should be sufficient to encourage packagers and
+developers to do the right thing. To fix the problem, use the above
+post-install command, after you have created the appropriate new
+mail_owner or setgid_group user or group IDs.
+
+[snapshot-20020106] If you run multiple Postfix instances on the
+same machine you now have to specify their configuration directories
+in the default main.cf file as "alternate_config_directories =
+/dir1 /dir2 ...".  Otherwise, some Postfix commands will no longer
+work: the set-group ID postdrop command for mail submission and
+the set-group ID postqueue command for queue listing/flushing.
+
+[snapshot-20010808] The default setting for the maps_rbl_domains
+parameter is now "empty", because mail-abuse.org has become a
+subscription-based service. The names of the RBL parameters haven't
+changed.
+
+[snapshot-20020106] Postfix SMTP access maps will no longer return
+OK for non-local multi-domain recipient mail addresses (user@dom1@dom2,
+user%dom1@dom2, etcetera); the lookup now returns DUNNO (undetermined).
+Non-local multi-domain recipient addresses were already prohibited
+from matching the permit_mx_backup and the relay_domains-based
+restrictions.
+
+[snapshot-20011210] Stricter checking of Postfix chroot configurations.
+The Postfix startup procedure now warns if "system" directories
+(etc, bin, lib, usr) under the Postfix top-level queue directory
+are not owned by the super-user (usually the result of well-intended,
+but misguided, applications of "chown -R postfix /var/spool/postfix).
+
+[snapshot-20011008] The Postfix SMTP server now rejects requests
+with a generic "try again later" status (451 Server configuration
+error) when it detects an error in smtp_{client, helo, sender,
+recipient, etrn}_restrictions settings.  More details about the
+problem are logged to the syslogd; sending such information to
+random clients would be inappropriate.
+
+[snapshot-20011008] Postfix no longer flushes the entire mail queue
+after receiving an ETRN request for a random domain name. Requests
+for domains that do not match $fast_flush_domains are now rejected
+instead.
+
+[snapshot-20011226] Postfix configuration file comments no longer
+continue on the next line when that next line starts with whitespace.
+This change avoids surprises, but it may cause unexpected behavior
+with existing, improperly formatted, configuration files. Caveat
+user. Comment lines are allowed to begin with whitespace. Multi-line
+input is no longer terminated by a comment line, by an all whitespace
+line, or by an empty line.
+
+[snapshot-20010714] Postfix delivery agents now refuse to create
+a missing maildir or mail spool subdirectory when its parent
+directory is world writable.  This is necessary to prevent security
+problems with maildirs or with hashed mailboxes under a world
+writable mail spool directory.
+
+[snapshot-20010525] As per RFC 2821, the Postfix SMTP client now
+always sends EHLO at the beginning of an SMTP session. Specify
+"smtp_always_send_ehlo = no" for the old behavior, which is to send
+EHLO only when the server greeting banner contains the word ESMTP.
+
+[snapshot-20010525] As per RFC 2821, an EHLO command in the middle
+of an SMTP session resets the Postfix SMTP server state just like
+RSET. This behavior cannot be disabled.
+
+[snapshot-20010709] The SMTP client now by default breaks lines >
+2048 characters, to avoid mail delivery problems with fragile SMTP
+server software.  To get the old behavior back, specify "smtp_break_lines
+= no" in the Postfix main.cf file.
+
+[snapshot-20010709] With recipient_delimiter=+ (or any character
+other than -) Postfix will now recognize address extensions even
+with owner-foo+extension addresses. This change was necessary to
+make VERP useful for mailing list bounce processing.
+
+[snapshot-20010610] The Postfix pipe delivery agent no longer
+automatically case-folds the expansion of $user, $extension or
+$mailbox command-line macros.  Specify the 'u' flag to get the old
+behavior.
+
+[snapshot-20011210] The Postfix sendmail command no longer exits
+with status 1 when mail submission fails, but instead returns a
+sendmail-compatible status code as defined in /usr/include/sysexits.h.
+
+Major changes with Postfix version 1.1.0 (Released 20020117)
+============================================================
+
+Changes are listed in order of decreasing importance, not release
+date.
+
+The nqmgr queue manager is now bundled with Postfix. It implements
+a smarter scheduling strategy that allows ordinary mail to slip
+past mailing list mail, resulting in better response. This queue
+manager is expected to become the default queue manager shortly.
+
+[snapshot-20010709, snapshot-20010808] VERP (variable envelope
+return path) support.  This is enabled by default, including in
+the SMTP server. See the VERP_README file for instructions.  Specify
+"disable_verp_bounces = yes" to have Postfix send one RFC-standard,
+non-VERP, bounce report for multi-recipient mail, even when VERP
+style delivery was requested.  This reduces the explosive behavior
+of bounces when sending mail to a list.
+
+[snapshot-20010709] QMQP server support, so that Postfix can be
+used as a backend mailer for the ezmlm-idx mailing list manager.
+You still need qmail to drive ezmlm and to process mailing list
+bounces. The QMQP service is disabled by default. To enable, follow
+the instructions in the QMQP_README file.
+
+[snapshot-20010709] You can now reject unknown virtual(8) recipients
+at the SMTP port by specifying a "domain.name whatever" entry in
+the tables specified with virtual_mailbox_maps, similar to Postfix
+virtual(5) domains.  [virtual(8) is the Postfix virtual delivery
+agent, virtual(5) is the Postfix virtual map. The two implement
+virtual domains in a very different manner.]
+
+[snapshot-20011121] Configurable host/domain name wildcard matching
+behavior: choice between "pattern `domain.name' matches string
+`host.domain.name'" (this is to be deprecated in the future) and
+"pattern `.domain.name' matches string `host.domain.name'" (this
+is to be preferred in the future).  The configuration parameter
+"parent_domain_matches_subdomains" specifies which Postfix features
+use the behavior that will become deprecated.
+
+[snapshot-20010808] Variable coupling between message receiving
+rates and message delivery rates. When the message receiving rate
+exceeds the message delivery rate, an SMTP server will pause for
+$in_flow_delay seconds before accepting a message.  This delay
+gives Postfix a chance catch up and access the disk, while still
+allowing new mail to arrive.  This feature currently has effect
+only when mail arrives via a small number of SMTP clients.
+
+[snapshot-20010610, snapshot-20011121, snapshot-20011210] Workarounds
+for a bug in old versions of the CISCO PIX firewall software that
+caused mail to be resent repeatedly.  The workaround has no effect
+for other mail deliveries. The workaround is turned off when mail
+is queued for less than $smtp_pix_workaround_threshold_time seconds
+(default:  500 seconds) so that the workaround is normally enabled
+only for deferred mail.  The delay before sending .<CR><LF> is now
+controlled by the $smtp_pix_workaround_delay_time setting (default:
+10 seconds).
+
+[snapshot-20011226] Postfix will now do null address lookups in
+SMTPD access maps.  If your access maps cannot store or look up
+null string key values, specify "smtpd_null_access_lookup_key =
+<>" and the null sender address will be looked up as <> instead.
+
+[snapshot-20011210] More usable virtual delivery agent, thanks to
+a new "static" map type by Jeff Miller that always returns its map
+name as the lookup result. This eliminates the need for per-recipient
+user ID and group ID tables.  See the VIRTUAL_README file for more
+details.
+
+[snapshot-20011125] Anti-sender spoofing. New main.cf parameter
+smtpd_sender_login_maps that specifies the (SASL) login name that
+owns a MAIL FROM sender address.  Specify a regexp table in order
+to require a simple one-to-one mapping.  New SMTPD restriction
+reject_sender_login_mismatch that refuses a MAIL FROM address when
+$smtpd_sender_login_maps specifies an owner but the client is not
+(SASL) logged in as the MAIL FROM address owner, or when a client
+is (SASL) logged in but does not own the address according to
+$smtpd_sender_login_maps.
+
+[snapshot-20011121] The mailbox_command_maps parameter allows you
+to configure the external delivery command per user (local delivery
+agent only).  This feature has precedence over the mailbox_command
+and home_mailbox settings.
+
+[snapshot-20011121] New "warn_if_reject" smtpd UCE restriction that
+only warns if the restriction that follows would reject mail.  Look
+for file records that contain the string "reject_warning".
+
+[snapshot-20011127] New header/body_check result "WARN" to make
+Postfix log a warning about a header/body line without rejecting
+the content.
+
+[snapshot-20011103] In header/body_check files, REJECT can now be
+followed by text that is sent to the originator. That feature was
+stuck waiting for years, pending the internal protocol revision.
+
+[snapshot-20011008] The permit_mx_backup feature allows you to
+specify network address blocks via the permit_mx_backup_networks
+parameter.  This requires that the primary MX hosts for the given
+destination match the specified network blocks. When no value is
+given for permit_mx_backup_networks, Postfix will accept mail
+whenever the local MTA is listed in the DNS as an MX relay host
+for a destination, even when you never gave permission to do so.
+
+[snapshot-20010709] Specify "mail_spool_directory = /var/mail/"
+(note the trailing "/" character) to enable maildir format for
+/var/mail/username.
+
+[snapshot-20010808] Finer control over address masquerading. The
+masquerade_classes parameter now controls header and envelope sender
+and recipient addresses.  With earlier Postfix versions, address
+masquerading rewrote all addresses except for the envelope recipient.
+
+[snapshot-20010610] The pipe mail delivery agent now supports proper
+quoting of white space and other special characters in the expansions
+of the $sender and $recipient command-line macros. This was necessary
+for correct operation of the "simple" content filter, and is also
+recommended for delivery via UUCP or BSMTP.
+
+[snapshot-20010610] The pipe mail delivery agent now supports case
+folding the localpart and/or domain part of expansions of the
+$nexthop, $recipient, $user, $extension or $mailbox command-line
+macros. This is recommended for mail delivery via UUCP. Bug: $nexthop
+is always case folded because of problems in the queue manager
+code.
+
+[snapshot-20010525] This release contains many little revisions of
+little details in the light of the new RFC 2821 and RFC 2822
+standards. Changes that may affect interoperability are listed
+above under "incompatible changes".  Other little details are
+discussed in comments in the source code.
+
+[snapshot-20010502] The Postfix SMTP client now by default randomly
+shuffles destination IP addresses of equal preference (whether
+obtained via MX lookup or otherwise). Reportedly, this is needed
+for sites that use Bernstein's dnscache program. Specify
+"smtp_randomize_addresses = no" to disable this behavior. Based on
+shuffling code by Aleph1.
+
+[snapshot-20011127] New parameter smtpd_noop_commands to specify
+a list of commands that the Postfix SMTP server treats as NOOP
+commands (no syntax check, no state change). This is a workaround
+for misbehaving clients that send unsupported commands such as
+ONEX.
+
+[snapshot-20010502] "postmap -q -" and "postmap -d -" read key
+values from standard input, which makes it easier to drive them
+from another program.  The same feature was added to the postalias
+command.
+
+[snapshot-20010502] The postsuper command now has a command-line
+option to delete queue files.  In principle this command can be
+used while Postfix is running, but there is a possibility of deleting
+the wrong queue file when Postfix deletes a queue file and reuses
+the queue ID for a new message.  In that case, postsuper will delete
+the new message.
+
+[snapshot-20010525] The postsuper queue maintenance tool now renames
+files whose name (queue ID) does not match the message file inode
+number. This is necessary after a Postfix mail queue is restored
+from another machine or from backups.  The feature is selected with
+the -s option, which is the default, and runs whenever Postfix is
+started.
+
+[snapshot-20010525] The postsuper queue maintenance tool has a new
+-r (requeue) option for subjecting some or all queue files to
+another iteration of address rewriting. This is useful after the
+virtual or canonical maps have changed.
+
+[snapshot-20010525] The postsuper queue maintenance tool was extended
+with options to read queue IDs from standard input. This makes the
+tool easier to drive from scripts.
+
+[snapshot-20010329] Better support for running multiple Postfix
+instances on one machine. Each instance can be recognized by its
+logging (defaults:  "syslog_name = postfix", "syslog_facility =
+mail").
+
+Major incompatible changes with release-20010228 Patch 01 (a.k.a. Postfix 1.0.1)
+================================================================================
+
+This release changes the names of the "fast ETRN" logfiles with
+delayed mail per destination. These files are maintained by the
+Postfix "fast flush" daemon. The old scheme failed with addresses
+of the form user@[ip.address] and user@a.domain.name.  In order to
+populate the new "fast ETRN" logfiles, execute the command "sendmail
+-q".  The old "fast ETRN" logfiles go away by themselves (default:
+after 7 days).
+
+Major incompatible changes with release-20010228 (a.k.a. Postfix 1.0.0)
+=======================================================================
+
+[snapshot-20010225] POSTFIX NO LONGER RELAYS MAIL FOR CLIENTS IN
+THE ENTIRE CLASS A/B/C NETWORK. To get the old behavior, specify
+"mynetworks_style = class" in the main.cf file. The default
+(mynetworks_style = subnet) is to relay for clients in the local
+IP subnet. See conf/main.cf.
+
+[snapshot-20001005, snapshot-20010225] You must execute "postfix
+stop" before installing this release.  Some recommended parameter
+settings have changed, and a new entry must be added to the master.cf
+file before you can start Postfix again.
+
+1 - The recommended Postfix configuration no longer uses flat
+    directories for the "incoming" "active", "bounce", and "defer"
+    queue directories.  The "flush" directory for the new "flush"
+    service directory should not be flat either.
+
+    Upon start-up, Postfix checks if the hash_queue_names configuration
+    parameter is properly set up, and will add any queue directory
+    names that are missing.
+
+2 - In order to improve performance of one-to-one mail deliveries
+    the queue manager will now look at up to 10000 queue files
+    (was: 1000).  The default qmgr_message_active_limit setting
+    was changed accordingly.
+
+    If you have a non-default qmgr_message_active_limit in main.cf,
+    you may want adjust it.
+
+3 - The new "flush" service needs to be configured in master.cf.
+
+    Upon start-up, Postfix checks if the new "flush" service is
+    configured in the master.cf file, and will add an entry if it
+    is missing.
+
+Should you wish to back out to a previous Postfix release there is
+no need to undo the above queue configuration changes.
+
+[snapshot-20000921] The protocol between queue manager and delivery
+agents has changed.  This means that you cannot mix the Postfix
+queue manager or delivery agents with those of Postfix versions
+prior to 20000921. This change does not affect Postfix queue file
+formats.
+
+[snapshot-20000529] This release introduces an incompatible queue
+file format change ONLY when content filtering is enabled (see text
+in FILTER_README). Old Postfix queue files will work fine, but
+queue files with the new content filtering info will not work with
+Postfix versions before 20000529.  Postfix logs a warning and moves
+incompatible queue files to the "corrupt" mail queue subdirectory.
+
+Minor incompatible changes with release-20010228
+================================================
+
+[snapshot-20010225] The incoming and deferred queue directories
+are now hashed by default.  This improves the performance considerably
+under heavy load, at the cost of a small but noticeable slowdown
+when one runs "mailq" on an unloaded system.
+
+[snapshot-20010222] Postfix no longer automatically delivers
+recipients one at a time when their domain is listed in $mydestination.
+This change solves delivery performance problems with delivery via
+LMTP, with virus scanning, and with firewall relays that forward
+all mail for $mydestination to an inside host.
+
+The "one recipient at a time" delivery behavior is now controlled
+by the per-transport recipient limit (xxx_destination_recipient_limit,
+where xxx is the name of the delivery mechanism).  This parameter
+controls the number of recipients that can be sent in one delivery
+(surprise).
+
+The setting of the per-transport recipient limit also controls the
+meaning of the per-transport destination concurrency limit (named
+xxx_destination_concurrency_limit, where xxx is again the name of
+the delivery mechanism):
+
+ 1) When the per-transport recipient limit is 1 (i.e., send one
+    recipient per delivery), the per-transport destination concurrency
+    limit controls the number of simultaneous deliveries to the
+    same recipient.  This is the default behavior for delivery via
+    the Postfix local delivery agent.
+
+ 2) When the per-transport recipient limit is > 1 (i.e., send
+    multiple recipients per delivery), the per-transport destination
+    concurrency limit controls the number of simultaneous deliveries
+    to the same domain.  This is the default behavior for all other
+    Postfix delivery agents.
+
+[snapshot-20010128] The Postfix local delivery agent now enforces
+mailbox file size limits (default: mailbox_size_limit = 51200000).
+This limit affects all file write access by the local delivery
+agent or by a process run by the local delivery agent. The purpose
+of this parameter is to act as a safety for run-away software. It
+cannot be a substitute for a file quota management system. Specify
+a limit of 0 to disable.
+
+[snapshot-20010128] REJECT in header/body_checks is now flagged as
+policy violation rather than bounce, for consistency in postmaster
+notifications.
+
+[snapshot-20010128] The default RBL (real-time blackhole lists)
+domain examples have been changed from *.vix.com to *.mail-abuse.org.
+
+[snapshot-20001210] Several interfaces of libutil and libglobal
+routines have changed.  This may break third-party code written
+for Postfix. In particular, the safe_open() routine has changed,
+the way the preferred locking method is specified in the sys_defs.h
+file, as well as all routines that perform file locking. When
+compiling third-party code written for Postfix, the incompatibilities
+will be detected by the compiler provided that #include file
+dependencies are properly maintained.
+
+[snapshot-20001210] When delivering to /file/name (as directed in
+an alias or .forward file), the local delivery agent now logs a
+warning when it is unable to create a /file/name.lock file. Mail
+is still delivered as before.
+
+[snapshot-20001210] The "sun_mailtool_compatibility" feature is
+going away (a compatibility mode that turns off kernel locks on
+mailbox files). It still works, but a warning is logged. Instead
+of using "sun_mailtool_compatibility", specify the mailbox locking
+strategy as "mailbox_delivery_lock = dotlock".
+
+[snapshot-20001210] The Postfix SMTP client now skips SMTP server
+replies that do not start with "CODE SPACE" or with "CODE HYPHEN"
+and flags them as protocol errors. Older Postfix SMTP clients
+silently treated "CODE TEXT" as "CODE SPACE TEXT", i.e. as a valid
+SMTP reply.
+
+[snapshot-20001121] On RedHat Linux 7.0, you must install the
+db3-devel RPM before you can compile the Postfix source code.
+
+[snapshot-20000924] The postmaster address in the "sorry" text at
+the top of bounced mail is now just postmaster, not postmaster@machine.
+The idea is to refer users to their own postmaster.
+
+[snapshot-20000921] The notation of [host:port] in transport tables
+etc. is going away but it is still supported. The preferred form
+is now [host]:port.  This change is necessary to support IPV6
+address forms which use ":" as part of a numeric IP address. In a
+future release, Postfix will log a warning when it encounters the
+[host:port] form.
+
+[snapshot-20000921] In mail headers, Errors-To:, Reply-To: and
+Return-Receipt:  addresses are now rewritten as a sender address
+(was: recipient).
+
+[snapshot-20000921] Postfix no longer inserts Sender: message
+headers.
+
+[snapshot-20000921] The queue manager now logs the original number
+of recipients when opening a queue file (example: from=<>, size=3502,
+nrcpt=1).
+
+[snapshot-20000921] The local delivery agent no longer appends a
+blank line to mail that is delivered to external command.
+
+[snapshot-20000921] The pipe delivery agent no longer appends a
+blank line when the F flag is specified (in the master.cf file).
+Specify the B flag if you need that blank line.
+
+[snapshot-20000507] As required by RFC 822, Postfix now inserts a
+generic destination message header when no destination header is
+present.  The text is specified via the undisclosed_recipients_header
+configuration parameter (default:  "To: undisclosed-recipients:;").
+
+[snapshot-20000507] The Postfix sendmail command treats a line with
+only `.' as the end of input, for the sake of sendmail compatibility.
+To disable this feature, specify the sendmail-compatible `-i' or
+`-oi' flags on the sendmail command line.
+
+[snapshot-20000507] For the sake of Sendmail compatibility, the
+Postfix SMTP client skips over SMTP servers that greet with a 4XX
+or 5XX reply code, treating them as unreachable servers.  To obtain
+prior behavior (4XX=retry, 5XX=bounce), specify "smtp_skip_4xx_greeting
+= no" and "smtp_skip_5xx_greeting = no".
+
+Major changes with release-20010228
+===================================
+
+Postfix produces DSN formatted bounced/delayed mail notifications.
+The human-readable text still exists, so that users will not have
+to be unnecessarily confused by all the ugliness of RFC 1894.  Full
+DSN support will be later.
+
+This release introduces full content filtering through an external
+process. This involves an incompatible change in queue file format.
+Mail is delivered to content filtering software via an existing
+mail delivery agent, and is re-injected into Postfix via an existing
+mail submission agent.  See examples in the FILTER_README file.
+Depending on how the filter is implemented, you can expect to lose
+a factor of 2 to 4 in delivery performance of SMTP transit mail,
+more if the content filtering software needs lots of CPU or memory.
+
+Specify "body_checks = regexp:/etc/postfix/body_checks" for a quick
+and dirty emergency content filter that looks at non-header lines
+one line at a time (including MIME headers inside the message body).
+Details in conf/sample-filter.cf.
+
+The header_checks and body_checks features can be used to strip
+out unwanted data. Specify IGNORE on the right-hand side and the
+data will disappear from the mail.
+
+Support for SASL (RFC 2554) authentication in the SMTP server and
+in the SMTP and LMTP clients. See the SASL_README file for more
+details. This file still needs better examples.
+
+Postfix now ships with an LMTP delivery agent that can deliver over
+local/remote TCP sockets and over local UNIX-domain sockets.  The
+LMTP_README file gives example, but still needs to be revised.
+
+Fast "ETRN" and "sendmail -qR".  Postfix maintains per-destination
+logfiles with information about what mail is queued for selected
+destinations.  See the file ETRN_README for details.
+
+The mailbox locking style is now fully configurable at runtime.
+The new configuration parameter is called "mailbox_delivery_lock".
+Depending on the operating system type, mailboxes can be locked
+with one or more of "flock", "fcntl" or "dotlock".  The command
+"postconf -l" shows the available locking styles.  The default
+mailbox locking style is system dependent.  This change affects
+all mailbox and all "/file/name" deliveries by the Postfix local
+delivery agent.
+
+Minor changes with release-20010228
+===================================
+
+You can now specify multiple SMTP destinations in the relayhost
+and fallback_relay configuration parameters. The destinations are
+tried in the specified order. Specify host or host:port (perform
+MX record lookups), [host] or [host]:port (no MX record lookups),
+[address] or [address]:port (numerical IP address).
+
+The "mailbox_transport" and "fallback_transport" parameters now
+understand the form "transport:nexthop", with suitable defaults
+when either transport or nexthop are omitted, just like in the
+Postfix transport map. This allows you to specify for example,
+"mailbox_transport = lmtp:unix:/file/name".
+
+The local_transport and default_transport configuration parameters
+can now be specified in transport:destination notation, just like
+the mailbox_transport and fallback_transport parameters.  The
+:destination part is optional.  However, these parameters take only
+one destination, unlike relayhost and fallback-relay which take
+any number of destinations.
+
+More general virtual domain support.  Postfix now supports both
+Sendmail-style virtual domains and Postfix-style virtual domains.
+Details and examples are given in the revised virtual manual page.
+
+- With Sendmail-style virtual domains, local users/aliases/mailing
+  lists are visible as localname@virtual.domain. This is convenient
+  if you want to host mailing lists under virtual domains.
+
+- With Postfix-style virtual domains, local users/aliases/mailing
+  lists are not visible as localname@virtual.domain. Each virtual
+  domain has its own separate name space.
+
+More general "soft bounce" feature.  Specify "soft_bounce = yes"
+in main.cf to prevent the SMTP server from bouncing mail while you
+are testing configurations. Until this release the SMTP server was
+not aware of soft bounces.
+
+Workarounds for non-standard RFC 2554 (AUTH command) implementations.
+Specify "broken_sasl_auth_clients = yes" to enable SMTP server
+support for old Microsoft client applications. The Postfix SMTP
+client supports non-standard RFC 2554 servers by default.
+
+All time-related configuration parameters now accept a one-letter
+suffix to indicate the time unit (s: second, m: minute, h: hour,
+d: day, w: week). The exceptions are the LDAP and MYSQL modules
+which are maintained separately.
+
+New "import_environment" and "export_environment" configuration
+parameters provide explicit control over what environment variables
+Postfix will import, and what environment variables Postfix will
+pass on to a non-Postfix process.
+
+In order to improve performance of one-to-one deliveries, Postfix
+by default now looks at up to 10000 messages at a time (was: 1000).
+
+Specify "syslog_facility = log_local1" etc. to separate the logging
+from multiple Postfix instances. However, a non-default logging
+facility takes effect only after process initialization. Errors
+during command-line parsing are still logged with the default syslog
+facility, as are errors while processing the main.cf file.
+
+Postfix now strips out Content-Length: headers in incoming mail to
+avoid confusion in mail user agents.
+
+Specify "require_home_directory = yes" to prevent mail from being
+delivered to a user whose home directory is not mounted. This
+feature is implemented by the Postfix local delivery agent.
+
+The pipe mailer has a size limit (size=nnn) command-line argument.
+
+The pipe delivery agent has a configurable end-of-line attribute.
+Specify "pipe ... eol=\r\n" for delivery mechanisms that require
+CRLF record delimiters. The eol attribute understands the following
+C-style escape sequences:  \a \b \f \n \r \t \v \nnn \\.
+
+In master.cf you can selectively override main.cf configuration
+parameters, for example: "smtpd -o myhostname=foo.com".
+
+In main.cf, specify "smtp_bind_address=x.x.x.x" to bind SMTP
+connections to a specific local interface. Or override the default
+setting in master.cf with "smtp -o smtp_bind_address=x.x.x.x".
+For now, you must specify a numeric IP address.
+
+Questionable feature: with "smtp_always_send_ehlo = yes", the SMTP
+client sends EHLO regardless of the content of the SMTP server's
+greeting.
+
+Specify "-d key" to postalias or postmap in order to remove one
+key. This still needs to be generalized to multi-key removal (e.g.,
+read keys from stdin).
+
+Comments in Postfix configuration files no longer contain troff
+formatting codes.  The text is now generated from prototype files
+in a new "proto" subdirectory.
+
+Major changes with postfix-19991231:
+====================================
+
+- It is now much more difficult to configure Postfix as an open
+relay. The SMTP server requires that "smtpd_recipient_restrictions"
+contains at least one restriction that by default refuses mail (as
+is the default).  There were too many accidents with changes to
+the UCE restrictions.
+
+- The relay_domains parameter no longer needs to contain $virtual_maps.
+
+- Overhauled FAQ (html/faq.html) with many more examples.
+
+- Updated UCE documentation (html/uce.html) with more examples.
+More UCE configuration examples in sample configuration files.
+
+- Several little improvements to the installation procedure:
+relative symlinks, configurable directory for scratch files so the
+installation can be done without write access to the build tree.
+
+- Updated LDAP client code (John Hensley).
+
+- Updated mysql client code (Scott Cotton).
+
+- The SMTP server now rejects mail for unknown users in virtual
+domains that are defined by Postfix virtual maps.
+
+- The SMTP server can reject mail for unknown local users.  Specify
+"local_recipient_maps = $alias_maps, unix:passwd.byname" if your
+local mail is delivered by a UNIX-style local delivery agent.  See
+example in conf/main.cf.
+
+- Use "disable_vrfy_command = yes" to disable the SMTP VRFY command.
+This prevents some forms of address harvesting.
+
+- The sendmail "-f" option now understands <user> and even understands
+forms with RFC 822-style comments.
+
+- New "qmgr_fudge_factor" parameter allows you to balance mailing
+list performance against response time for one-to-one mail.  The
+fudge factor controls what percentage of delivery resources Postfix
+will devote to one message.  With 100%, delivery of one message
+does not begin before delivery of the previous message is completed.
+This is good for list performance, bad for one-to-one mail. With
+10%, response time for one-to-one mail improves much, but list
+performance suffers: in the worst case, people near the start of a
+mailing list get a burst of postings today, while people near the
+end of the list get that same burst of postings a whole day later.
+
+- It is now relatively safe to configure 550 status codes for the
+main.cf unknown_address_reject_code or unknown_client_reject_code
+parameters.  The SMTP server now always sends a 450 (try again)
+reply code when an UCE restriction fails due to a soft DNS error,
+regardless of what main.cf specifies.
+
+- The RBL checks now show the content of TXT records (Simon J Mudd).
+
+- The Postfix SMTP server now understands a wider range of illegal
+address forms in MAIL FROM and RCPT TO commands. In order to disable
+illegal forms, specify "strict_rfc821_envelopes = yes". This also
+disables support for MAIL FROM and RCPT TO addresses without <>.
+
+- Per-client/helo/sender/recipient UCE restrictions (fully-recursive
+UCE restriction parser). See the RESTRICTION_CLASS file for details.
+
+- Use "postmap -q key" or "postalias -q key" for testing Postfix
+lookup tables or alias files.
+
+- Use "postconf -e name=value..." to edit the main.cf file.  This
+is easier and safer than editing the main.cf file by hand. The
+edits are done on a temporary copy that is renamed into place.
+
+- Use "postconf -m" to display all supported lookup table types
+(Scott Cotton).
+
+- New "permit_auth_destination" UCE restriction for finer-grained
+access control (Jesper Skriver).
+
+Incompatible changes with postfix-19990906
+==========================================
+
+- On systems that use user.lock files to protect system mailboxes
+against simultaneous updates, Postfix now uses /file/name.lock
+files while delivering to files specified in aliases/forward/include
+files. This is a no-op when the recipient lacks directory write
+permission.
+
+- The LDAP client code no longer looks up a name containing "*"
+because it could be abused.  See the LDAP_README file for how to
+restore previous behavior.
+
+- The Postfix to PCRE interface now expects PCRE version 2.08.
+Postfix is no longer compatible with PCRE versions prior to 2.06.
+
+Major changes with postfix-19990906
+===================================
+
+Several bugfixes, none related to security.  See the HISTORY file
+for a complete list of changes.
+
+- Postfix is now distributed under IBM Public License Version 1.0
+which does not carry the controversial termination clause. The new
+license does have a requirement that contributors make source code
+available.
+
+- INSTALL.sh install/upgrade procedure that replaces existing
+programs and shell scripts instead of overwriting them, and that
+leaves existing queue files and configuration files alone.
+
+- The ugly Delivered-To: header can now be turned off selectively.
+The default setting is:  "prepend_delivered_header = command, file,
+forward".  Turning off the Delivered-To:  header when forwarding
+mail is not recommended.
+
+- mysql client support by Scott Cotton and Joshua Marcus, Internet
+Consultants Group, Inc. See the file MYSQL_README for instructions.
+
+- reject_unauth_destination SMTP recipient restriction that rejects
+destinations not in $relay_domains. Unlike the check_relay_domains
+restriction, reject_unauth_destination ignores the client hostname.
+By Lamont Jones of Hewlett-Packard.
+
+- reject_unauth_pipelining SMTP *anything* restriction to stop mail
+from spammers that improperly use SMTP command pipelining to speed
+up their deliveries.
+
+- Postfix "sendmail" now issues a warning and drops privileges if
+installed set-uid root.
+
+- No more duplicate delivery when "postfix reload" is immediately
+followed by "sendmail -q".
+
+- No more "invalid argument" errors when a Postfix daemon opens a
+DB/DBM file while some other process is changing the file.
+
+- Portability to the Mac OS X Server, Reliant Unix, AIX 3.2.5 and
+Ultrix 4.3.
+
+Incompatible changes with postfix-19990601:
+===========================================
+
+- The SMTP server now delays all UCE restrictions until the RCPT
+TO, VRFY or ETRN command. This makes the restrictions more useful,
+because many SMTP clients do not expect negative responses earlier
+in the protocol.  In order to restore the old behavior, specify
+"smtpd_delay_reject = no" in /etc/postfix/main.cf.
+
+- The Postfix local delivery agent no longer automatically propagates
+address extensions to aliases/include/forward addresses.  Specify
+"propagate_unmatched_extensions = canonical, virtual, alias, forward,
+include" to restore the old behavior.
+
+- The Postfix local delivery agent no longer does $name expansion
+on words found in the mailbox_command configuration parameter. This
+makes it easier to specify shell syntax. See conf/main.cf.
+
+- The luser_relay syntax has changed. You can specify one address;
+it is subjected to $user, etc. expansions. See conf/main.cf.
+
+- File system reorganization: daemon executables are now in the
+libexec subdirectory, command executables in the bin subdirectory.
+The INSTALL instructions now recommend installing daemons and
+commands into separate directories.
+
+Major changes with postfix-19990601:
+=====================================
+
+- New USER, EXTENSION, LOCAL, DOMAIN and RECIPIENT environment
+variables for delivery to command (including mailbox_command) by
+the local delivery agent. As you might expect, the information is
+censored. The list of acceptable characters is specified with the
+command_expansion_filter configuration parameter.  Unacceptable
+characters are replaced by underscores. See html/local.8.html.
+
+- Specify "forward_path = /var/forward/$user" to avoid looking up
+.forward files in user home directories.  The default value is
+$home/.forward$recipient_delimiter$extension, $home/.forward.
+Initial code by Philip A.  Prindeville, Mirapoint, Inc., USA.
+
+- Conditional $name expansion in forward_path and luser_relay.
+Available names are: $user (bare user name) $shell (user login
+shell), $home (user home directory), $local (everything to the left
+of @), $extension (optional address extension), $domain (everything
+to the right of @), $recipient (the complete address) and
+$recipient_delimiter.  A simple $name expands as usual.  ${name?value}
+expands to value when $name is defined.  ${name:value} expands to
+value when $name is not defined. With ${name?value} and ${name:value},
+the value is subject to another iteration of $name expansion.
+
+- POSIX regular expression support, enabled by default on 4.4BSD,
+LINUX, HP-UX, and Solaris 2.5 and later. See conf/sample-regexp.cf.
+Initial code by Lamont Jones, Hewlett-Packard, borrowing heavily
+from the PCRE implementation by Andrew McNamara, connect.com.au
+Pty. Ltd., Australia.
+
+- Regular expression checks for message headers.  This requires
+support for POSIX or for PCRE regular expressions.  Specify
+"header_checks = regexp:/file/name" or "header_checks = pcre:/file/name",
+and specify "/^header-name:  badstuff/ REJECT" in the pattern file
+(patterns are case-insensitive by default).  Code by Lamont Jones,
+Hewlett-Packard.  It is to be expected that full content filtering
+will be delegated to an external command.
+
+- Regular expression support for all lookup tables, including access
+control (full mail addresses only), address rewriting (canonical/virtual,
+full mail addresses only) and transport tables (full domain names
+only).  However, regular expressions are not allowed for aliases,
+because that would open up security exposures.
+
+- Automatic detection of changes to DB or DBM lookup tables.  This
+eliminates the need to run "postfix reload" after each change to
+the SMTP access table, or to the canonical, virtual, transport or
+aliases tables.
+
+- New error mailer. Specify ".domain.name error:domain is undeliverable"
+in the transport table to bounce mail for entire domains.
+
+- No more Postfix lockups on Solaris (knock on wood). The code no
+longer uses Solaris UNIX-domain sockets, because they are still
+broken, even with Solaris 7.
+
+- Workaround for the Solaris mailtool, which keeps an exclusive
+kernel lock on the mailbox while its window is not iconified (specify
+"sun_mailtool_compatibility = yes" in main.cf).
+
+- Questionable workaround for Solaris, which reportedly loses
+long-lived exclusive locks that are held by the master daemon.
+
+- New reject_unknown_{sender,recipient}_domain restrictions for
+sender and recipient mail addresses that distinguish between soft
+errors (always 450) and hard errors (unknown_address_reject_code,
+default 450).
+
+- MIME-encapsulated bounce messages, making it easier to recover
+bounced mail. Initial implementation by Philip A.  Prindeville,
+Mirapoint, Inc., USA. Support for RFC 1892 (multipart/report) and
+RFC 1894 (DSN) will have to wait until Postfix internals have been
+revised to support RFC 1893.
+
+- Separately configurable "postmaster" addresses for single bounces
+(bounce_notice_recipient), double bounces (2bounce_notice_recipient),
+delayed mail (delay_notice_recipient), and for mailer error reports
+(error_notice_recipient). See conf/main.cf.
+
+- Questionable feature: specify "best_mx_transport = local" if
+this machine is the best MX host for domains not in mydestinations.
+
+Incompatible changes with postfix-19990317:
+===========================================
+
+- You MUST install the new version of /etc/postfix/postfix-script.
+
+- The pipe mailer "flags" syntax has changed. You now explicitly
+MUST specify the R flag in order to generate a Return-Path:  message
+header (as needed by, for example, cyrus).
+
+Major changes with postfix-19990317:
+====================================
+
+A detailed record of changes is given in the HISTORY file.
+
+- Less postmaster mail. Undeliverable bounce messages (double
+bounces) are now discarded. Specify "notify_classes = 2bounce..."
+to get copies of double bounces. Specify "notify_classes = bounce..."
+to get copies of normal and double bounces.
+
+- Improved LDAP client code by John Hensley of Merit Network, USA.
+See LDAP_README for details.
+
+- Perl-compatible regular expression support for lookup maps by
+Andrew McNamara, connect.com.au Pty. Ltd., Australia..  Example:
+"check_recipient_access pcre:/etc/postfix/sample-pcre.cf". Regular
+expressions provide a powerful tool not only for SMTP access control
+but also for address rewriting. See PCRE_README for details.
+
+- Automatic notification of delayed mail (disabled by default).
+With "delay_warning_time = 4", Postfix informs senders when mail
+has not been delivered after 4 hours. Initial version of the code
+by Daniel Eisenbud, University of California at Berkeley. In order
+to get postmaster copies of such warnings, specify "notify_classes
+= delay...".
+
+- More configurable local delivery: "mail_spool_directory" to
+specify the UNIX mail spool directory; "mailbox_transport" to
+delegate all mailbox delivery to, for example, cyrus, and
+"fallback_transport" to delegate delivery of only non-UNIX users.
+And all this without losing local aliases and local .forward
+processing.  See config/main.cf and config/master.cf.
+
+- Several changes to improve Postfix behavior under worst-case
+conditions (frequent Postfix restarts/reloads combined with lots
+if inbound mail, intermittent connectivity problems, SMTP servers
+that become comatose after receiving QUIT).
+
+- More NFS-friendly mailbox delivery. The local delivery agent
+now avoids using root privileges where possible.
+
+- For sites that do not receive mail at all, mydestination can now
+be an empty string. Be sure to set up a transport table entry to
+prevent mail from looping.
+
+- New "postsuper" utility to clean up stale files from Postfix
+queues.
+
+- Workaround for BSD select() collisions that cause performance
+problems on large BSD systems.
+
+- Several questionable but useful features to capture mail:
+"always_bcc = address" to capture a copy of every message that
+enters the system, and "luser_relay = address" to capture mail for
+unknown recipients (does not work when mailbox_transport or
+fallback_transport are being used).
+
+- Junk mail controls: new reject_non_fqdn_{hostname,sender,recipient}
+restrictions to reject non-FQDN arguments in HELO, MAIL FROM and
+RCPT TO commands, and stricter checking of numeric HELO arguments.
+
+- "fallback_relay" feature for sites that use DNS but that can't
+talk to the entire world. The fall-back relay gets the mail when
+a destination is not found in the DNS or when the destination is
+found but not reachable.
+
+- Several questionable controls that can help to keep mail going:
+specify "smtp_skip_4xx_greeting = yes" to skip SMTP servers that
+greet with 4XX, "ignore_mx_lookup_error = yes" to look up an A
+record when a DNS server does not respond to an MX query.
+
+Incompatible changes with postfix-beta-19990122-pl01:
+=====================================================
+
+None.
+
+Major changes with postfix-beta-19990122-pl01:
+==============================================
+
+- Restrict who may use ETRN and what domains may be specified.
+Example:  "smtpd_etrn_restrictions = permit_mynetworks, reject".
+
+- BIFF notifications.  For compatibility reasons this feature is
+on by default.  Specify "biff = no" in main.cf if your machine has
+lots of shell users.
+
+- With "soft_bounce = yes", defer delivery instead of bouncing
+mail. This is a safety net for configuration errors with delivery
+agents. It has no effect on errors in virtual maps, canonical maps,
+or in junk mail restrictions.
+
+- Specify "owner_request_special = no" to turn off special treatment
+of owner-foo and foo-request addresses.
+
+Incompatible changes with postfix-beta-19990122:
+================================================
+
+- The syntax of the transport table has changed. An entry like:
+
+       customer.org    smtp:[gateway.customer.org]
+
+  no longer forwards mail for anything.customer.org. For that you
+  need to specify:
+
+       customer.org    smtp:[gateway.customer.org]
+       .customer.org   smtp:[gateway.customer.org]
+
+  This change makes transport tables more compatible with
+  sendmail mailer tables.
+
+- The format of syslog records has changed. A client is now always
+logged as hostname[address]; the pickup daemon logs queue file uid
+and sender address.
+
+Major changes with postfix-beta-19990122:
+=========================================
+
+- Junk mail restrictions can now be postponed to the RCPT TO command.
+Specify: "smtpd_recipient_restrictions = reject_maps_rbl...".
+
+- More flexible interface for delivery to e.g., cyrus IMAP without
+need for PERL scripts to munge recipient addresses. In addition to
+$sender, $nexthop and $recipient, the pipe mailer now also supports
+$user, $extension and $mailbox.
+
+- New mail now has precedence over deferred mail, plus some other
+tweaks to make bulk mail go faster. But it ain't no cure for massive
+network outages.
+
+- Watchdog timer for systems that cause the Postfix queue manager
+to lock up, so it recovers without human intervention.
+
+- Delivery to qmail-style maildir files, which is good for NFS
+environments.  Specify "home_mailbox = Maildir/", or specify
+/file/name/ in aliases or in .forward files. The trailing / is
+required to turn on maildir delivery.
+
+- Incremental updates of aliases and maps. Specify "postmap -i
+mapname" and it will read new entries from stdin.
+
+- Newaliases will now update more than one alias database.
+Specify the names with the main.cf "alias_database" parameter.
+
+- Address masquerading exceptions to prevent users from being
+masqueraded. Specify "masquerade_exceptions = root".
+
+- A pipelined SMTP client. Deliveries to Postfix, qmail, LSOFT,
+zmailer, and exim (once it's fixed) speed up by some 30% for short
+messages with one recipient, with more for multi-recipient mails.
+
+- Hook for local delivery to "|command" via the smrsh restricted
+shell, to restrict what commands may be used in .forward etc. files.
+Specify "local_command_shell = /some/where/smrsh -c".
diff --git a/postfix/RELEASE_NOTES-2.0 b/postfix/RELEASE_NOTES-2.0
new file mode 100644 (file)
index 0000000..3c95d2b
--- /dev/null
@@ -0,0 +1,819 @@
+In the text below, changes are labeled with the Postfix snapshot
+that introduced the change, and whether the change introduced a
+feature, an incompatibility, or whether the feature is obsolete.
+If you upgrade from a later Postfix version, then you do not have
+to worry about incompatibilities introduced in earlier versions.
+
+Official Postfix releases are called a.b.c where a=major release
+number, b=minor release number, c=patchlevel.  Snapshot releases
+are now called a.b.c-yyyymmdd where yyyymmdd is the release date
+(yyyy=year, mm=month, dd=day).  The mail_release_date configuration
+parameter contains the release date (both for official release and
+snapshot release).  Patches change the patchlevel and the release
+date. Snapshots change only the release date, unless they include
+the same bugfixes as a patch release.
+
+Major changes with Postfix version 2.0.0 (released 20021222)
+============================================================
+
+First comes the bad news - things that may break when you upgrade
+from Postfix 1.1. Then comes the good news - things that evolved
+in snapshots over the past year.
+
+For the release notes of Postfix 1.1 and earlier, see the
+RELEASE_NOTES-1.1 file.
+
+Unknown Recipients are now rejected by default
+==============================================
+
+[Incompatibility 20021209] The Postfix SMTP server now rejects mail
+for $mydestination domain recipients that it does not know about.
+This keeps undeliverable mail out of your queue.
+
+[Incompatibility 20021209] To avoid losing mail when upgrading from
+Postfix 1.1, you need to review the LOCAL_RECIPIENT_README file if
+one of the following is true:
+
+- You define $mydestination domain recipients in files other than
+  /etc/passwd or /etc/aliases.  For example, you define $mydestination
+  domain recipients in the $virtual_mailbox_maps files.
+- You run the Postfix SMTP server chrooted (see master.cf).
+- You redefined the local delivery agent in master.cf.
+- You redefined the "local_transport" setting in main.cf.
+- You use the mailbox_transport feature of the Postfix local delivery agent.
+- You use the fallback_transport feature of the Postfix local delivery agent.
+- You use the luser_relay feature of the Postfix local delivery agent.
+
+Name change of virtual domain tables
+====================================
+
+This release introduces separation of lookup tables for addresses
+and for domain names of virtual domains.
+
+[Incompat 20021209] the virtual_maps parameter is replaced by
+virtual_alias_maps (for address lookups) and virtual_alias_domains
+(for the names of what were formerly called "Postfix-style virtual
+domains").
+
+  For backwards compatibility with Postfix version 1.1, the new
+  virtual_alias_maps parameter defaults to $virtual_maps, and the
+  new virtual_alias_domains parameter defaults to $virtual_alias_maps.
+  This means that you can still keep all information about a domain
+  in one file, just like before.
+
+For details, see the virtual(5) and sample-virtual.cf files.
+
+[Incompat 20021209] the virtual_mailbox_maps parameter now has a
+companion parameter called virtual_mailbox_domains (for the names
+of domains served by the virtual delivery agent). virtual_mailbox_maps
+is now used for address lookups only.
+
+  For backwards compatibility with Postfix version 1.1,, the new
+  virtual_mailbox_domains parameter defaults to $virtual_mailbox_maps.
+  This means that you can still keep all information about a domain
+  in one file, just like before.
+
+For details, see the VIRTUAL_README file.
+
+Incompatible queue file format changes
+======================================
+
+[Incompat 20020527] Queue files created with the header/body_checks
+"FILTER" feature are not compatible with "postqueue -r" (move queue
+files back to the maildrop directory) of previous Postfix releases.
+
+[Incompat 20020512] Postfix queue files contain records that are
+incompatible with "postqueue -r" on all Postfix versions prior to
+1.1 and release candidates. This happens whenever the sender
+specifies MIME body type information via the SMTP `MAIL FROM'
+command, via the `sendmail -B' command line option, or via the
+Content-Transfer-Encoding:  message header.
+
+[Incompat 20020512] Postfix queue files may contain records that
+are incompatible with "postqueue -r" on previous 1.1 Postfix versions
+and release candidates. This happens whenever the sender specifies
+the MIME body type only via the Content-Transfer-Encoding:  message
+header, and not via `MAIL FROM' or `sendmail -B'.
+
+Features that are going away
+============================
+
+[Obsolete 20021209] Sendmail-style virtual domains are no longer
+documented.  This part of Postfix was too confusing.
+
+[Obsolete 20021209] The "reject_maps_rbl" restriction is going
+away. The SMTP server now logs a warning and suggests using the
+more flexible "reject_rbl_client" feature instead.
+
+[Obsolete 20021209] The "check_relay_domains" restriction is going
+away.  The SMTP server logs a warning and suggests using the more
+robust "reject_unauth_destination" instead.
+
+[Obsolete 20020917] In regexp lookup tables, the form /pattern1/!/pattern2/
+is going away. Use the cleaner and more flexible "if !/pattern2/..endif"
+form.  The old form still exists but is no longer documented, and
+causes a warning (suggesting to use the new format) to be logged.
+For details, see "man regexp_table".
+
+[Obsolete 20020819] The qmgr_site_hog_factor feature is gone (this
+would defer mail delivery for sites that occupy too much space in
+the active queue, and be a real performance drain due to excessive
+disk I/O).  The new qmgr_clog_warn_time feature (see below) provides
+more useful suggestions for dealing with Postfix congestion.
+
+[Obsolete 20020819] The "permit_naked_ip_address" restriction on
+HELO command syntax is unsafe when used with most smtpd_XXX_restrictions
+and will go away. Postfix logs a warning, suggesting to use
+"permit_mynetworks" instead.
+
+MIME support
+============
+
+[Feature 20020527] Postfix now has real MIME support. This improves
+content filtering efficiency and accuracy, and improves inter-operability
+with mail systems that cannot receive 8-bit mail. See conf/sample-mime.cf
+for details.
+
+[Feature 20020527] Postfix header_checks now properly recognize
+MIME headers in attachments. This is much more efficient than
+previous versions that recognized MIME headers via body_checks.
+MIME headers are now processed one multi-line header at a time,
+instead of one body line at a time.  To get the the old behavior,
+specify "disable_mime_input_processing = yes".  More details in
+conf/sample-filter.cf.
+
+[Feature 20020527] Postfix now has three classes of header patterns:
+header_checks (for primary message headers except MIME headers),
+mime_header_checks (for MIME headers), and nested_header_checks
+(for headers of attached email messages except MIME headers).  By
+default, all headers are matched with header_checks.
+
+[Feature 20020527] The Postfix SMTP client will now convert 8BITMIME
+mail to 7BIT when delivering to an SMTP server that does not announce
+8BITMIME support.  To disable, specify "disable_mime_output_conversion
+= yes". However, this conversion is required by RFC standards.
+
+[Feature 20020528] Postfix can enforce specific aspects of the MIME
+standards while receiving mail.
+
+* Specify "strict_7bit_headers = yes" to disallow 8-bit characters
+  in message headers.  These are always illegal.
+
+* Specify "strict_8bitmime_body = yes" to block mail with 8-bit
+  content that is not properly labeled as 8-bit MIME. This blocks
+  mail from poorly written mail software, including (bounces from
+  qmail, bounces from Postfix before snapshot 20020514, and Majordomo
+  approval requests) that contain valid 8BITMIME mail.
+
+* Specify "strict_8bitmime = yes" to turn on both strict_7bit_headers
+  and strict_8bitmime_body.
+
+* Specify "strict_mime_encoding_domain = yes" to block mail from
+  poorly written mail software. More details in conf/sample-mime.cf.
+
+[Incompat 20020527] Postfix now rejects mail if the MIME multipart
+structure is nested more than mime_nesting_limit levels (default:
+100) when MIME input processing is enabled while receiving mail, or
+when Postfix is performing 8BITMIME to 7BIT conversion while
+delivering mail.
+
+[Incompat 20020527] Postfix now recognizes "name :" as a valid
+message header, but normalizes it to "name:" for consistency
+(actually, there is so much code in Postfix that would break with
+"name :" that there is little choice, except to not recognize "name
+:" headers).
+
+[Incompat 20020512] Postfix queue files contain records that are
+incompatible with "postqueue -r" on all Postfix versions prior to
+1.1 and release candidates. This happens whenever the sender
+specifies MIME body type information via the SMTP `MAIL FROM'
+command, via the `sendmail -B' command line option, or via the
+Content-Transfer-Encoding:  message header.
+
+[Incompat 20020512] Postfix queue files may contain records that
+are incompatible with "postqueue -r" on previous 1.1 Postfix versions
+and release candidates. This happens whenever the sender specifies
+the MIME body type only via the Content-Transfer-Encoding:  message
+header, and not via `MAIL FROM' or `sendmail -B'.
+
+[Feature 20020512] The Postfix SMTP and LMTP clients now properly
+pass on the MIME body type information (7BIT or 8BITMIME), provided
+that the sender properly specifies MIME body type information via
+the SMTP MAIL FROM command, via the sendmail -B command line option,
+or via MIME message headers. This includes mail that is returned
+as undeliverable.
+
+Improved performance
+====================
+
+[Incompat 20021209] The default queue directory hash_queue_depth
+setting is reduced to 1 level of subdirectories per Postfix queue.
+This improves "mailq" performance on most systems, but can result
+in poorer worst-case performance on systems with lots of mail in
+the queue.
+
+[Incompat 20021209] The Postfix SMTP client no longer expands CNAMEs
+in MAIL FROM or RCPT TO addresses (as permitted by RFC 2821). This
+eliminates one DNS lookup per sender and recipient, and can make
+a dramatic difference when sending mailing list mail via a relayhost.
+
+[Incompat 20021209] The Postfix installation procedure no longer
+sets the "chattr +S" bit on Linux queue directories. Wietse has
+gotten too annoyed with naive reviewers who complain about performance
+without having a clue of what they are comparing.
+
+[Feature 20021209] On mail gateway systems, separation of inbound
+mail relay traffic from outbound traffic. This eliminates a problem
+where inbound mail deliveries could become resource starved in the
+presence of a high volume of outbound mail.
+
+[Feature 20021013] The body_checks_max_size parameter limits the
+amount of text per message body segment (or attachment, if you
+prefer to use that term) that is subjected to body_checks inspection.
+The default limit is 50 kbytes. This speeds up the processing of
+mail with large attachments.
+
+[Feature 20020917] Speedups of regexp table lookups by optimizing
+for the $number substitutions that are actually present in the
+right-hand side.  Based on a suggestion by Liviu Daia.
+
+[Feature 20020917] Speedups of regexp and pcre tables, using
+IF..ENDIF support. Based on an idea by Bert Driehuis.  To protect
+a block of patterns, use:
+
+    if /pattern1/
+    /pattern2/ result2
+    /pattern3/ result3
+    endif
+
+IF..ENDIF can nest. Don't specify blanks at the beginning of lines
+inside IF..ENDIF, because lines beginning with whitespace are
+appended to the previous line. More details about the syntax are
+given in the pcre_table(5) and regexp_table(5) manual pages.
+
+[Feature 20020717] The default timeout for establishing an SMTP
+connection has been reduced to 30 seconds, because many systems
+have an atrociously large default timeout value.
+
+[Feature 20020505] Finer control over Berkeley DB memory usage,
+The parameter "berkeley_db_create_buffer_size" (default:  16 MBytes)
+specifies the buffer size for the postmap and postalias commands.
+The parameter "berkeley_db_read_buffer_size" (default:  256 kBytes)
+speficies the buffer size for all other applications.  Specify
+"berkeley_db_read_buffer_size = 1048576" to get the old read buffer
+size. For more information, see the last paragraphs of the DB_README
+file.
+
+Improved compatibitity
+======================
+
+[Feature 20020527] The Postfix SMTP client will now convert 8BITMIME
+mail to 7BIT when delivering to an SMTP server that does not announce
+8BITMIME support.  To disable, specify "disable_mime_output_conversion
+= yes". However, this conversion is required by RFC standards.
+
+[Feature 20020512] The Postfix SMTP and LMTP clients now properly
+pass on the MIME body type information (7BIT or 8BITMIME), provided
+that the sender properly specifies MIME body type information via
+the SMTP MAIL FROM command, via the sendmail -B command line option,
+or via MIME message headers. This includes mail that is returned
+as undeliverable.
+
+[Incompat 20020326] The Postfix SMTP client now breaks message
+header or body lines that are longer than $smtp_line_length_limit
+characters (default:  990). Earlier Postfix versions broke lines
+at $line_length_limit characters (default: 2048). Postfix versions
+before 20010611 did not break long lines at all.  Reportedly, some
+mail servers refuse to receive mail with lines that exceed the 1000
+character limit that is specified by the SMTP standard.
+
+[Incompat 20020326] The Postfix SMTP client now breaks long message
+header or body lines by inserting <CR> <LF> <SPACE>.  Earlier
+Postfix versions broke long lines by inserting <CR> <LF> only. This
+broke MIME encapsulation, causing MIME attachments to "disappear"
+with Postfix versions after 20010611.
+
+[Incompat 20020326] Postfix now discards text when a logical message
+header exceeds $header_size_limit characters (default: 102400).
+Earlier Postfix versions would place excess text, and all following
+text, in the message body. The same thing was done when a physical
+header line exceeded $line_length_limit characters (default: 2048).
+Both behaviors broke MIME encapsulation, causing MIME attachments
+to "disappear" with all previous Postfix versions.
+
+[Incompat 20021015] The Postfix LMTP client no longer lowercases email
+addresses in MAIL FROM and RCPT TO commands.
+
+[Incompat 20021013] The default Linux kernel lock style for mailbox
+delivery is changed from flock() to fcntl(). This has no impact if
+your system uses procmail for local delivery, if you use maildir-style
+mailboxes, or when mailbox access software locks mailboxes with
+username.lock files (which is usually the case with non-maildir
+mailboxes).
+
+Address classes
+===============
+
+[Feature 20021209] This release introduces the concept of address
+domain classes, each having its own default mail delivery transport:
+
+  Destination matches      Default transport       Default name
+  ==============================================================
+  $mydestination or
+     $inet_interfaces      $local_transport        local
+  $virtual_alias_domains   (not applicable)        (not applicable)
+  $virtual_mailbox_domains $virtual_transport      virtual
+  $relay_domains           $relay_transport        relay
+  other                    $default_transport      smtp
+
+The benefits of these changes are:
+
+- You no longer need to specify all the virtual(8) domains in the
+  Postfix transport map. The virtual(8) delivery agent has
+  become a first-class citizen just like local(8) or smtp(8).
+
+- On mail gateway systems, separation of inbound mail relay traffic
+  from outbound traffic. This eliminates a problem where inbound
+  mail deliveries could become resource starved in the presence of
+  a high volume of outbound mail.
+
+- The SMTP server rejects unknown recipients in a more consistent
+  manner than was possible with previous Postfix versions.
+
+See the ADDRESS_CLASS_README file for a description of address
+classes, their benefits, and their incompatibilities.
+
+New relay transport in master.cf
+================================
+
+[Incompat 20021209] Postfix no longer defaults to the "smtp"
+transport for all non-local destinations.  In particular, Postfix
+now uses the "relay" mail delivery transport for delivery to domains
+matching $relay_domains.  This may affect your defer_transports
+settings.
+
+On mail gateway systems, this allows us to separate inbound mail
+relay traffic from outbound traffic, and thereby eliminate a problem
+where inbound mail deliveries could become resource starved in the
+presence of a high volume of outbound mail.
+
+[Incompat 20021209] This release adds a new "relay" service to the
+Postfix master.cf file. This is a clone of the "smtp" service.  If
+your Postfix is unable to connect to the "relay" service then you
+have not properly followed the installation procedure.
+
+Revision of RBL blacklisting code
+=================================
+
+[Feature 20020923] Complete rewrite of the RBL blacklisting code.
+The names of RBL restrictions are now based on a suggestion that
+was made by Liviu Daia in October 2001. See conf/sample-smtpd.cf
+or html/uce.html for details.
+
+[Feature 20020923] "reject_rbl_client rbl.domain.tld" for client
+IP address blacklisting. Based on code by LaMont Jones.  The old
+"reject_maps_rbl" is now implemented as a wrapper around the
+reject_rbl_client code, and logs a warning that "reject_maps_rbl"
+is going away.
+
+[Feature 20020923] "reject_rhsbl_sender rbl.domain.tld" for sender
+domain blacklisting. Also: reject_rhsbl_client and reject_rhsbl_recipient
+for client and recipient domain blacklisting.
+
+[Feature 20020923] "rbl_reply_maps" configuration parameter for
+lookup tables with template responses per RBL server. Based on code
+by LaMont Jones.  If no reply template is found the default template
+is used as specified with the default_rbl_reply configuration
+parameter.  The template responses support $name expansion of
+client, helo, sender, recipient and RBL related attributes.
+
+[Incompat 20020923] The default RBL "reject" server reply now
+includes an indication of *what* is being rejected: Client host,
+Helo command, Sender address, or Recipient address. This also
+changes the logfile format.
+
+[Feature 20020923] "smtpd_expansion_filter" configuration parameter
+to control what characters are allowed in the expansion of template
+RBL reply $name macros. Characters outside the allowed set are
+replaced by "_".
+
+More sophisticated handling of UCE-related DNS lookup errors
+============================================================
+
+[Feature 20020906] More sophisticated handling of UCE-related DNS
+lookup errors.  These cause Postfix to not give up so easily, so
+that some deliveries will not have to be deferred after all.
+
+[Feature 20020906] The SMTP server sets a defer_if_permit flag when
+an UCE reject restriction fails due to a temporary (DNS) problem,
+to prevent unwanted mail from slipping through.  The defer_if_permit
+flag is tested at the end of the ETRN and recipient restrictions.
+
+[Feature 20020906] A similar flag, defer_if_reject, is maintained
+to prevent mail from being rejected because a whitelist operation
+(such as permit_mx_backup) fails due to a temporary (DNS) problem.
+
+[Feature 20020906] The permit_mx_backup restriction is made more
+strict. With older versions, some DNS failures would cause mail to
+be accepted anyway, and some DNS failures would cause mail to be
+rejected by later restrictions in the same restriction list.  The
+improved version will defer delivery when Postfix could make the
+wrong decision.
+
+- After DNS lookup failure, permit_mx_backup will now accept the
+request if a subsequent restriction would cause the request to be
+accepted anyway, and will defer the request if a subsequent
+restriction would cause the request to be rejected.
+
+- After DNS lookup failure, reject_unknown_hostname (the hostname
+given in HELO/EHLO commands) reject_unknown_sender_domain and
+reject_unknown_recipient_domain will now reject the request if a
+subsequent restriction would cause the request to be rejected
+anyway, and will defer the request if a subsequent restriction
+would cause the request to be accepted.
+
+[Feature 20020906] Specify "smtpd_data_restrictions =
+reject_unauth_pipelining" to block mail from SMTP clients that send
+message content before Postfix has replied to the SMTP DATA command.
+
+Other UCE related changes
+=========================
+
+[Feature 20020717] The SMTP server reject_unknown_{sender,recipient}_domain
+etc.  restrictions now also attempt to look up AAAA (IPV6 address)
+records.
+
+[Incompat 20020513] In order to allow user@domain@domain addresses
+from untrusted systems, specify "allow_untrusted_routing = yes" in
+main.cf.  This opens opportunities for mail relay attacks when
+Postfix provides backup MX service for Sendmail systems.
+
+[Incompat 20020514] For safety reasons, the permit_mx_backup
+restriction no longer accepts mail for user@domain@domain. To
+recover the old behavior, specify "allow_untrusted_routing = yes"
+and live with the risk of becoming a relay victim.
+
+[Incompat 20020509] The Postfix SMTP server no longer honors OK
+access rules for user@domain@postfix-style.virtual.domain, to close
+a relaying loophole with postfix-style virtual domains that have
+@domain.name catch-all patterns.
+
+[Incompat 20020201] In Postfix SMTPD access tables, Postfix now
+uses <> as the default lookup key for the null address, in order
+to work around bugs in some Berkeley DB implementations. This
+behavior is controlled with the smtpd_null_access_lookup_key
+configuration parameter.
+
+Changes in transport table lookups
+==================================
+
+[Feature 20020610] user@domain address lookups in the transport
+map.  This feature also understands address extensions.  Transport
+maps still support lookup keys in the form of domain names, but
+only with non-regexp tables.  Specify mailer-daemon@my.host.name
+in order to match the null address. More in the transport(5) manual
+page.
+
+[Feature 20020505] Friendlier behavior of Postfix transport tables.
+There is a new "*" wildcard pattern that always matches.  The
+meaning of null delivery transport AND nexhop information field
+has changed to "do not modify": use the information that would be
+used if the transport table did not exist. This change makes it
+easier to route intranet mail (everything under my.domain) directly:
+you no longer need to specify explicit "local" transport table
+entries for every domain name that resolves to the local machine.
+For more information, including examples, see the updated transport(5)
+manual page.
+
+[Incompat 20020610] Regexp/PCRE-based transport maps now see the
+entire recipient address instead of only the destination domain
+name.
+
+[Incompat 20020505, 20021215] The meaning of null delivery transport
+and nexhop fields has changed incompatibly.
+
+- A null delivery transport AND nexthop information field means
+"do not modify": use the delivery transport or nexthop information
+that would be used if no transport table did not exist.
+
+- The delivery transport is not changed with a null delivery
+transport field and non-null nexthop field.
+
+- The nexthop is reset to the recipient domain with a non-null
+transport field and a null nexthop information field.
+
+Address manipulation changes
+============================
+
+[Incompat 20020717] Postfix no longer strips multiple '.' characters
+from the end of an email address or domain name. Only one '.' is
+tolerated.
+
+[Feature 20020717] The masquerade_domains feature now supports
+exceptions.  Prepend a ! character to a domain name in order to
+not strip its subdomain structure.  More information in
+conf/sample-rewrite.cf.
+
+[Feature 20020717] The Postfix virtual delivery agent supports
+catch-all entries (@domain.tld) in lookup tables. These match users
+that do not have a specific user@domain.tld entry. The virtual
+delivery agent now ignores address extensions (user+foo@domain.tld)
+when searching its lookup tables, but displays the extensions in
+Delivered-To:  message headers.
+
+[Feature 20020610] user@domain address lookups in the transport
+map.  This feature also understands address extensions.  Transport
+maps still support lookup keys in the form of domain names, but
+only with non-regexp tables.  Specify mailer-daemon@my.host.name
+in order to match the null address. More in the transport(5) manual
+page.
+
+[Incompat 20020610] Regexp/PCRE-based transport maps now see the
+entire recipient address instead of only the destination domain
+name.
+
+[Incompat 20020513] In order to allow user@domain@domain addresses
+from untrusted systems, specify "allow_untrusted_routing = yes" in
+main.cf.  This opens opportunities for mail relay attacks when
+Postfix provides backup MX service for Sendmail systems.
+
+[Incompat 20020509] The Postfix SMTP server no longer honors OK
+access rules for user@domain@postfix-style.virtual.domain, to close
+a relaying loophole with postfix-style virtual domains that have
+@domain.name catch-all patterns.
+
+[Incompat 20020509] The appearance of user@domain1@domain2 addresses
+has changed.  In mail headers, such addresses are now properly
+quoted as "user@domain1"@domain2. As a side effect, this quoted
+form is now also expected on the left-hand side of virtual and
+canonical lookup tables, but only by some of the Postfix components.
+For now, it is better not to use user@domain1@domain2 address forms
+on the left-hand side of lookup tables.
+
+Regular expression and PCRE related changes
+===========================================
+
+[Feature 20021209] Regular expression maps are now allowed with
+local delivery agent alias tables and with all virtual delivery
+agent lookup tables.  However, regular expression substitution of
+$1 etc.  is still forbidden for security reasons.
+
+[Obsolete 20020917] In regexp lookup tables, the form /pattern1/!/pattern2/
+is going away. Use the cleaner and more flexible "if !/pattern2/..endif"
+form.  The old form still exists but is no longer documented, and
+causes a warning (suggesting to use the new format) to be logged.
+
+[Incompat 20020610] Regexp/PCRE-based transport maps now see the
+entire recipient address instead of only the destination domain
+name.
+
+[Incompat 20020528] With PCRE pattern matching, the `.' metacharacter
+now matches all characters including newline characters. This makes
+PCRE pattern matching more convenient to use with multi-line message
+headers, and also makes PCRE more compatible with regexp pattern
+matching.  The pcre_table(5) manual page has been greatly revised.
+
+New mail "HOLD" action and "hold" queue
+=======================================
+
+[Feature 20020819] New "hold" queue for mail that should not be
+delivered.  "postsuper -h" puts mail on hold, and "postsuper -H"
+releases mail, moving mail that was "on hold" to the deferred queue.
+
+[Feature 20020821] HOLD and DISCARD actions in SMTPD access tables.
+As with the header/body version of the same, these actions apply
+to all recipients of the same queue file.
+
+[Feature 20020819] New header/body HOLD action that causes mail to
+be placed on the "hold" queue. Presently, all you can do with mail
+"on hold" is to examine it with postcat, to take it "off hold" with
+"postsuper -H", or to destroy it with "postsuper -d". See
+conf/sample-filter.cf.
+
+[Incompat 20020819] In mailq output, the queue ID is followed by
+the ! character when the message is in the "hold" queue (see below).
+This may break programs that process mailq output.
+
+Content filtering
+=================
+
+[Feature 20020823] Selective content filtering. In in SMTPD access
+tables, specify "FILTER transport:nexthop" for mail that needs
+filtering. More info about content filtering is in the Postfix
+FILTER_README file.  This feature overrides the main.cf content_filter
+setting. Presently, this applies to all the recipients of a queue
+file.
+
+[Feature 20020527] Selective content filtering. In header/body_check
+patterns, specify "FILTER transport:nexthop" for mail that needs
+filtering. This requires different cleanup servers before and after
+the filter, with header/body checks turned off in the second cleanup
+server.  More info about content filtering is in the Postfix
+FILTER_README file.  This feature overrides the main.cf content_filter
+setting. Presently, this applies to all the recipients of a queue
+file.
+
+[Feature 20020527] Postfix now has real MIME support. This improves
+content filtering efficiency and accuracy, and improves inter-operability
+with mail systems that cannot receive 8-bit mail. See conf/sample-mime.cf
+for details.
+
+[Feature 20020527] Postfix header_checks now properly recognize
+MIME headers in attachments. This is much more efficient than
+previous versions that recognized MIME headers via body_checks.
+MIME headers are now processed one multi-line header at a time,
+instead of one body line at a time.  To get the the old behavior,
+specify "disable_mime_input_processing = yes".  More details in
+conf/sample-filter.cf.
+
+[Feature 20020527] Postfix now has three classes of header patterns:
+header_checks (for primary message headers except MIME headers),
+mime_header_checks (for MIME headers), and nested_header_checks
+(for headers of attached email messages except MIME headers).  By
+default, all headers are matched with header_checks.
+
+[Feature 20021013] The body_checks_max_size parameter limits the
+amount of text per message body segment (or attachment, if you
+prefer to use that term) that is subjected to body_checks inspection.
+The default limit is 50 kbytes. This speeds up the processing of
+mail with large attachments.
+
+[Feature 20020917] Speedups of regexp table lookups by optimizing
+for the $number substitutions that are actually present in the
+right-hand side.  Based on a suggestion by Liviu Daia.
+
+[Feature 20020917] Speedups of regexp and pcre tables, using
+IF..ENDIF support. Based on an idea by Bert Driehuis.  To protect
+a block of patterns, use:
+
+    if /pattern1/
+    /pattern2/ result2
+    /pattern3/ result3
+    endif
+
+IF..ENDIF can nest. Don't specify blanks at the beginning of lines
+inside IF..ENDIF, because lines beginning with whitespace are
+appended to the previous line. More details about the syntax are
+given in the pcre_table(5) and regexp_table(5) manual pages.
+
+Postmap/postalias/newaliases changes
+====================================
+
+[Incompat 20020505] The postalias command now copies the source
+file read permissions to the result file when creating a table for
+the first time. Until now, the result file was created with default
+read permissions.  This change makes postalias more similar to
+postmap.
+
+[Incompat 20020505] The postalias and postmap commands now drop
+super-user privileges when processing a non-root source file. The
+file is now processed as the source file owner, and the owner must
+therefore have permission to update the result file. Specify the
+"-o" flag to get the old behavior (process non-root files with root
+privileges).
+
+[Incompat 20020122] When the postmap command creates a non-existent
+result file, the new file inherits the group/other read permissions
+of the source file.
+
+Assorted changes
+================
+
+[Feature 20021028] The local(8) and virtual(8) delivery agents now record
+the original recipient address in the X-Original-To: message header.
+This header can also be emitted by the pipe(8) delivery agent.
+
+[Feature 20021024] New proxy_interfaces parameter, for sites behind a
+network address translation gateway or other type of proxy. You
+should specify all the proxy network addresses here, to avoid avoid
+mail delivery loops.
+
+[Feature 20021013] Updated MacOS X support by Gerben Wierda. See
+the auxiliary/MacOSX directory.
+
+[Incompat 20021013] Subtle change in ${name?result} macro expansions:
+the expansion no longer happens when $name is an empty string. This
+probably makes more sense than the old behavior.
+
+[Incompat 20020917] The relayhost setting now behaves as documented,
+i.e. you can no longer specify multiple destinations.
+
+[Incompatibility 20021219] The use of the XVERP extension in the
+SMTP MAIL FROM command is now restricted to SMTP clients that match
+the hostnames, domains or networks listed with the authorized_verp_clients
+parameter (default:  $mynetworks).
+
+[Feature 20020819] When the Postfix local delivery agent detects
+a mail delivery loop (usually the result of mis-configured mail
+pickup software), the undeliverable mail is now sent to the mailing
+list owner instead of the envelope sender address (usually the
+original poster who has no guilt, and who cannot fix the problem).
+
+[Warning 20020819] The Postfix queue manager now warns when mail
+for some destination is piling up in the active queue, and suggests
+a variety of remedies to speed up delivery (increase per-destination
+concurrency limit, increase active queue size, use a separate
+delivery transport, increase per-transport process limit).  The
+qmgr_clog_warn_time parameter controls the time between warnings.
+To disable these warnings, specify "qmgr_clog_warn_time = 0".
+
+[Warning 20020717] The Postfix SMTP client now logs a warning when
+the same domain is listed in main.cf:mydestination as well as a
+Postfix-style virtual map. Such a mis-configuration may cause mail
+for users to be rejected with "user unknown".
+
+[Feature 20020331] A new smtp_helo_name parameter that specifies
+the hostname to be used in HELO or EHLO commands; this can be more
+convenient than changing the myhostname parameter setting.
+
+[Feature 20020331] Choice between multiple instances of internal
+services:  bounce, cleanup, defer, error, flush, pickup, queue,
+rewrite, showq.  This allows you to use different cleanup server
+settings for different SMTP server instances.  For example, specify
+in the master.cf file:
+
+    localhost:10025 ... smtpd -o cleanup_service_name=cleanup2 ...
+    cleanup2        ... cleanup -o header_checks= body_checks= ...
+
+Logfile format changes
+======================
+
+[Incompat 20021209] The Postfix SMTP client no longer expands CNAMEs
+in MAIL FROM addresses (as permitted by RFC 2821) before logging
+the recipient address.
+
+[Incompat 20021028] The Postfix SMTP server UCE reject etc. logging
+now includes the queue ID, the mail protocol (SMTP or ESMTP), and
+the hostname that was received with the HELO or EHLO command, if
+available.
+
+[Incompat 20021028] The Postfix header/body_checks logging now
+includes the mail protocol (SMTP, ESMTP, QMQP) and the hostname
+that was received with the SMTP HELO or EHLO command, if available.
+
+[Incompat 20021028] The Postfix status=sent/bounced/deferred logging
+now shows the original recipient address (as received before any
+address rewriting or aliasing).  The original recipient address is
+logged only when it differs from the final recipient address.
+
+[Incompat 20020923] The default RBL "reject" server reply now
+includes an indication of *what* is being rejected: Client host,
+Helo command, Sender address, or Recipient address. This also
+changes the logfile format.
+
+LDAP related changes
+====================
+
+[Incompat 20020819] LDAP API version 1 is no longer supported. The
+memory allocation and deallocation strategy has changed too much
+to maintain both version 1 and 2 at the same time.
+
+[Feature 20020513] Updated LDAP client module with better handling
+of dead LDAP servers, and with configurable filtering of query
+results.
+
+SASL related changes
+====================
+
+[Incompat 20020819] The smtpd_sasl_local_domain setting now defaults
+to the null string, rather than $myhostname. This seems to work
+better with Cyrus SASL version 2. This change may cause incompatibility
+with the saslpasswd2 command.
+
+[Feature 20020331] Support for the Cyrus SASL version 2 library,
+contributed by Jason Hoos. This adds some new functionality that
+was not available in Cyrus SASL version 1, and provides bit-rot
+insurance for the time when Cyrus SASL version 1 eventually stops
+working.
+
+Berkeley DB related changes
+===========================
+
+[Feature 20020505] Finer control over Berkeley DB memory usage,
+The parameter "berkeley_db_create_buffer_size" (default:  16 MBytes)
+specifies the buffer size for the postmap and postalias commands.
+The parameter "berkeley_db_read_buffer_size" (default:  256 kBytes)
+speficies the buffer size for all other applications.  Specify
+"berkeley_db_read_buffer_size = 1048576" to get the old read buffer
+size. For more information, see the last paragraphs of the DB_README
+file.
+
+[Incompat 20020201] In Postfix SMTPD access tables, Postfix now
+uses <> as the default lookup key for the null address, in order
+to work around bugs in some Berkeley DB implementations. This
+behavior is controlled with the smtpd_null_access_lookup_key
+configuration parameter.
+
+[Incompat 20020201] Postfix now detects if the run-time Berkeley
+DB library routines do not match the major version number of the
+compile-time include file that was used for compiling Postfix. The
+software issues a warning and aborts in case of a discrepancy. If
+it didn't, the software was certain to crash with a segmentation
+violation.
+
+Assorted workarounds
+====================
+
+[Incompat 20020201] On SCO 3.2 UNIX, the input rate flow control
+is now turned off by default, because of limitations in the SCO
+UNIX kernel.
index b2c9bfc70b9708fab55c6cc91b0e9833253554c5..c5ebc9987e1ca256f6fdd3e145036605a40f66f3 100644 (file)
@@ -172,7 +172,7 @@ mail_owner = postfix
 #
 # - You define $mydestination domain recipients in files other than
 #   /etc/passwd, /etc/aliases, or the $virtual_alias_maps files.
-#   For example, you define $mydestination domain recipients in
+#   For example, you define $mydestination domain recipients in    
 #   the $virtual_mailbox_maps files.
 #
 # - You redefined the local delivery agent in master.cf.
index 82983792dee0e963a0e4e1ad52fe60af3b74c2f7..1955bd4d0d0297c365eb84132078c4ac9ccc1860 100644 (file)
@@ -78,6 +78,8 @@ qmgr    fifo  n       -       n       300     1       qmgr
 rewrite          unix  -       -       n       -       -       trivial-rewrite
 bounce   unix  -       -       n       -       0       bounce
 defer    unix  -       -       n       -       0       bounce
+trace    unix  -       -       n       -       0       bounce
+verify   unix  -       -       n       -       1       verify
 flush    unix  n       -       n       1000?   0       flush
 smtp     unix  -       -       n       -       -       smtp
 relay    unix  -       -       n       -       -       smtp
index 88fae3a76b04177c150178662ff28e5bdbb6eb77..9b176f7f8868c8790d86d69f8589961d480ecc8d 100644 (file)
@@ -467,6 +467,38 @@ flush     unix  -       -       n       1000?   0       flush
 EOF
     }
 
+    # Add missing trace service to master.cf.
+
+    grep 'trace.*bounce' $config_directory/master.cf >/dev/null || {
+       echo Editing $config_directory/master.cf, adding missing entry for trace service
+       cat >>$config_directory/master.cf <<EOF || exit 1
+trace    unix  -       -       n       -       0       bounce
+EOF
+    }
+
+    # Add missing verify service to master.cf.
+
+    grep '^verify.*verify' $config_directory/master.cf >/dev/null || {
+       echo Editing $config_directory/master.cf, adding missing entry for verify service
+       cat >>$config_directory/master.cf <<EOF || exit 1
+verify   unix  -       -       n       -       1       verify
+EOF
+    }
+
+    # Fix verify service process limit.
+
+    grep '^verify.*[   ]0[     ]*verify' \
+       $config_directory/master.cf >/dev/null && {
+           echo Editing $config_directory/master.cf, setting verify process limit to 1
+           ed $config_directory/master.cf <<EOF || exit 1
+/^verify.*[    ]0[     ]*verify/
+s/\([  ]\)0\([         ]\)/\11\2/
+p
+w
+q
+EOF
+    }
+
     # Change privileged pickup service into unprivileged.
 
     grep "^pickup[     ]*fifo[         ]*n[    ]*n" \
@@ -531,7 +563,7 @@ EOF
     if [ -z "$has_lrm" -a -z "$has_lrjc" ]
     then
        echo SAFETY: editing main.cf, setting $unknown_local=450.
-       echo See the RELEASE_NOTES and $config_directory/main.cf for details.
+       echo See the RELEASE_NOTES and LOCAL_RECIPIENT_README files for details.
        $POSTCONF -e "$unknown_local = 450" || exit 1
     fi
 
index b0d215dba090d5b6b263c9613f141cafcb85eebd..c6ef0a34b9369f97ed7b21dea4d4b142062abbd5 100644 (file)
@@ -53,6 +53,7 @@ $queue_directory/private:d:$mail_owner:-:700:uc
 $queue_directory/maildrop:d:$mail_owner:$setgid_group:730:uc
 $queue_directory/public:d:$mail_owner:$setgid_group:710:uc
 $queue_directory/pid:d:root:-:755:uc
+$queue_directory/trace:d:$mail_owner:-:700:ucr
 $daemon_directory/bounce:f:root:-:755
 $daemon_directory/cleanup:f:root:-:755
 $daemon_directory/error:f:root:-:755
@@ -70,6 +71,7 @@ $daemon_directory/smtp:f:root:-:755
 $daemon_directory/smtpd:f:root:-:755
 $daemon_directory/spawn:f:root:-:755
 $daemon_directory/trivial-rewrite:f:root:-:755
+$daemon_directory/verify:f:root:-:755
 $daemon_directory/virtual:f:root:-:755
 $command_directory/postalias:f:root:-:755
 $command_directory/postcat:f:root:-:755
@@ -139,7 +141,9 @@ $manpage_directory/man8/showq.8:f:root:-:644
 $manpage_directory/man8/smtp.8:f:root:-:644
 $manpage_directory/man8/smtpd.8:f:root:-:644
 $manpage_directory/man8/spawn.8:f:root:-:644
+$manpage_directory/man8/trace.8:f:root:-:644
 $manpage_directory/man8/trivial-rewrite.8:f:root:-:644
+$manpage_directory/man8/verify.8:f:root:-:644
 $manpage_directory/man8/virtual.8:f:root:-:644
 $sample_directory/sample-aliases.cf:f:root:-:644
 $sample_directory/sample-auth.cf:f:root:-:644
@@ -167,6 +171,7 @@ $sample_directory/sample-rewrite.cf:f:root:-:644
 $sample_directory/sample-smtp.cf:f:root:-:644
 $sample_directory/sample-smtpd.cf:f:root:-:644
 $sample_directory/sample-transport.cf:f:root:-:644
+$sample_directory/sample-verify.cf:f:root:-:644
 $sample_directory/sample-virtual.cf:f:root:-:644
 $readme_directory/ADDRESS_CLASS_README:f:root:-:644
 $readme_directory/DB_README:f:root:-:644
index aa9661e8c1a76a8b8193180642a83dfb5f378328..25b00567eb496a571eaf00ef9b4671febc0b5050 100644 (file)
@@ -170,7 +170,7 @@ check)
        }
 
        find `ls -d $queue_directory/* | \
-           egrep '/(incoming|active|defer|deferred|bounce|hold|corrupt|public|private|flush)$'` \
+           egrep '/(incoming|active|defer|deferred|bounce|hold|trace|corrupt|public|private|flush)$'` \
            ! \( -type p -o -type s \) ! -user $mail_owner \
                -exec $WARN not owned by $mail_owner: {} \;
 
index 63e0eb7ad53976e4fcf6e1edb42f8d82c4da2d86..4fd7c08ccd826890a656e1b8aa03a2547bef1ef8 100644 (file)
@@ -337,6 +337,9 @@ smtpd_sender_restrictions =
 #
 #  *permit_mynetworks: permit if the client address matches $mynetworks.
 #   reject_unknown_sender_domain: reject sender domain without A or MX record.
+#   reject_unverified_sender: reject undeliverable sender address.
+#   reject_unverified_recipient: reject undeliverable recipient address.
+#   reject_multi_recipient_bounce: reject mail from <> with multiple recipients.
 #   reject_rhsbl_recipient domain.tld: reject recipient domain name if it is
 #      listed in an A record under domain.tld.
 #   permit_auth_destination: permit mail
@@ -514,6 +517,14 @@ invalid_hostname_reject_code = 501
 #
 maps_rbl_reject_code = 550
 
+# The multi_recipient_bounce_reject_code parameter specifies the SMTP
+# server response when an SMTP client request is blocked by the
+# reject_multi_recipient_bounce restriction.
+#
+# Do not change this unless you have a complete understanding of RFC 821.
+#
+multi_recipient_bounce_reject_code = 550
+
 # The rbl_reply_maps parameter specifies tables with RBL response
 # templates, indexed by RBL domain name. By default, Postfix uses
 # the default template as specified with the default_rbl_reply
@@ -553,6 +564,28 @@ smtpd_expansion_filter = \t\40!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQR
 #
 unknown_address_reject_code = 450
 
+# The unverified_sender_reject_code parameter specifies the SMTP
+# server response when a client violates the reject_unverified_sender
+# restriction.
+#
+# Unlike elsewhere in Postfix, you can specify 250 in order to
+# accept the address anyway.
+# 
+# Do not change this unless you have a complete understanding of RFC 821.
+# 
+unverified_sender_reject_code = 450
+
+# The unverified_recipient_reject_code parameter specifies the SMTP
+# server response when a client violates the reject_unverified_recipient
+# restriction.
+#
+# Unlike elsewhere in Postfix, you can specify 250 in order to
+# accept the address anyway.
+# 
+# Do not change this unless you have a complete understanding of RFC 821.
+# 
+unverified_recipient_reject_code = 450
+
 # The unknown_client_reject_code parameter specifies the SMTP server
 # response when a client without address to name mapping violates
 # the reject_unknown_client restriction.
diff --git a/postfix/conf/sample-verify.cf b/postfix/conf/sample-verify.cf
new file mode 100644 (file)
index 0000000..75094bf
--- /dev/null
@@ -0,0 +1,81 @@
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
+# This file contains example settings of Postfix configuration
+# parameters that control the SMTP client program.
+
+#
+# ADDRESS VERIFICATION (see also: verify(8) and SENDER_VERIFICATION_README)
+#
+
+# The address_verify_map configuration parameter specifies an optional
+# table for persistent recipient status storage. The file is opened
+# before the process enters a chroot jail and before it drops root
+# privileges.
+# 
+# By default, the information is kept in volatile memory, and is lost
+# after postfix reload or postfix stop.
+#
+# Specify a pathname in a file system that will not fill up. If the
+# database becomes corrupted, the world comes to an end. To recover
+# you have to delete the file and do "postfix reload".
+# 
+#address_verify_map = hash:/etc/postfix/verify
+#address_verify_map = btree:/etc/postfix/verify
+address_verify_map = 
+
+# The address_verify_sender configuration parameter specifies the
+# sender address that Postfix will use in address verification probe
+# messages.
+# 
+# By default, the probe sender address is postmaster@$myorigin.
+# 
+# Specify an empty value (address_verify_sender =) or <> if you want
+# to use the null sender address. Beware, some sites reject mail from
+# <>, even though RFCs require that such addresses to be accepted.
+# 
+#address_verify_sender = <>
+#address_verify_sender = postmaster@my.domain
+address_verify_sender = postmaster
+
+# The address_verify_positive_expire_time configuration parameter
+# specifies the amount of time after which a known to be good address
+# expires.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+# 
+address_verify_positive_expire_time = 31d
+
+# The address_verify_positive_refresh_time configuration parameter
+# specifies the minimal amount of time after which a proactive probe
+# is sent to verify that a known to be good address is still good.
+# The address status is not updated when the probe fails (optimistic
+# caching).
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+# 
+address_verify_positive_refresh_time = 7d
+
+# The address_verify_negative_cache configuration parameter specifies
+# whether negative probe results are stored in the address verification
+# cache. When enabled, the cache may pollute quickly with garbage.
+# When disabled, Postfix will generate an address probe for every
+# lookup.
+# 
+address_verify_negative_cache = yes
+
+# The address_verify_negative_expire_time configuration parameter
+# specifies the amount of time after which a rejected address expires
+# from the address verification cache.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+# 
+address_verify_negative_expire_time = 3d
+
+# The address_verify_negative_refresh_time configuration parameter
+# speficies the minimal amount of time after which a proactive probe
+# is sent to verify that a known to be bad address is still bad.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+# 
+address_verify_negative_refresh_time = 2h
index ca3515cb256465b1399bdf1bc576ab95aa1b9718..4ed7cb70bb44f2d13d3a08c11b2b4e00beab5bbd 100644 (file)
@@ -5,7 +5,8 @@ SHELL   = /bin/sh
 DAEMONS        =  bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
        lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \
        showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
-       nqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html
+       nqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html \
+       trace.8.html verify.8.html
 COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
        postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
        postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
@@ -103,10 +104,18 @@ virtual.8.html: ../src/virtual/virtual.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
 
+trace.8.html: bounce.8.html
+       rm -f $@
+       ln -s $? $@
+
 trivial-rewrite.8.html: ../src/trivial-rewrite/trivial-rewrite.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
 
+verify.8.html: ../src/verify/verify.c
+       PATH=../mantools:$$PATH; \
+       srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
+
 postalias.1.html: ../src/postalias/postalias.c
        PATH=../mantools:$$PATH; \
        srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
index 5ee7aeef834bdaa92b87292aa6bfaf11c6057067..99ab2a1bdfc5678e191bd8e9fb0ea9ef76c77d84 100644 (file)
@@ -40,9 +40,9 @@ limits as specified in the <b>master.cf</b> configuration file.
 
 <p>
 
-<li>The <a href="bounce.8.html">bounce or defer</a> daemon is called
-upon left and right by other daemon processes, in order to maintain
-per-message log files with non-delivery status information.
+<li>The <a href="bounce.8.html">bounce, defer, or trace</a> daemon
+is called upon left and right by other daemon processes, in order
+to maintain per-message log files with delivery status information.
 
 <p>
 
@@ -66,6 +66,13 @@ destinations.
 
 <p>
 
+<li>The <a href="verify.8.html">verify</a> daemon maintains the
+address verification cache that is used by the
+\fBreject_unverified_sender\fR and \fBreject_unverified_recipient\fR
+UCE restrictions.
+
+<p>
+
 <li>The <a href="spawn.8.html">spawn</a> daemon listens on a TCP
 port, UNIX-domain socket or FIFO, and runs non-Postfix commands on
 request, with the socket or FIFO connected to the standard input,
index 548369f71848fd943047288259ce537c9c766e3f..8ff624661253d311977009b24742bc1f70f185c1 100644 (file)
@@ -12,26 +12,27 @@ BOUNCE(8)                                               BOUNCE(8)
        non-delivery status information. Each log  file  is  named
        after  the  queue file that it corresponds to, and is kept
        in a queue subdirectory named after the  service  name  in
-       the <b>master.cf</b> file (either <b>bounce</b> or <b>defer</b>).  This program
-       expects to be run from the <a href="master.8.html"><b>master</b>(8)</a> process manager.
+       the  <b>master.cf</b> file (either <b>bounce</b>, <b>defer</b> or <b>trace</b>).  This
+       program expects to be run from the <a href="master.8.html"><b>master</b>(8)</a> process  man-
+       ager.
 
        The <b>bounce</b> daemon processes two types of service requests:
 
-       <b>o</b>      Append  a  recipient status record to a per-message
+       <b>o</b>      Append a recipient status record to  a  per-message
               log file.
 
-       <b>o</b>      Post a bounce message, with a copy of  a  log  file
-              and  of  the corresponding message. When the bounce
+       <b>o</b>      Post  a  bounce  message, with a copy of a log file
+              and of the corresponding message. When  the  bounce
               is posted successfully, the log file is deleted.
 
-       The software does a best effort to notify the sender  that
-       there  was a problem. A notification is sent even when the
+       The  software does a best effort to notify the sender that
+       there was a problem. A notification is sent even when  the
        log file or original message cannot be read.
 
-       Optionally, a client can request that the per-message  log
-       file  be deleted when the requested operation fails.  This
+       Optionally,  a client can request that the per-message log
+       file be deleted when the requested operation fails.   This
        is used by clients that cannot retry transactions by them-
-       selves,  and  that  depend  on  retry  logic  in their own
+       selves, and that  depend  on  retry  logic  in  their  own
        client.
 
 <b>STANDARDS</b>
@@ -43,36 +44,41 @@ BOUNCE(8)                                               BOUNCE(8)
        Problems and transactions are logged to <b>syslogd</b>(8).
 
 <b>BUGS</b>
-       The log files use an  ad-hoc,  unstructured  format.  This
-       will  have  to  change in order to easily support standard
+       The  log  files  use  an ad-hoc, unstructured format. This
+       will have to change in order to  easily  support  standard
        delivery status notifications.
 
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
-       The following <b>main.cf</b> parameters are  especially  relevant
-       to  this  program. See the Postfix <b>main.cf</b> file for syntax
-       details and for default values.  Use  the  <b>postfix</b>  <b>reload</b>
+       The  following  <b>main.cf</b> parameters are especially relevant
+       to this program. See the Postfix <b>main.cf</b> file  for  syntax
+       details  and  for  default  values. Use the <b>postfix</b> <b>reload</b>
        command after a configuration change.
 
        <b>bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
-              The  recipient of single bounce postmaster notices.
+              The recipient of single bounce postmaster  notices.
 
        <b>2bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
-              The recipient of double bounce postmaster  notices.
+              The  recipient of double bounce postmaster notices.
 
        <b>delay</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
               The recipient of "delayed mail" postmaster notices.
 
        <b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b>
-              Limit the amount of original message  context  that
+              Limit  the  amount of original message context that
               is sent in a non-delivery notification.
 
+       <b>backwards</b><i>_</i><b>bounce</b><i>_</i><b>logfile</b><i>_</i><b>compatibility</b>
+              Controls whether the logfile will  be  readable  by
+              old  Postfix  versions that used the ad-hoc logfile
+              format of <i>&</i>lt;<i>address&</i>gt;<i>:</i> <i>text</i>.
+
        <b>mail</b><i>_</i><b>name</b>
-              Use  this mail system name in the introductory text
+              Use this mail system name in the introductory  text
               at the start of a bounce message.
 
        <b>notify</b><i>_</i><b>classes</b>
-              Notify the postmaster of  bounced  mail  when  this
-              parameter  includes  the  <b>bounce</b> class. For privacy
+              Notify  the  postmaster  of  bounced mail when this
+              parameter includes the <b>bounce</b>  class.  For  privacy
               reasons, the message body is not included.
 
 <b>SEE</b> <b>ALSO</b>
@@ -81,7 +87,7 @@ BOUNCE(8)                                               BOUNCE(8)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 2eb68f224d98ca2fd643d75e63d976f1ffa87b3b..ed012cfb19e5201a6675d60e16566f4cf72a7979 100644 (file)
@@ -15,8 +15,8 @@ POSTSUPER(1)                                         POSTSUPER(1)
        By default, <b>postsuper</b> performs  the  operations  requested
        with  the  <b>-s</b>  and  <b>-p</b> command-line options on all Postfix
        queue directories - this includes the <b>incoming</b>, <b>active</b> and
-       <b>deferred</b> directories with mail files and the <b>bounce</b>, <b>defer</b>
-       and <b>flush</b> directories with log files.
+       <b>deferred</b>  directories  with  mail  files  and  the <b>bounce</b>,
+       <b>defer</b>, <b>trace</b> and <b>flush</b> directories with log files.
 
        Options:
 
index b96c79529d82fa33b9da23cf33f496f871449c2f..788233b26831ff83538b46646fba79885d15bba9 100644 (file)
@@ -138,17 +138,22 @@ SENDMAIL(1)                                           SENDMAIL(1)
               This mode of operation is  implemented  by  running
               the <a href="smtpd.8.html"><b>smtpd</b>(8)</a> daemon.
 
+       <b>-bv</b>    Send an email report after verifying each recipient
+              address.  Verification always happens in the  back-
+              ground.  This is useful for testing address rewrit-
+              ing and routing configurations.
+
        <b>-f</b> <i>sender</i>
               Set  the  envelope  sender  address.  This  is  the
               address where delivery problems are sent to, unless
-              the  message contains an <b>Errors-To:</b> message header.
+              the message contains an <b>Errors-To:</b> message  header.
 
        <b>-h</b> <i>hop_count</i> (ignored)
-              Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b>  configura-
+              Hop  count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura-
               tion parameter instead.
 
-       <b>-i</b>     When  reading  a message from standard input, don't
-              treat a line with only a <b>.</b> character as the end  of
+       <b>-i</b>     When reading a message from standard  input,  don't
+              treat  a line with only a <b>.</b> character as the end of
               input.
 
        <b>-m</b> (ignored)
@@ -158,61 +163,60 @@ SENDMAIL(1)                                           SENDMAIL(1)
               Backwards compatibility.
 
        <b>-oA</b><i>alias_database</i>
-              Non-default  alias  database.  Specify  <i>pathname</i> or
+              Non-default alias  database.  Specify  <i>pathname</i>  or
               <i>type</i>:<i>pathname</i>. See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
 
        <b>-o7</b> (ignored)
 
        <b>-o8</b> (ignored)
               To send 8-bit or binary content, use an appropriate
-              MIME  encapsulation  and specify the appropriate <b>-B</b>
+              MIME encapsulation and specify the  appropriate  <b>-B</b>
               command-line option.
 
-       <b>-oi</b>    When reading a message from standard  input,  don't
-              treat  a line with only a <b>.</b> character as the end of
+       <b>-oi</b>    When  reading  a message from standard input, don't
+              treat a line with only a <b>.</b> character as the end  of
               input.
 
        <b>-om</b> (ignored)
-              The sender is  never  eliminated  from  alias  etc.
+              The  sender  is  never  eliminated  from alias etc.
               expansions.
 
        <b>-o</b> <i>x</i> <i>value</i> (ignored)
-              Set  option <i>x</i> to <i>value</i>. Use the equivalent configu-
+              Set option <i>x</i> to <i>value</i>. Use the equivalent  configu-
               ration parameter in <b>main.cf</b> instead.
 
        <b>-r</b> <i>sender</i>
               Set  the  envelope  sender  address.  This  is  the
               address where delivery problems are sent to, unless
-              the message contains an <b>Errors-To:</b> message  header.
+              the  message contains an <b>Errors-To:</b> message header.
 
-       <b>-q</b>     Attempt  to deliver all queued mail. This is imple-
+       <b>-q</b>     Attempt to deliver all queued mail. This is  imple-
               mented by executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
 
        <b>-q</b><i>interval</i> (ignored)
-              The  interval   between   queue   runs.   Use   the
+              The   interval   between   queue   runs.   Use  the
               <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> configuration parameter instead.
 
        <b>-qR</b><i>site</i>
-              Schedule  immediate  delivery  of  all mail that is
+              Schedule immediate delivery of  all  mail  that  is
               queued for the named <i>site</i>. This option accepts only
-              <i>site</i>  names  that are eligible for the "fast flush"
-              service,  and  is  implemented  by  executing   the
+              <i>site</i> names that are eligible for the  "fast  flush"
+              service,   and  is  implemented  by  executing  the
               <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.  See <a href="flushd.8.html"><b>flush</b>(8)</a> for more infor-
               mation about the "fast flush" service.
 
        <b>-qS</b><i>site</i>
-              This command is not  implemented.  Use  the  slower
+              This  command  is  not  implemented. Use the slower
               <b>sendmail</b> <b>-q</b> command instead.
 
-       <b>-t</b>     Extract   recipients  from  message  headers.  This
-              requires that no recipients  be  specified  on  the
+       <b>-t</b>     Extract  recipients  from  message  headers.   This
+              requires  that  no  recipients  be specified on the
               command line.
 
-       <b>-v</b>     Enable verbose logging for debugging purposes. Mul-
-              tiple <b>-v</b> options  make  the  software  increasingly
-              verbose.  For  compatibility  with  mailx and other
-              mail submission software, a single <b>-v</b>  option  pro-
-              duces no output.
+       <b>-v</b>     Send an email report of all delivery attempts (mail
+              delivery  always  happens  in the background). When
+              multiple <b>-v</b> options are given, enable verbose  log-
+              ging for debugging purposes.
 
 <b>SECURITY</b>
        By  design,  this  program  is not set-user (or group) id.
index 7e6267be3518f4542e0a11632fac609cf4d38b2b..d33b3af5309aad48c1d9b854ff272d2a6eda0dcc 100644 (file)
@@ -264,6 +264,9 @@ SMTP(8)                                                   SMTP(8)
               received, a warning is logged that the mail may  be
               delivered multiple times.
 
+       <b>smtp</b><i>_</i><b>rset</b><i>_</i><b>timeout</b>
+              Timeout for sending the <b>RSET</b> command.
+
        <b>smtp</b><i>_</i><b>quit</b><i>_</i><b>timeout</b>
               Timeout  for  sending  the  <b>QUIT</b>  command,  and for
               receiving the server response.
index 350f249424f44407897df78b44b95cf6dbdc8e6d..c481f91551f609ed48817fc8a9a66c933c575a49 100644 (file)
@@ -344,15 +344,19 @@ SMTPD(8)                                                 SMTPD(8)
        <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b>
               Response code when a request is RBL blacklisted.
 
+       <b>multi</b><i>_</i><b>recipient</b><i>_</i><b>bounce</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+              Response  code  when  a  multi-recipient  bounce is
+              blocked.
+
        <b>rbl</b><i>_</i><b>reply</b><i>_</i><b>maps</b>
-              Table  with  template responses for RBL blacklisted
-              requests, indexed by RBL domain  name.  These  tem-
+              Table with template responses for  RBL  blacklisted
+              requests,  indexed  by  RBL domain name. These tem-
               plates   are   used   by   the   <b>reject</b><i>_</i><b>rbl</b><i>_</i><b>*</b>   and
-              <b>reject</b><i>_</i><b>rhsbl</b><i>_</i><b>*</b>     restrictions.     See      also:
+              <b>reject</b><i>_</i><b>rhsbl</b><i>_</i><b>*</b>      restrictions.     See     also:
               <b>default</b><i>_</i><b>rbl</b><i>_</i><b>reply</b> and <b>smtpd</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>.
 
        <b>reject</b><i>_</i><b>code</b>
-              Response  code  when  the  client  matches a <b>reject</b>
+              Response code when  the  client  matches  a  <b>reject</b>
               restriction.
 
        <b>relay</b><i>_</i><b>domains</b><i>_</i><b>reject</b><i>_</i><b>code</b>
@@ -360,7 +364,7 @@ SMTPD(8)                                                 SMTPD(8)
               mail relay policy.
 
        <b>unknown</b><i>_</i><b>address</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Response   code   when   a   client   violates  the
+              Response  code   when   a   client   violates   the
               <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction.
 
        <b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b>
@@ -369,9 +373,17 @@ SMTPD(8)                                                 SMTPD(8)
               tion.
 
        <b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Response  code   when   a   client   violates   the
+              Response   code   when   a   client   violates  the
               <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
 
+       <b>unverified</b><i>_</i><b>sender</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+              Response code when a sender address is known to  be
+              undeliverable.
+
+       <b>unverified</b><i>_</i><b>recipient</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+              Response  code when a recipient address is known to
+              be undeliverable.
+
 <b>SEE</b> <b>ALSO</b>
        <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a> address resolver
        <a href="cleanup.8.html">cleanup(8)</a> message canonicalization
@@ -379,7 +391,7 @@ SMTPD(8)                                                 SMTPD(8)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
diff --git a/postfix/html/trace.8.html b/postfix/html/trace.8.html
new file mode 120000 (symlink)
index 0000000..4de6cc2
--- /dev/null
@@ -0,0 +1 @@
+bounce.8.html
\ No newline at end of file
index 03055c96381f3b2cdb573fec55aa145a89e4d28a..eee2d501dc0285ef8655195d83b4dc00868deb1a 100644 (file)
@@ -686,6 +686,20 @@ is always <b>450</b> in case of a temporary DNS error.
 
 <p>
 
+<a name="reject_unverified_sender">
+
+<dt> <b>reject_unverified_sender</b> <dd> Reject the request when
+mail to the sender address is known to bounce, or when the sender
+address destination is not reachable.  Address verification
+information is managed by the <a href="verify.8.html"> verify</a>(8)
+server.  The <b>unverified_sender_reject_code </b> parameter
+specifies the response when an address is known to bounce (default:
+450, change into 550 when you are confident that it is safe to do
+so). Postfix replies with 450 when an address probe failed due to
+a temporary problem.
+
+<p>
+
 <a name="reject_rhsbl_sender">
 
 <dt> <b>reject_rhsbl_sender</b> <i>domain.tld</i> <dd> Reject the
@@ -956,6 +970,16 @@ restriction at the end of all recipient restrictions.
 
 <p>
 
+<a name="reject_multi_recipient_bounce">
+
+<dt> <b>reject_multi_recipient_bounce</b> <dd> Reject the request
+when the envelope sender is the null address, and the message has
+multiple envelope recipients. The <b>multi_recipient_bounce_reject_code
+</b> parameter specifies the response code for rejected requests
+(default:  <b>550</b>).
+
+<p>
+
 <a name="reject_unknown_recipient_domain">
 
 <dt> <b>reject_unknown_recipient_domain</b> <dd> Reject the request
@@ -966,6 +990,20 @@ is always <b>450</b> in case of a temporary DNS error.
 
 <p>
 
+<a name="reject_unverified_recipient">
+
+<dt> <b>reject_unverified_recipient</b> <dd> Reject the request when
+mail to the recipient address is known to bounce, or when the recipient
+address destination is not reachable.  Address verification
+information is managed by the <a href="verify.8.html"> verify</a>(8)
+server.  The <b>unverified_recipient_reject_code </b> parameter
+specifies the response when an address is known to bounce (default:
+450, change into 550 when you are confident that it is safe to do
+so). Postfix replies with 450 when an address probe failed due to
+a temporary problem.
+
+<p>
+
 <a name="reject_rhsbl_recipient">
 
 <dt> <b>reject_rhsbl_recipient</b> <i>domain.tld</i> <dd> Reject the
diff --git a/postfix/html/verify.8.html b/postfix/html/verify.8.html
new file mode 100644 (file)
index 0000000..f86eeb0
--- /dev/null
@@ -0,0 +1,152 @@
+<html> <head> </head> <body> <pre>
+VERIFY(8)                                               VERIFY(8)
+
+<b>NAME</b>
+       verify - Postfix address verification server
+
+<b>SYNOPSIS</b>
+       <b>verify</b> [generic Postfix daemon options]
+
+<b>DESCRIPTION</b>
+       The Postfix address verification server maintains a record
+       of what recipient addresses are known to be deliverable or
+       undeliverable.
+
+       Addresses are verified by submitting probe messages to the
+       Postfix queue. Probe messages  are  run  through  all  the
+       routing and rewriting machinery except for final delivery,
+       and are discarded rather than being deferred or bounced.
+
+       Address verification relies on the answer from the nearest
+       MTA  for  the  specified  address,  and will therefore not
+       detect all undeliverable addresses.
+
+       This server is designed to run under control by the  Post-
+       fix  master  server.  It  maintains an optional persistent
+       database.  To avoid being interrupted by "postfix stop" in
+       the  middle  of  a  database update, the process runs in a
+       separate process group.
+
+       This server implements the following requests:
+
+       <b>VRFY</b><i>_</i><b>ADDR</b><i>_</i><b>UPDATE</b> <i>address</i> <i>status</i> <i>text</i>
+              Update the status of the specified address.
+
+       <b>VRFY</b><i>_</i><b>ADDR</b><i>_</i><b>QUERY</b> <i>address</i>
+              Look up  the  <i>status</i>  and  <i>text</i>  of  the  specified
+              address.  If the status is unknown, a probe is sent
+              and a default status is returned.
+
+       The server reply status is one of:
+
+       <b>VRFYSTAT</b><i>_</i><b>OK</b>
+              The request completed normally.
+
+       <b>VRFYSTAT</b><i>_</i><b>BAD</b>
+              The server rejected the request (bad request  name,
+              bad request parameter value).
+
+       <b>VRFYSTAT</b><i>_</i><b>FAIL</b>
+              The request failed.
+
+       The recipient status is one of:
+
+       <b>DEL</b><i>_</i><b>RCPT</b><i>_</i><b>STAT</b><i>_</i><b>OK</b>
+              The address is deliverable.
+
+       <b>DEL</b><i>_</i><b>RCPT</b><i>_</i><b>STAT</b><i>_</i><b>DEFER</b>
+              The  address  is  undeliverable  due to a temporary
+              problem.
+
+       <b>DEL</b><i>_</i><b>RCPT</b><i>_</i><b>STAT</b><i>_</i><b>BOUNCE</b>
+              The address is undeliverable  due  to  a  permanent
+              problem.
+
+       <b>DEL</b><i>_</i><b>RCPT</b><i>_</i><b>STAT</b><i>_</i><b>TODO</b>
+              The address status is being determined.
+
+<b>SECURITY</b>
+       The address verification server is not security-sensitive.
+       It does not talk to the network, and it does not  talk  to
+       local  users.  The verify server can run chrooted at fixed
+       low privilege.
+
+       The address verification server can be  coerced  to  store
+       unlimited  amounts  of  garbage.  Limiting  the cache size
+       trades one problem (disk space exhaustion) for another one
+       (poor response time to client requests).
+
+<b>DIAGNOSTICS</b>
+       Problems and transactions are logged to <b>syslogd</b>(8).
+
+<b>BUGS</b>
+       This  prototype  server  uses  synchronous  submission for
+       sending a probe message, which  can  be  slow  on  a  busy
+       machine.
+
+       If  the  persistent  database ever gets corrupted then the
+       world comes to an end and human  intervention  is  needed.
+       This violates a basic Postfix principle.
+
+<b>CONFIGURATION</b> <b>PARAMETERS</b>
+       See  the  Postfix  <b>main.cf</b> file for syntax details and for
+       default values. Use the <b>postfix</b>  <b>reload</b>  command  after  a
+       configuration change.
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>map</b>
+              Optional  table  for  persistent  recipient  status
+              storage. The file  is  opened  before  the  process
+              enters a chroot jail and before it drops root priv-
+              ileges.  By default, the  information  is  kept  in
+              volatile  memory,  and is lost after <b>postfix</b> <b>reload</b>
+              or <b>postfix</b> <b>stop</b>.
+
+              To recover from a  corrupted  address  verification
+              database, delete the file and do <b>postfix</b> <b>reload</b>.
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>sender</b>
+              The sender address to use for probe messages. Spec-
+              ify an empty value (<b>address</b><i>_</i><b>verify</b><i>_</i><b>sender</b> <b>=</b>) or  &lt;&gt;
+              if you want to use the null sender address.
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>positive</b><i>_</i><b>expire</b><i>_</i><b>time</b>
+              The  amount  of time after which a known to be good
+              address expires.
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>positive</b><i>_</i><b>refresh</b><i>_</i><b>time</b>
+              The minimal amount of time after which a  proactive
+              probe  is  sent  to  verify that a known to be good
+              address is still good. The address  status  is  not
+              updated  when the probe fails (optimistic caching).
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>negative</b><i>_</i><b>cache</b>
+              A boolean parameter that controls whether  negative
+              probe  results  are stored in the address verifica-
+              tion cache. When enabled,  the  cache  may  pollute
+              quickly  with  garbage. When disabled, Postfix will
+              generate an address probe for every lookup.
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>negative</b><i>_</i><b>expire</b><i>_</i><b>time</b>
+              The amount of time after which a  rejected  address
+              expires.
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>negative</b><i>_</i><b>refresh</b><i>_</i><b>time</b>
+              The  minimal amount of time after which a proactive
+              probe is sent to verify that  a  known  to  be  bad
+              address is still bad.
+
+<b>SEE</b> <b>ALSO</b>
+       verify_clnt(3) address verification client
+
+<b>LICENSE</b>
+       The  Secure  Mailer  license must be distributed with this
+       software.
+
+<b>AUTHOR(S)</b>
+       Wietse Venema
+       IBM T.J. Watson Research
+       P.O. Box 704
+       Yorktown Heights, NY 10598, USA
+
+                                                        VERIFY(8)
+</pre> </body> </html>
index 279950201b53a7a18b63030d4163dfdfe924b49d..3a54be60c289b4260291fba44cd78341a747e90f 100644 (file)
@@ -5,7 +5,8 @@ SHELL   = /bin/sh
 DAEMONS        = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
        man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \
        man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
-       man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8
+       man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8 \
+       man8/verify.8 man8/trace.8
 COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
        man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
        man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
@@ -85,6 +86,12 @@ man8/smtpd.8: ../src/smtpd/smtpd.c
 man8/virtual.8: ../src/virtual/virtual.c
        ../mantools/srctoman $? >$@
 
+man8/verify.8: ../src/verify/verify.c
+       ../mantools/srctoman $? >$@
+
+man8/trace.8:
+       echo .so man8/bounce.8 >$@
+
 man8/trivial-rewrite.8: ../src/trivial-rewrite/trivial-rewrite.c
        ../mantools/srctoman $? >$@
 
index 3d98b8b0ae96af239354bb356a7c89b829490036..4884c72029d4e765b7c8450061ff91f2f63264ae 100644 (file)
@@ -23,7 +23,7 @@ By default, \fBpostsuper\fR performs the operations requested with the
 \fB-s\fR and \fB-p\fR command-line options on all Postfix queue
 directories - this includes the \fBincoming\fR, \fBactive\fR and
 \fBdeferred\fR directories with mail files and the \fBbounce\fR,
-\fBdefer\fR and \fBflush\fR directories with log files.
+\fBdefer\fR, \fBtrace\fR and \fBflush\fR directories with log files.
 
 Options:
 .IP "\fB-c \fIconfig_dir\fR"
index 785ded0496610306d50afad402471b78d6180c09..6e7f76e6b79ae76d018cb8a592a63678b19d0b00 100644 (file)
@@ -120,6 +120,10 @@ run the process as the \fBmail_owner\fR user.
 .sp
 This mode of operation is implemented by running the
 \fBsmtpd\fR(8) daemon.
+.IP \fB-bv\fR
+Send an email report after verifying each recipient address.
+Verification always happens in the background. This is useful
+for testing address rewriting and routing configurations.
 .IP "\fB-f \fIsender\fR"
 Set the envelope sender address. This is the address where
 delivery problems are sent to, unless the message contains an
@@ -174,10 +178,9 @@ command instead.
 Extract recipients from message headers. This requires that no
 recipients be specified on the command line.
 .IP \fB-v\fR
-Enable verbose logging for debugging purposes. Multiple \fB-v\fR
-options make the software increasingly verbose. For compatibility
-with mailx and other mail submission software, a single \fB-v\fR
-option produces no output.
+Send an email report of all delivery attempts (mail delivery
+always happens in the background). When multiple \fB-v\fR
+options are given, enable verbose logging for debugging purposes.
 .SH SECURITY
 .na
 .nf
index a1afc3faa09ab17800d024cec49319ccb9cb17b1..f36529add83a6c9cb223a27c8165179bd211f8e3 100644 (file)
@@ -16,7 +16,7 @@ The \fBbounce\fR daemon maintains per-message log files with
 non-delivery status information. Each log file is named after the
 queue file that it corresponds to, and is kept in a queue subdirectory
 named after the service name in the \fBmaster.cf\fR file (either
-\fBbounce\fR or \fBdefer\fR).
+\fBbounce\fR, \fBdefer\fR or \fBtrace\fR).
 This program expects to be run from the \fBmaster\fR(8) process
 manager.
 
@@ -70,6 +70,9 @@ The recipient of "delayed mail" postmaster notices.
 .IP \fBbounce_size_limit\fR
 Limit the amount of original message context that is sent in
 a non-delivery notification.
+.IP \fBbackwards_bounce_logfile_compatibility\fR
+Controls whether the logfile will be readable by old Postfix versions
+that used the ad-hoc logfile format of \fI<address>: text\fR.
 .IP \fBmail_name\fR
 Use this mail system name in the introductory text at the
 start of a bounce message.
index 15bee3addf77abd047e22a359571583ba9fa412f..64fa7fae7e2f0c68ce87ebe0bb14d26f8a204524 100644 (file)
@@ -221,6 +221,8 @@ Timeout for sending the message content.
 Timeout for sending the "\fB.\fR" command, and for
 receiving the server response. When no response is received, a
 warning is logged that the mail may be delivered multiple times.
+.IP \fBsmtp_rset_timeout\fR
+Timeout for sending the \fBRSET\fR command.
 .IP \fBsmtp_quit_timeout\fR
 Timeout for sending the \fBQUIT\fR command, and for
 receiving the server response.
index e15f7919c60e2d37366230a16195c834fc0e311d..1b7d59fa3eb6988bfc78858a4b2c8e0f7c24e8f0 100644 (file)
@@ -279,6 +279,8 @@ Response code when a client violates the \fBreject_invalid_hostname\fR
 restriction.
 .IP \fBmaps_rbl_reject_code\fR
 Response code when a request is RBL blacklisted.
+.IP \fBmulti_recipient_bounce_reject_code\fR
+Response code when a multi-recipient bounce is blocked.
 .IP \fBrbl_reply_maps\fR
 Table with template responses for RBL blacklisted requests, indexed by
 RBL domain name. These templates are used by the \fBreject_rbl_*\fR
@@ -298,6 +300,10 @@ violates the \fBreject_unknown_client\fR restriction.
 .IP \fBunknown_hostname_reject_code\fR
 Response code when a client violates the \fBreject_unknown_hostname\fR
 restriction.
+.IP \fBunverified_sender_reject_code\fR
+Response code when a sender address is known to be undeliverable.
+.IP \fBunverified_recipient_reject_code\fR
+Response code when a recipient address is known to be undeliverable.
 .SH SEE ALSO
 .na
 .nf
diff --git a/postfix/man/man8/trace.8 b/postfix/man/man8/trace.8
new file mode 100644 (file)
index 0000000..411dfa1
--- /dev/null
@@ -0,0 +1 @@
+.so man8/bounce.8
diff --git a/postfix/man/man8/verify.8 b/postfix/man/man8/verify.8
new file mode 100644 (file)
index 0000000..6eb33a1
--- /dev/null
@@ -0,0 +1,139 @@
+.TH VERIFY 8 
+.ad
+.fi
+.SH NAME
+verify
+\-
+Postfix address verification server
+.SH SYNOPSIS
+.na
+.nf
+\fBverify\fR [generic Postfix daemon options]
+.SH DESCRIPTION
+.ad
+.fi
+The Postfix address verification server maintains a record
+of what recipient addresses are known to be deliverable or
+undeliverable.
+
+Addresses are verified by submitting probe messages to the
+Postfix queue. Probe messages are run through all the routing
+and rewriting machinery except for final delivery, and are
+discarded rather than being deferred or bounced.
+
+Address verification relies on the answer from the nearest
+MTA for the specified address, and will therefore not detect
+all undeliverable addresses.
+
+This server is designed to run under control by the Postfix
+master server. It maintains an optional persistent database.
+To avoid being interrupted by "postfix stop" in the middle
+of a database update, the process runs in a separate process
+group.
+
+This server implements the following requests:
+.IP "\fBVRFY_ADDR_UPDATE\fI address status text\fR"
+Update the status of the specified address.
+.IP "\fBVRFY_ADDR_QUERY\fI address\fR"
+Look up the \fIstatus\fR and \fItext\fR of the specified address.
+If the status is unknown, a probe is sent and a default status is
+returned.
+.PP
+The server reply status is one of:
+.IP \fBVRFYSTAT_OK\fR
+The request completed normally.
+.IP \fBVRFYSTAT_BAD\fR
+The server rejected the request (bad request name, bad
+request parameter value).
+.IP \fBVRFYSTAT_FAIL\fR
+The request failed.
+.PP
+The recipient status is one of:
+.IP \fBDEL_RCPT_STAT_OK\fR
+The address is deliverable.
+.IP \fBDEL_RCPT_STAT_DEFER\fR
+The address is undeliverable due to a temporary problem.
+.IP \fBDEL_RCPT_STAT_BOUNCE\fR
+The address is undeliverable due to a permanent problem.
+.IP \fBDEL_RCPT_STAT_TODO\fR
+The address status is being determined.
+.SH SECURITY
+.na
+.nf
+.ad
+.fi
+The address verification server is not security-sensitive. It does
+not talk to the network, and it does not talk to local users.
+The verify server can run chrooted at fixed low privilege.
+
+The address verification server can be coerced to store
+unlimited amounts of garbage. Limiting the cache size
+trades one problem (disk space exhaustion) for another
+one (poor response time to client requests).
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems and transactions are logged to \fBsyslogd\fR(8).
+.SH BUGS
+.ad
+.fi
+This prototype server uses synchronous submission for sending
+a probe message, which can be slow on a busy machine.
+
+If the persistent database ever gets corrupted then the world
+comes to an end and human intervention is needed. This violates
+a basic Postfix principle.
+.SH CONFIGURATION PARAMETERS
+.na
+.nf
+.ad
+.fi
+See the Postfix \fBmain.cf\fR file for syntax details and for
+default values. Use the \fBpostfix reload\fR command after a
+configuration change.
+.IP \fBaddress_verify_map\fR
+Optional table for persistent recipient status storage. The file
+is opened before the process enters a chroot jail and before
+it drops root privileges.
+By default, the information is kept in volatile memory,
+and is lost after \fBpostfix reload\fR or \fBpostfix stop\fR.
+.sp
+To recover from a corrupted address verification database,
+delete the file and do \fBpostfix reload\fR.
+.IP \fBaddress_verify_sender\fR
+The sender address to use for probe messages. Specify an empty
+value (\fBaddress_verify_sender =\fR) or \fB<>\fR if you want
+to use the null sender address.
+.IP \fBaddress_verify_positive_expire_time\fR
+The amount of time after which a known to be good address expires.
+.IP \fBaddress_verify_positive_refresh_time\fR
+The minimal amount of time after which a proactive probe is sent to
+verify that a known to be good address is still good. The address
+status is not updated when the probe fails (optimistic caching).
+.IP \fBaddress_verify_negative_cache\fR
+A boolean parameter that controls whether negative probe results
+are stored in the address verification cache. When enabled, the
+cache may pollute quickly with garbage. When disabled, Postfix
+will generate an address probe for every lookup.
+.IP \fBaddress_verify_negative_expire_time\fR
+The amount of time after which a rejected address expires.
+.IP \fBaddress_verify_negative_refresh_time\fR
+The minimal amount of time after which a proactive probe is sent to
+verify that a known to be bad address is still bad.
+.SH SEE ALSO
+.na
+.nf
+verify_clnt(3) address verification client
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index 503ae4368ae0f582d5967695614146a28ebec899..fadc1467865b5098b0bd8b9591e982e40f01b604 100644 (file)
@@ -22,25 +22,25 @@ clobber:
        rm -f $(CONFIG)
 
 ../conf/access: access
-       ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
 ../conf/aliases: aliases0 aliases
-       (cat aliases0; ../mantools/srctoman - aliases | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /') >$@
+       (cat aliases0; srctoman - aliases | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /') >$@
 
 ../conf/canonical: canonical
-       ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
 ../conf/pcre_table: pcre_table
-       ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
 ../conf/regexp_table: regexp_table
-       ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
 ../conf/relocated: relocated
-       ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
 ../conf/transport: transport
-       ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
 ../conf/virtual: virtual
-       ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
index bd8451ea556de88dad1449febdac0ae00e4645d5..aafc24afbd81e258c7da1f3ead79f6017a950050 100644 (file)
@@ -1,10 +1,10 @@
 SHELL  = /bin/sh
 SRCS   = bounce.c bounce_append_service.c bounce_notify_service.c \
        bounce_cleanup.c bounce_notify_util.c bounce_notify_verp.c \
-       bounce_one_service.c
+       bounce_one_service.c bounce_warn_service.c bounce_trace_service.c
 OBJS   = bounce.o bounce_append_service.o bounce_notify_service.o \
        bounce_cleanup.o bounce_notify_util.o bounce_notify_verp.o \
-       bounce_one_service.o
+       bounce_one_service.o bounce_warn_service.o bounce_trace_service.o
 HDRS   = 
 TESTSRC        = 
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -74,6 +74,8 @@ bounce.o: ../../include/mail_queue.h
 bounce.o: ../../include/mail_params.h
 bounce.o: ../../include/mail_conf.h
 bounce.o: ../../include/bounce.h
+bounce.o: ../../include/deliver_request.h
+bounce.o: ../../include/recipient_list.h
 bounce.o: ../../include/mail_addr.h
 bounce.o: ../../include/mail_server.h
 bounce.o: bounce_service.h
@@ -85,11 +87,15 @@ bounce_append_service.o: ../../include/vstring.h
 bounce_append_service.o: ../../include/vbuf.h
 bounce_append_service.o: ../../include/vstream.h
 bounce_append_service.o: ../../include/stringops.h
+bounce_append_service.o: ../../include/mail_params.h
 bounce_append_service.o: ../../include/mail_queue.h
 bounce_append_service.o: ../../include/quote_822_local.h
 bounce_append_service.o: ../../include/quote_flags.h
 bounce_append_service.o: ../../include/deliver_flock.h
 bounce_append_service.o: ../../include/myflock.h
+bounce_append_service.o: ../../include/mail_proto.h
+bounce_append_service.o: ../../include/iostuff.h
+bounce_append_service.o: ../../include/attr.h
 bounce_append_service.o: bounce_service.h
 bounce_append_service.o: ../../include/bounce_log.h
 bounce_cleanup.o: bounce_cleanup.c
@@ -175,3 +181,33 @@ bounce_one_service.o: ../../include/mail_error.h
 bounce_one_service.o: bounce_service.h
 bounce_one_service.o: ../../include/vstring.h
 bounce_one_service.o: ../../include/bounce_log.h
+bounce_trace_service.o: bounce_trace_service.c
+bounce_trace_service.o: ../../include/sys_defs.h
+bounce_trace_service.o: ../../include/msg.h
+bounce_trace_service.o: ../../include/vstream.h
+bounce_trace_service.o: ../../include/vbuf.h
+bounce_trace_service.o: ../../include/mail_params.h
+bounce_trace_service.o: ../../include/mail_queue.h
+bounce_trace_service.o: ../../include/vstring.h
+bounce_trace_service.o: ../../include/post_mail.h
+bounce_trace_service.o: ../../include/cleanup_user.h
+bounce_trace_service.o: ../../include/mail_addr.h
+bounce_trace_service.o: ../../include/mail_error.h
+bounce_trace_service.o: ../../include/name_mask.h
+bounce_trace_service.o: bounce_service.h
+bounce_trace_service.o: ../../include/bounce_log.h
+bounce_warn_service.o: bounce_warn_service.c
+bounce_warn_service.o: ../../include/sys_defs.h
+bounce_warn_service.o: ../../include/msg.h
+bounce_warn_service.o: ../../include/vstream.h
+bounce_warn_service.o: ../../include/vbuf.h
+bounce_warn_service.o: ../../include/name_mask.h
+bounce_warn_service.o: ../../include/mail_params.h
+bounce_warn_service.o: ../../include/mail_queue.h
+bounce_warn_service.o: ../../include/vstring.h
+bounce_warn_service.o: ../../include/post_mail.h
+bounce_warn_service.o: ../../include/cleanup_user.h
+bounce_warn_service.o: ../../include/mail_addr.h
+bounce_warn_service.o: ../../include/mail_error.h
+bounce_warn_service.o: bounce_service.h
+bounce_warn_service.o: ../../include/bounce_log.h
index 83a0273ab5922ba583974862cf30f1266b6d73e3..a4f77b2b9dc72fa9fbaf22413e88718ad7fbd673 100644 (file)
@@ -10,7 +10,7 @@
 /*     non-delivery status information. Each log file is named after the
 /*     queue file that it corresponds to, and is kept in a queue subdirectory
 /*     named after the service name in the \fBmaster.cf\fR file (either
-/*     \fBbounce\fR or \fBdefer\fR).
+/*     \fBbounce\fR, \fBdefer\fR or \fBtrace\fR).
 /*     This program expects to be run from the \fBmaster\fR(8) process
 /*     manager.
 /*
@@ -56,6 +56,9 @@
 /* .IP \fBbounce_size_limit\fR
 /*     Limit the amount of original message context that is sent in
 /*     a non-delivery notification.
+/* .IP \fBbackwards_bounce_logfile_compatibility\fR
+/*     Controls whether the logfile will be readable by old Postfix versions
+/*     that used the ad-hoc logfile format of \fI<address>: text\fR.
 /* .IP \fBmail_name\fR
 /*     Use this mail system name in the introductory text at the
 /*     start of a bounce message.
@@ -132,6 +135,8 @@ static VSTRING *recipient;
 static VSTRING *encoding;
 static VSTRING *sender;
 static VSTRING *verp_delims;
+static VSTRING *dsn_status;
+static VSTRING *dsn_action;
 static VSTRING *why;
 
 #define STR vstring_str
@@ -150,8 +155,10 @@ static int bounce_append_proto(char *service_name, VSTREAM *client)
                            ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
                            ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
                            ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+                           ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
+                           ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
                            ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
-                           ATTR_TYPE_END) != 5) {
+                           ATTR_TYPE_END) != 7) {
        msg_warn("malformed request");
        return (-1);
     }
@@ -160,8 +167,10 @@ static int bounce_append_proto(char *service_name, VSTREAM *client)
        return (-1);
     }
     if (msg_verbose)
-       msg_info("bounce_append_proto: service=%s id=%s to=%s why=%s",
-                service_name, STR(queue_id), STR(recipient), STR(why));
+       msg_info("bounce_append_proto: service=%s id=%s org_to=%s to=%s stat=%s act=%s why=%s",
+                service_name, STR(queue_id), STR(orig_rcpt),
+                STR(recipient), STR(dsn_status),
+                STR(dsn_action), STR(why));
 
     /*
      * On request by the client, set up a trap to delete the log file in case
@@ -174,12 +183,15 @@ static int bounce_append_proto(char *service_name, VSTREAM *client)
      * Execute the request.
      */
     return (bounce_append_service(service_name, STR(queue_id),
-                                 STR(recipient), STR(why)));
+                                 STR(orig_rcpt), STR(recipient),
+                                 STR(dsn_status), STR(dsn_action),
+                                 STR(why)));
 }
 
 /* bounce_notify_proto - bounce_notify server protocol */
 
-static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
+static int bounce_notify_proto(char *service_name, VSTREAM *client,
+                     int (*service) (char *, char *, char *, char *, char *))
 {
     int     flags;
 
@@ -219,14 +231,14 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
     /*
      * Execute the request.
      */
-    return (bounce_notify_service(service_name, STR(queue_name),
-                                 STR(queue_id), STR(encoding),
-                                 STR(sender), flush));
+    return (service(service_name, STR(queue_name),
+                   STR(queue_id), STR(encoding),
+                   STR(sender)));
 }
 
 /* bounce_verp_proto - bounce_notify server protocol, VERP style */
 
-static int bounce_verp_proto(char *service_name, VSTREAM *client, int flush)
+static int bounce_verp_proto(char *service_name, VSTREAM *client)
 {
     char   *myname = "bounce_verp_proto";
     int     flags;
@@ -278,11 +290,11 @@ static int bounce_verp_proto(char *service_name, VSTREAM *client, int flush)
        msg_warn("request to send VERP-style notification of bounced mail");
        return (bounce_notify_service(service_name, STR(queue_name),
                                      STR(queue_id), STR(encoding),
-                                     STR(sender), flush));
+                                     STR(sender)));
     } else
        return (bounce_notify_verp(service_name, STR(queue_name),
                                   STR(queue_id), STR(encoding),
-                                  STR(sender), STR(verp_delims), flush));
+                                  STR(sender), STR(verp_delims)));
 }
 
 /* bounce_one_proto - bounce_one server protocol */
@@ -302,8 +314,10 @@ static int bounce_one_proto(char *service_name, VSTREAM *client)
                            ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
                            ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
                            ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+                           ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
+                           ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_status,
                            ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
-                           ATTR_TYPE_END) != 8) {
+                           ATTR_TYPE_END) != 9) {
        msg_warn("malformed request");
        return (-1);
     }
@@ -321,15 +335,17 @@ static int bounce_one_proto(char *service_name, VSTREAM *client)
        return (-1);
     }
     if (msg_verbose)
-       msg_info("bounce_one_proto: queue=%s id=%s encoding=%s sender=%s recipient=%s why=%s",
+       msg_info("bounce_one_proto: queue=%s id=%s encoding=%s sender=%s orig_to=%s to=%s stat=%s act=%s why=%s",
                 STR(queue_name), STR(queue_id), STR(encoding),
-                STR(sender), STR(recipient), STR(why));
+                STR(sender), STR(orig_rcpt), STR(recipient),
+                STR(dsn_status), STR(dsn_action), STR(why));
 
     /*
      * Execute the request.
      */
     return (bounce_one_service(STR(queue_name), STR(queue_id), STR(encoding),
-                              STR(sender), STR(recipient), STR(why)));
+                              STR(sender), STR(orig_rcpt), STR(recipient),
+                              STR(dsn_status), STR(dsn_action), STR(why)));
 }
 
 /* bounce_service - parse bounce command type and delegate */
@@ -360,11 +376,16 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv)
        msg_warn("malformed request");
        status = -1;
     } else if (command == BOUNCE_CMD_VERP) {
-       status = bounce_verp_proto(service_name, client, REALLY_BOUNCE);
+       status = bounce_verp_proto(service_name, client);
     } else if (command == BOUNCE_CMD_FLUSH) {
-       status = bounce_notify_proto(service_name, client, REALLY_BOUNCE);
+       status = bounce_notify_proto(service_name, client,
+                                    bounce_notify_service);
     } else if (command == BOUNCE_CMD_WARN) {
-       status = bounce_notify_proto(service_name, client, JUST_WARN);
+       status = bounce_notify_proto(service_name, client,
+                                    bounce_warn_service);
+    } else if (command == BOUNCE_CMD_TRACE) {
+       status = bounce_notify_proto(service_name, client,
+                                    bounce_trace_service);
     } else if (command == BOUNCE_CMD_APPEND) {
        status = bounce_append_proto(service_name, client);
     } else if (command == BOUNCE_CMD_ONE) {
@@ -411,6 +432,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
     encoding = vstring_alloc(10);
     sender = vstring_alloc(10);
     verp_delims = vstring_alloc(10);
+    dsn_status = vstring_alloc(10);
+    dsn_action = vstring_alloc(10);
     why = vstring_alloc(10);
 }
 
index 82620f02b7684783cc14efb64cc95b4904dfb6b4..3225b4787830ebd648f44d35a2786b9ca98ad856 100644 (file)
@@ -6,9 +6,13 @@
 /* SYNOPSIS
 /*     #include "bounce_service.h"
 /*
-/*     int     bounce_append_service(queue_id, recipient, why)
+/*     int     bounce_append_service(queue_id, orig_rcpt, recipient,
+/*                                     status, action, why)
 /*     char    *queue_id;
+/*     char    *orig_rcpt;
 /*     char    *recipient;
+/*     char    *status;
+/*     char    *action;
 /*     char    *why;
 /* DESCRIPTION
 /*     This module implements the server side of the bounce_append()
 #include <ctype.h>
 #include <string.h>
 
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
 /* Utility library. */
 
 #include <msg.h>
 
 /* Global library. */
 
+#include <mail_params.h>
 #include <mail_queue.h>
 #include <quote_822_local.h>
 #include <deliver_flock.h>
+#include <mail_proto.h>
 
 /* Application-specific. */
 
@@ -59,7 +69,9 @@
 /* bounce_append_service - append bounce log */
 
 int     bounce_append_service(char *service, char *queue_id,
-                                     char *recipient, char *why)
+                                     char *orig_rcpt, char *recipient,
+                                     char *status, char *action,
+                                     char *why)
 {
     VSTRING *in_buf = vstring_alloc(100);
     VSTRING *out_buf = vstring_alloc(100);
@@ -97,17 +109,31 @@ int     bounce_append_service(char *service, char *queue_id,
      * may change once we replace the present ad-hoc bounce/defer logfile
      * format by one that is transparent for control etc. characters. See
      * also: showq/showq.c.
+     * 
+     * While migrating from old format to new format, allow backwards
+     * compatibility by writing an old-style record before the new-style
+     * records.
      */
     if ((orig_length = vstream_fseek(log, 0L, SEEK_END)) < 0)
        msg_fatal("seek file %s %s: %m", service, queue_id);
 
-    if (*recipient)
-       vstream_fprintf(log, "<%s>: ",
-          printable(vstring_str(quote_822_local(in_buf, recipient)), '?'));
-    else
-       vstream_fprintf(log, "<>: ");
-    vstream_fputs(printable(why, '?'), log);
-    vstream_fputs("\n\n", log);
+    vstream_fputs("\n", log);
+    if (var_oldlog_compat) {
+       vstream_fprintf(log, "<%s>: %s\n", *recipient == 0 ? "" :
+           printable(vstring_str(quote_822_local(in_buf, recipient)), '?'),
+                       printable(why, '?'));
+    }
+    vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_RECIP, *recipient ?
+          printable(vstring_str(quote_822_local(in_buf, recipient)), '?') :
+                   "<>");
+    if (strcasecmp(recipient, orig_rcpt) != 0)
+       vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_ORCPT, *orig_rcpt ?
+          printable(vstring_str(quote_822_local(in_buf, orig_rcpt)), '?') :
+                       "<>");
+    vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_STATUS, printable(status, '?'));
+    vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_ACTION, printable(action, '?'));
+    vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_WHY, printable(why, '?'));
+    vstream_fputs("\n", log);
 
     if (vstream_fflush(log) != 0 || fsync(vstream_fileno(log)) < 0) {
 #ifndef NO_TRUNCATE
index 21652f6b0598a151f137e1c4c8f7e98e28b41b99..8ce07c11ca8c3757cf8d0ae8e251d57ddbbd1572 100644 (file)
@@ -7,7 +7,7 @@
 /*     #include "bounce_service.h"
 /*
 /*     int     bounce_notify_service(queue_name, queue_id, encoding,
-/*                                     sender, flush)
+/*                                     sender)
 /*     char    *queue_name;
 /*     char    *queue_id;
 /*     char    *encoding;
@@ -15,8 +15,8 @@
 /*     int     flush;
 /* DESCRIPTION
 /*     This module implements the server side of the bounce_notify()
-/*     (send bounce message) request. If flush is zero, the logfile
-/*     is not removed, and a warning is sent instead of a bounce.
+/*     (send bounce message) request. The logfile is removed after a
+/*     warning is posted.
 /*
 /*     When a message bounces, a full copy is sent to the originator,
 /*     and an optional  copy of the diagnostics with message headers is
@@ -81,7 +81,7 @@
 
 int     bounce_notify_service(char *service, char *queue_name,
                                      char *queue_id, char *encoding,
-                                     char *recipient, int flush)
+                                     char *recipient)
 {
     BOUNCE_INFO *bounce_info;
     int     bounce_status = 1;
@@ -95,10 +95,11 @@ int     bounce_notify_service(char *service, char *queue_name,
      * Initialize. Open queue file, bounce log, etc.
      */
     bounce_info = bounce_mail_init(service, queue_name, queue_id,
-                                  encoding, flush);
+                                  encoding, BOUNCE_MSG_FAIL);
 
 #define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
 #define NULL_CLEANUP_FLAGS     0
+#define NULL_TRACE_FLAGS       0
 #define BOUNCE_HEADERS         1
 #define BOUNCE_ALL             0
 
@@ -132,17 +133,17 @@ int     bounce_notify_service(char *service, char *queue_name,
      * Single bounce failed. Optionally send a double bounce to postmaster.
      */
 #define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE)
-#define SKIP_IF_BOUNCE (flush == 1 && (notify_mask & ANY_BOUNCE) == 0)
-#define SKIP_IF_DELAY  (flush == 0 && (notify_mask & MAIL_ERROR_DELAY) == 0)
+#define SKIP_IF_BOUNCE ((notify_mask & ANY_BOUNCE) == 0)
 
     else if (*recipient == 0) {
-       if (SKIP_IF_BOUNCE || SKIP_IF_DELAY) {
+       if (SKIP_IF_BOUNCE) {
            bounce_status = 0;
        } else {
-           postmaster = flush ? var_2bounce_rcpt : var_delay_rcpt;
+           postmaster = var_2bounce_rcpt;
            if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                                 postmaster,
-                                                NULL_CLEANUP_FLAGS)) != 0) {
+                                                NULL_CLEANUP_FLAGS,
+                                                NULL_TRACE_FLAGS)) != 0) {
 
                /*
                 * Double bounce to Postmaster. This is the last opportunity
@@ -154,8 +155,7 @@ int     bounce_notify_service(char *service, char *queue_name,
                    && bounce_diagnostic_log(bounce, bounce_info) == 0
                    && bounce_header_dsn(bounce, bounce_info) == 0
                    && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
-                   bounce_original(bounce, bounce_info, flush ?
-                                   BOUNCE_ALL : BOUNCE_HEADERS);
+                   bounce_original(bounce, bounce_info, BOUNCE_ALL);
                bounce_status = post_mail_fclose(bounce);
            }
        }
@@ -166,7 +166,8 @@ int     bounce_notify_service(char *service, char *queue_name,
      */
     else {
        if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
-                                            NULL_CLEANUP_FLAGS)) != 0) {
+                                            NULL_CLEANUP_FLAGS,
+                                            NULL_TRACE_FLAGS)) != 0) {
 
            /*
             * Send the bounce message header, some boilerplate text that
@@ -178,8 +179,7 @@ int     bounce_notify_service(char *service, char *queue_name,
                && bounce_diagnostic_log(bounce, bounce_info) == 0
                && bounce_header_dsn(bounce, bounce_info) == 0
                && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
-               bounce_original(bounce, bounce_info, flush ?
-                               BOUNCE_ALL : BOUNCE_HEADERS);
+               bounce_original(bounce, bounce_info, BOUNCE_ALL);
            bounce_status = post_mail_fclose(bounce);
        }
 
@@ -189,10 +189,9 @@ int     bounce_notify_service(char *service, char *queue_name,
         * This postmaster notice is not critical, so if it fails don't
         * retransmit the bounce that we just generated, just log a warning.
         */
-#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
-#define WANT_IF_DELAY  (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
+#define WANT_IF_BOUNCE ((notify_mask & MAIL_ERROR_BOUNCE))
 
-       if (bounce_status == 0 && (WANT_IF_BOUNCE || WANT_IF_DELAY)
+       if (bounce_status == 0 && (WANT_IF_BOUNCE)
            && strcasecmp(recipient, mail_addr_double_bounce()) != 0) {
 
            /*
@@ -202,10 +201,11 @@ int     bounce_notify_service(char *service, char *queue_name,
             * don't retransmit the bounce that we just generated, just log a
             * warning.
             */
-           postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
+           postmaster = var_bounce_rcpt;
            if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                                 postmaster,
-                                                NULL_CLEANUP_FLAGS)) != 0) {
+                                                NULL_CLEANUP_FLAGS,
+                                                NULL_TRACE_FLAGS)) != 0) {
                if (bounce_header(bounce, bounce_info, postmaster) == 0
                    && bounce_diagnostic_log(bounce, bounce_info) == 0
                    && bounce_header_dsn(bounce, bounce_info) == 0
@@ -224,7 +224,7 @@ int     bounce_notify_service(char *service, char *queue_name,
      * the bounce was posted successfully, and only if we are bouncing for
      * real, not just warning.
      */
-    if (flush != 0 && bounce_status == 0 && mail_queue_remove(service, queue_id)
+    if (bounce_status == 0 && mail_queue_remove(service, queue_id)
        && errno != ENOENT)
        msg_fatal("remove %s %s: %m", service, queue_id);
 
index b8970025b02284e81bc4e6d0850b8958bdf105a6..137c0c99d9e22187485d19245eb480465688061c 100644 (file)
 /*     int     flush;
 /*
 /*     BOUNCE_INFO *bounce_mail_one_init(queue_name, queue_id,
-/*                                     encoding, orig_recipient, why)
+/*                                     encoding, orig_recipient,
+/*                                     recipient, status, why)
 /*     const char *queue_name;
 /*     const char *queue_id;
 /*     const char *encoding;
 /*     const char *orig_recipient;
+/*     const char *recipient;
+/*     const char *status;
 /*     const char *why;
 /*
 /*     void    bounce_mail_free(bounce_info)
 /* bounce_mail_alloc - initialize */
 
 static BOUNCE_INFO *bounce_mail_alloc(const char *service,
-                                                    const char *queue_name,
-                                                    const char *queue_id,
-                                                    const char *encoding,
-                                                    int flush,
-                                                    BOUNCE_LOG *log_handle)
+                                             const char *queue_name,
+                                             const char *queue_id,
+                                             const char *encoding,
+                                             int flush,
+                                             BOUNCE_LOG *log_handle)
 {
     BOUNCE_INFO *bounce_info;
     int     rec_type;
@@ -285,6 +288,9 @@ BOUNCE_INFO *bounce_mail_one_init(const char *queue_name,
                                          const char *queue_id,
                                          const char *encoding,
                                          const char *orig_recipient,
+                                         const char *recipient,
+                                         const char *dsn_status,
+                                         const char *dsn_action,
                                          const char *why)
 {
     BOUNCE_INFO *bounce_info;
@@ -296,7 +302,8 @@ BOUNCE_INFO *bounce_mail_one_init(const char *queue_name,
      */
 #define REALLY_BOUNCE  1
 
-    log_handle = bounce_log_forge(orig_recipient, "5.0.0", why);
+    log_handle = bounce_log_forge(orig_recipient, recipient, dsn_status,
+                                 dsn_action, why);
     bounce_info = bounce_mail_alloc("none", queue_name, queue_id,
                                    encoding, REALLY_BOUNCE, log_handle);
     return (bounce_info);
@@ -336,7 +343,7 @@ int     bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
     /*
      * Non-delivery subject line.
      */
-    if (bounce_info->flush) {
+    if (bounce_info->flush == BOUNCE_MSG_FAIL) {
        post_mail_fputs(bounce, dest == var_bounce_rcpt
                     || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
                        "Subject: Postmaster Copy: Undelivered Mail" :
@@ -346,12 +353,20 @@ int     bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
     /*
      * Delayed mail subject line.
      */
-    else {
+    else if (bounce_info->flush == BOUNCE_MSG_WARN) {
        post_mail_fputs(bounce, dest == var_bounce_rcpt
                     || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
                        "Subject: Postmaster Warning: Delayed Mail" :
                        "Subject: Delayed Mail (still being retried)");
     }
+
+    /*
+     * Address verification or delivery report.
+     */
+    else {
+       post_mail_fputs(bounce, "Subject: Mail Delivery Status Report");
+    }
+
     post_mail_fprintf(bounce, "To: %s",
                      STR(quote_822_local(bounce_info->buf, dest)));
 
@@ -392,15 +407,18 @@ int     bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
      * word wrapping to make the text look nicer. No matter how hard we would
      * try, receiving bounced mail will always suck.
      */
+#define UNDELIVERED(flush) \
+       ((flush) == BOUNCE_MSG_FAIL || (flush) == BOUNCE_MSG_WARN)
+
     post_mail_fprintf(bounce, "This is the %s program at host %s.",
                      var_mail_name, var_myhostname);
     post_mail_fputs(bounce, "");
-    if (bounce_info->flush) {
+    if (bounce_info->flush == BOUNCE_MSG_FAIL) {
        post_mail_fputs(bounce,
               "I'm sorry to have to inform you that the message returned");
        post_mail_fputs(bounce,
               "below could not be delivered to one or more destinations.");
-    } else {
+    } else if (bounce_info->flush == BOUNCE_MSG_WARN) {
        post_mail_fputs(bounce,
                        "####################################################################");
        post_mail_fputs(bounce,
@@ -414,13 +432,15 @@ int     bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
        post_mail_fprintf(bounce,
                          "It will be retried until it is %.1f days old.",
                          var_max_queue_time / 86400.0);
+    } else {
+       post_mail_fputs(bounce,
+               "Enclosed is the mail delivery report that you requested.");
     }
-
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce,
-                     "For further assistance, please send mail to <%s>",
-                     MAIL_ADDR_POSTMASTER);
-    if (bounce_info->flush) {
+    if (UNDELIVERED(bounce_info->flush)) {
+       post_mail_fputs(bounce, "");
+       post_mail_fprintf(bounce,
+                         "For further assistance, please send mail to <%s>",
+                         MAIL_ADDR_POSTMASTER);
        post_mail_fputs(bounce, "");
        post_mail_fprintf(bounce,
               "If you do so, please include this problem report. You can");
@@ -507,7 +527,7 @@ int     bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
     post_mail_fputs(bounce, "");
     post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
     post_mail_fprintf(bounce, "Content-Description: %s",
-                     "Delivery error report");
+                     "Delivery report");
     post_mail_fprintf(bounce, "Content-Type: %s", "message/delivery-status");
 
     /*
@@ -532,21 +552,23 @@ int     bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
 int     bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
 {
     post_mail_fputs(bounce, "");
-#if 0
-    post_mail_fprintf(bounce, "Original-Recipient: rfc822; %s", "whatever");
-#endif
     post_mail_fprintf(bounce, "Final-Recipient: rfc822; %s",
                      bounce_info->log_handle->recipient);
-    post_mail_fprintf(bounce, "Action: %s", bounce_info->flush ?
-                     "failed" : "delayed");
-    post_mail_fprintf(bounce, "Status: %s", bounce_info->log_handle->status);
+    if (bounce_info->log_handle->orig_rcpt)
+       post_mail_fprintf(bounce, "Original-Recipient: rfc822; %s",
+                         bounce_info->log_handle->orig_rcpt);
+    post_mail_fprintf(bounce, "Action: %s",
+                     bounce_info->flush == BOUNCE_MSG_FAIL ?
+                     "failed" : bounce_info->log_handle->dsn_action);
+    post_mail_fprintf(bounce, "Status: %s",
+                     bounce_info->log_handle->dsn_status);
     bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: X-Postfix; %s",
                      bounce_info->log_handle->text);
 #if 0
     post_mail_fprintf(bounce, "Last-Attempt-Date: %s",
                      bounce_info->log_handle->log_time);
 #endif
-    if (bounce_info->flush == 0)
+    if (bounce_info->flush == BOUNCE_MSG_WARN)
        post_mail_fprintf(bounce, "Will-Retry-Until: %s",
                 mail_date(bounce_info->arrival_time + var_max_queue_time));
     return (vstream_ferror(bounce));
@@ -585,8 +607,9 @@ int     bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
      */
     post_mail_fputs(bounce, "");
     post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
-    post_mail_fprintf(bounce, "Content-Description: %s", headers_only ?
-                     "Undelivered Message Headers" : "Undelivered Message");
+    post_mail_fprintf(bounce, "Content-Description: %s%s",
+                     UNDELIVERED(bounce_info->flush) ? "Undelivered " : "",
+                     headers_only ? "Message Headers" : "Message");
     post_mail_fprintf(bounce, "Content-Type: %s", headers_only ?
                      "text/rfc822-headers" : "message/rfc822");
     if (bounce_info->mime_encoding)
index da4606397ff488db896d8f2657aae02394a53842..0577ad4d06fef3e3202c40804cd047210229d6a8 100644 (file)
@@ -7,7 +7,7 @@
 /*     #include "bounce_service.h"
 /*
 /*     int     bounce_notify_verp(service, queue_name, queue_id, sender,
-/*                                     verp_delims, flush)
+/*                                     verp_delims)
 /*     char    *queue_name;
 /*     char    *queue_id;
 /*     char    *sender;
@@ -15,8 +15,8 @@
 /*     int     flush;
 /* DESCRIPTION
 /*     This module implements the server side of the bounce_notify()
-/*     (send bounce message) request. If flush is zero, the logfile
-/*     is not removed, and a warning is sent instead of a bounce.
+/*     (send bounce message) request. The logfile
+/*     is removed after and a warning is posted.
 /*     The bounce recipient address is encoded in VERP format.
 /*     This routine must be used for single bounces only.
 /*
@@ -81,8 +81,8 @@
 
 int     bounce_notify_verp(char *service, char *queue_name,
                                   char *queue_id, char *encoding,
-                                  char *recipient,
-                                  char *verp_delims, int flush)
+                                  char *recipient,
+                                  char *verp_delims)
 {
     char   *myname = "bounce_notify_verp";
     BOUNCE_INFO *bounce_info;
@@ -107,10 +107,11 @@ int     bounce_notify_verp(char *service, char *queue_name,
      * Initialize. Open queue file, bounce log, etc.
      */
     bounce_info = bounce_mail_init(service, queue_name, queue_id,
-                                  encoding, flush);
+                                  encoding, BOUNCE_MSG_FAIL);
 
 #define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
 #define NULL_CLEANUP_FLAGS     0
+#define NULL_TRACE_FLAGS       0
 #define BOUNCE_HEADERS         1
 #define BOUNCE_ALL             0
 
@@ -126,7 +127,8 @@ int     bounce_notify_verp(char *service, char *queue_name,
        verp_sender(verp_buf, verp_delims, recipient,
                    bounce_info->log_handle->recipient);
        if ((bounce = post_mail_fopen_nowait(NULL_SENDER, STR(verp_buf),
-                                            NULL_CLEANUP_FLAGS)) != 0) {
+                                            NULL_CLEANUP_FLAGS,
+                                            NULL_TRACE_FLAGS)) != 0) {
 
            /*
             * Send the bounce message header, some boilerplate text that
@@ -138,8 +140,7 @@ int     bounce_notify_verp(char *service, char *queue_name,
                && bounce_recipient_log(bounce, bounce_info) == 0
                && bounce_header_dsn(bounce, bounce_info) == 0
                && bounce_recipient_dsn(bounce, bounce_info) == 0)
-               bounce_original(bounce, bounce_info, flush ?
-                               BOUNCE_ALL : BOUNCE_HEADERS);
+               bounce_original(bounce, bounce_info, BOUNCE_ALL);
            bounce_status = post_mail_fclose(bounce);
        } else
            bounce_status = 1;
@@ -162,10 +163,9 @@ int     bounce_notify_verp(char *service, char *queue_name,
         * This postmaster notice is not critical, so if it fails don't
         * retransmit the bounce that we just generated, just log a warning.
         */
-#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
-#define WANT_IF_DELAY  (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
+#define WANT_IF_BOUNCE ((notify_mask & MAIL_ERROR_BOUNCE))
 
-       if (WANT_IF_BOUNCE || WANT_IF_DELAY) {
+       if (WANT_IF_BOUNCE) {
 
            /*
             * Send the text with reason for the bounce, and the headers of
@@ -174,10 +174,11 @@ int     bounce_notify_verp(char *service, char *queue_name,
             * don't retransmit the bounce that we just generated, just log a
             * warning.
             */
-           postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
+           postmaster = var_bounce_rcpt;
            if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                                 postmaster,
-                                                NULL_CLEANUP_FLAGS)) != 0) {
+                                                NULL_CLEANUP_FLAGS,
+                                                NULL_TRACE_FLAGS)) != 0) {
                if (bounce_header(bounce, bounce_info, postmaster) == 0
                    && bounce_recipient_log(bounce, bounce_info) == 0
                    && bounce_header_dsn(bounce, bounce_info) == 0
@@ -198,7 +199,7 @@ int     bounce_notify_verp(char *service, char *queue_name,
      * the bounce was posted successfully, and only if we are bouncing for
      * real, not just warning.
      */
-    if (flush != 0 && bounce_status == 0 && mail_queue_remove(service, queue_id)
+    if (bounce_status == 0 && mail_queue_remove(service, queue_id)
        && errno != ENOENT)
        msg_fatal("remove %s %s: %m", service, queue_id);
 
index a654b8324ecf51f40be05ca087db7bb480d9881e..37210d6cec5a247518f245d70eca01708e709861 100644 (file)
@@ -7,12 +7,14 @@
 /*     #include "bounce_service.h"
 /*
 /*     int     bounce_one_service(queue_name, queue_id, encoding,
-/*                                     orig_sender, orig_recipient, why)
+/*                                     orig_sender, orig_recipient,
+/*                                     status, why)
 /*     char    *queue_name;
 /*     char    *queue_id;
 /*     char    *encoding;
 /*     char    *orig_sender;
 /*     char    *orig_recipient;
+/*     char    *status;
 /*     char    *why;
 /* DESCRIPTION
 /*     This module implements the server side of the bounce_one()
@@ -80,7 +82,8 @@
 
 int     bounce_one_service(char *queue_name, char *queue_id, char *encoding,
                                   char *orig_sender, char *orig_recipient,
-                                  char *why)
+                                  char *recipient, char *dsn_status,
+                                  char *dsn_action, char *why)
 {
     BOUNCE_INFO *bounce_info;
     int     bounce_status = 1;
@@ -93,10 +96,13 @@ int     bounce_one_service(char *queue_name, char *queue_id, char *encoding,
      * Initialize. Open queue file, bounce log, etc.
      */
     bounce_info = bounce_mail_one_init(queue_name, queue_id,
-                                      encoding, orig_recipient, why);
+                                      encoding, orig_recipient,
+                                      recipient, dsn_status,
+                                      dsn_action, why);
 
 #define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
 #define NULL_CLEANUP_FLAGS     0
+#define NULL_TRACE_FLAGS       0
 #define BOUNCE_HEADERS         1
 #define BOUNCE_ALL             0
 
@@ -139,7 +145,8 @@ int     bounce_one_service(char *queue_name, char *queue_id, char *encoding,
        } else {
            if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                                 var_2bounce_rcpt,
-                                                NULL_CLEANUP_FLAGS)) != 0) {
+                                                NULL_CLEANUP_FLAGS,
+                                                NULL_TRACE_FLAGS)) != 0) {
 
                /*
                 * Double bounce to Postmaster. This is the last opportunity
@@ -162,7 +169,8 @@ int     bounce_one_service(char *queue_name, char *queue_id, char *encoding,
      */
     else {
        if ((bounce = post_mail_fopen_nowait(NULL_SENDER, orig_sender,
-                                            NULL_CLEANUP_FLAGS)) != 0) {
+                                            NULL_CLEANUP_FLAGS,
+                                            NULL_TRACE_FLAGS)) != 0) {
 
            /*
             * Send the bounce message header, some boilerplate text that
@@ -198,7 +206,8 @@ int     bounce_one_service(char *queue_name, char *queue_id, char *encoding,
             */
            if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                                 var_bounce_rcpt,
-                                                NULL_CLEANUP_FLAGS)) != 0) {
+                                                NULL_CLEANUP_FLAGS,
+                                                NULL_TRACE_FLAGS)) != 0) {
                if (bounce_header(bounce, bounce_info, var_bounce_rcpt) == 0
                    && bounce_recipient_log(bounce, bounce_info) == 0
                    && bounce_header_dsn(bounce, bounce_info) == 0
index 22636e8c7bc8fa5dd9790fa3a3c86157ff6d8e96..3c919e99b9f62efb5db4d61b3f280ccab86dc975 100644 (file)
  /*
   * bounce_append_service.c
   */
-extern int bounce_append_service(char *, char *, char *, char *);
+extern int bounce_append_service(char *, char *, char *, char *, char *, char *, char *);
 
  /*
   * bounce_notify_service.c
   */
-extern int bounce_notify_service(char *, char *, char *, char *, char *, int);
+extern int bounce_notify_service(char *, char *, char *, char *, char *);
+
+ /*
+  * bounce_warn_service.c
+  */
+extern int bounce_warn_service(char *, char *, char *, char *, char *);
+
+ /*
+  * bounce_trace_service.c
+  */
+extern int bounce_trace_service(char *, char *, char *, char *, char *);
 
  /*
   * bounce_notify_verp.c
   */
-extern int bounce_notify_verp(char *, char *, char *, char *, char *, char *, int);
+extern int bounce_notify_verp(char *, char *, char *, char *, char *, char *);
 
  /*
   * bounce_one_service.c
   */
-extern int bounce_one_service(char *, char *, char *, char *, char *, char *);
+extern int bounce_one_service(char *, char *, char *, char *, char *, char *, char *, char *, char *);
 
  /*
   * bounce_cleanup.c
@@ -66,7 +76,7 @@ typedef struct {
 } BOUNCE_INFO;
 
 extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, const char *, int);
-extern BOUNCE_INFO *bounce_mail_one_init(const char *, const char *, const char *, const char *, const char *);
+extern BOUNCE_INFO *bounce_mail_one_init(const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *);
 extern void bounce_mail_free(BOUNCE_INFO *);
 extern int bounce_header(VSTREAM *, BOUNCE_INFO *, const char *);
 extern int bounce_boilerplate(VSTREAM *, BOUNCE_INFO *);
@@ -77,6 +87,10 @@ extern int bounce_recipient_dsn(VSTREAM *, BOUNCE_INFO *);
 extern int bounce_diagnostic_dsn(VSTREAM *, BOUNCE_INFO *);
 extern int bounce_original(VSTREAM *, BOUNCE_INFO *, int);
 
+#define BOUNCE_MSG_FAIL                0
+#define BOUNCE_MSG_WARN                1
+#define BOUNCE_MSG_STATUS      2
+
 /* LICENSE
 /* .ad
 /* .fi
diff --git a/postfix/src/bounce/bounce_trace_service.c b/postfix/src/bounce/bounce_trace_service.c
new file mode 100644 (file)
index 0000000..4a142ff
--- /dev/null
@@ -0,0 +1,126 @@
+/*++
+/* NAME
+/*     bounce_trace_service 3
+/* SUMMARY
+/*     send status report to sender, server side
+/* SYNOPSIS
+/*     #include "bounce_service.h"
+/*
+/*     int     bounce_trace_service(queue_name, queue_id, encoding, sender)
+/*     char    *queue_name;
+/*     char    *queue_id;
+/*     char    *encoding;
+/*     char    *sender;
+/* DESCRIPTION
+/*     This module implements the server side of the trace_flush()
+/*     (send delivery notice) request. The logfile
+/*     is removed after the notice is posted.
+/*
+/*     A status report includes a prelude with human-readable text,
+/*     a DSN-style report, and the email message that was subject of
+/*     the status report.
+/*
+/*     When a status report is sent, the sender address is the empty
+/*     address.
+/* DIAGNOSTICS
+/*     Fatal error: error opening existing file. Warnings: corrupt
+/*     message file. A corrupt message is saved to the "corrupt"
+/*     queue for further inspection.
+/* BUGS
+/* SEE ALSO
+/*     bounce(3) basic bounce service client interface
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_queue.h>
+#include <post_mail.h>
+#include <mail_addr.h>
+#include <mail_error.h>
+
+/* Application-specific. */
+
+#include "bounce_service.h"
+
+#define STR vstring_str
+
+/* bounce_trace_service - send a delivery status notice */
+
+int     bounce_trace_service(char *service, char *queue_name,
+                                    char *queue_id, char *encoding,
+                                    char *recipient)
+{
+    BOUNCE_INFO *bounce_info;
+    int     bounce_status = 1;
+    VSTREAM *bounce;
+
+    /*
+     * Initialize. Open queue file, bounce log, etc.
+     */
+    bounce_info = bounce_mail_init(service, queue_name, queue_id,
+                                  encoding, BOUNCE_MSG_STATUS);
+
+#define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
+#define NULL_CLEANUP_FLAGS     0
+#define NULL_TRACE_FLAGS       0
+#define BOUNCE_ALL             0
+
+    /*
+     * Send a single bounce with a template message header, some boilerplate
+     * text that pretends that we are a polite mail system, the text with
+     * per-recipient status, and a copy of the original message.
+     */
+    if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
+                                        NULL_CLEANUP_FLAGS,
+                                        NULL_TRACE_FLAGS)) != 0) {
+       if (bounce_header(bounce, bounce_info, recipient) == 0
+           && bounce_boilerplate(bounce, bounce_info) == 0
+           && bounce_diagnostic_log(bounce, bounce_info) == 0
+           && bounce_header_dsn(bounce, bounce_info) == 0
+           && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+           bounce_original(bounce, bounce_info, BOUNCE_ALL);
+       bounce_status = post_mail_fclose(bounce);
+    }
+
+    /*
+     * Examine the completion status. Delete the trace log file only when the
+     * status notice was posted successfully.
+     */
+    if (bounce_status == 0 && mail_queue_remove(service, queue_id)
+       && errno != ENOENT)
+       msg_fatal("remove %s %s: %m", service, queue_id);
+
+    /*
+     * Cleanup.
+     */
+    bounce_mail_free(bounce_info);
+
+    return (bounce_status);
+}
diff --git a/postfix/src/bounce/bounce_warn_service.c b/postfix/src/bounce/bounce_warn_service.c
new file mode 100644 (file)
index 0000000..bbc3df2
--- /dev/null
@@ -0,0 +1,225 @@
+/*++
+/* NAME
+/*     bounce_warn_service 3
+/* SUMMARY
+/*     send non-delivery report to sender, server side
+/* SYNOPSIS
+/*     #include "bounce_service.h"
+/*
+/*     int     bounce_warn_service(queue_name, queue_id, encoding, sender)
+/*     char    *queue_name;
+/*     char    *queue_id;
+/*     char    *encoding;
+/*     char    *sender;
+/* DESCRIPTION
+/*     This module implements the server side of the bounce_warn()
+/*     (send delay notice) request. The logfile
+/*     is not removed, and a warning is sent instead of a bounce.
+/*
+/*     When a message bounces, a full copy is sent to the originator,
+/*     and an optional  copy of the diagnostics with message headers is
+/*     sent to the postmaster.  The result is non-zero when the operation
+/*     should be tried again.
+/*
+/*     When a bounce is sent, the sender address is the empty
+/*     address.  When a bounce bounces, an optional double bounce
+/*     with the entire undeliverable mail is sent to the postmaster,
+/*     with as sender address the double bounce address.
+/* DIAGNOSTICS
+/*     Fatal error: error opening existing file. Warnings: corrupt
+/*     message file. A corrupt message is saved to the "corrupt"
+/*     queue for further inspection.
+/* BUGS
+/* SEE ALSO
+/*     bounce(3) basic bounce service client interface
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <name_mask.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_queue.h>
+#include <post_mail.h>
+#include <mail_addr.h>
+#include <mail_error.h>
+
+/* Application-specific. */
+
+#include "bounce_service.h"
+
+#define STR vstring_str
+
+/* bounce_warn_service - send a delayed mail notice */
+
+int     bounce_warn_service(char *service, char *queue_name,
+                                   char *queue_id, char *encoding,
+                                   char *recipient)
+{
+    BOUNCE_INFO *bounce_info;
+    int     bounce_status = 1;
+    int     postmaster_status = 1;
+    VSTREAM *bounce;
+    int     notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks,
+                                   var_notify_classes);
+    char   *postmaster;
+
+    /*
+     * Initialize. Open queue file, bounce log, etc.
+     */
+    bounce_info = bounce_mail_init(service, queue_name, queue_id,
+                                  encoding, BOUNCE_MSG_WARN);
+
+#define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
+#define NULL_CLEANUP_FLAGS     0
+#define NULL_TRACE_FLAGS       0
+#define BOUNCE_HEADERS         1
+
+    /*
+     * The choice of sender address depends on the recipient address. For a
+     * single bounce (a non-delivery notification to the message originator),
+     * the sender address is the empty string. For a double bounce (typically
+     * a failed single bounce, or a postmaster notification that was produced
+     * by any of the mail processes) the sender address is defined by the
+     * var_double_bounce_sender configuration variable. When a double bounce
+     * cannot be delivered, the queue manager blackholes the resulting triple
+     * bounce message.
+     */
+
+    /*
+     * Double bounce failed. Never send a triple bounce.
+     * 
+     * However, this does not prevent double bounces from bouncing on other
+     * systems. In order to cope with this, either the queue manager must
+     * recognize the double-bounce recipient address and discard mail, or
+     * every delivery agent must recognize the double-bounce sender address
+     * and substitute something else so mail does not come back at us.
+     */
+    if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) {
+       msg_warn("%s: undeliverable postmaster notification discarded",
+                queue_id);
+       bounce_status = 0;
+    }
+
+    /*
+     * Single bounce failed. Optionally send a double bounce to postmaster.
+     */
+#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE)
+#define SKIP_IF_DELAY  ((notify_mask & MAIL_ERROR_DELAY) == 0)
+
+    else if (*recipient == 0) {
+       if (SKIP_IF_DELAY) {
+           bounce_status = 0;
+       } else {
+           postmaster = var_delay_rcpt;
+           if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
+                                                postmaster,
+                                                NULL_CLEANUP_FLAGS,
+                                                NULL_TRACE_FLAGS)) != 0) {
+
+               /*
+                * Double bounce to Postmaster. This is the last opportunity
+                * for this message to be delivered. Send the text with
+                * reason for the bounce, and the headers of the original
+                * message. Don't bother sending the boiler-plate text.
+                */
+               if (!bounce_header(bounce, bounce_info, postmaster)
+                   && bounce_diagnostic_log(bounce, bounce_info) == 0
+                   && bounce_header_dsn(bounce, bounce_info) == 0
+                   && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+                   bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
+               bounce_status = post_mail_fclose(bounce);
+           }
+       }
+    }
+
+    /*
+     * Non-bounce failed. Send a single bounce.
+     */
+    else {
+       if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
+                                            NULL_CLEANUP_FLAGS,
+                                            NULL_TRACE_FLAGS)) != 0) {
+
+           /*
+            * Send the bounce message header, some boilerplate text that
+            * pretends that we are a polite mail system, the text with
+            * reason for the bounce, and a copy of the original message.
+            */
+           if (bounce_header(bounce, bounce_info, recipient) == 0
+               && bounce_boilerplate(bounce, bounce_info) == 0
+               && bounce_diagnostic_log(bounce, bounce_info) == 0
+               && bounce_header_dsn(bounce, bounce_info) == 0
+               && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+               bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
+           bounce_status = post_mail_fclose(bounce);
+       }
+
+       /*
+        * Optionally, send a postmaster notice.
+        * 
+        * This postmaster notice is not critical, so if it fails don't
+        * retransmit the bounce that we just generated, just log a warning.
+        */
+#define WANT_IF_DELAY  ((notify_mask & MAIL_ERROR_DELAY))
+
+       if (bounce_status == 0 && WANT_IF_DELAY
+           && strcasecmp(recipient, mail_addr_double_bounce()) != 0) {
+
+           /*
+            * Send the text with reason for the bounce, and the headers of
+            * the original message. Don't bother sending the boiler-plate
+            * text. This postmaster notice is not critical, so if it fails
+            * don't retransmit the bounce that we just generated, just log a
+            * warning.
+            */
+           postmaster = var_delay_rcpt;
+           if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
+                                                postmaster,
+                                                NULL_CLEANUP_FLAGS,
+                                                NULL_TRACE_FLAGS)) != 0) {
+               if (bounce_header(bounce, bounce_info, postmaster) == 0
+                   && bounce_diagnostic_log(bounce, bounce_info) == 0
+                   && bounce_header_dsn(bounce, bounce_info) == 0
+                   && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+                   bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
+               postmaster_status = post_mail_fclose(bounce);
+           }
+           if (postmaster_status)
+               msg_warn("postmaster notice failed while bouncing to %s",
+                        recipient);
+       }
+    }
+
+    /*
+     * Cleanup.
+     */
+    bounce_mail_free(bounce_info);
+
+    return (bounce_status);
+}
index b5fc139927738aceb380d9f1cd381b1a7a2e18f0..362990e1671d20e9d13a1bfaef09f479fc2aea49 100644 (file)
@@ -123,6 +123,8 @@ cleanup_api.o: ../../include/mail_proto.h
 cleanup_api.o: ../../include/iostuff.h
 cleanup_api.o: ../../include/attr.h
 cleanup_api.o: ../../include/bounce.h
+cleanup_api.o: ../../include/deliver_request.h
+cleanup_api.o: ../../include/recipient_list.h
 cleanup_api.o: ../../include/mail_params.h
 cleanup_api.o: ../../include/mail_stream.h
 cleanup_api.o: ../../include/hold_message.h
index 23a0e25537764b17d914b4c99a0458d699e4ee1a..72a7f4a109f5e4b88b97ccdcc50862846f83757c 100644 (file)
@@ -125,10 +125,12 @@ static int deliver_message(DELIVER_REQUEST *request)
     /*
      * Bounce all recipients.
      */
+#define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS(request->flags)
+
     for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
        rcpt = request->rcpt_list.info + nrcpt;
        if (rcpt->offset >= 0) {
-           status = bounce_append(BOUNCE_FLAG_KEEP, request->queue_id,
+           status = bounce_append(BOUNCE_FLAGS(request), request->queue_id,
                                   rcpt->orig_addr, rcpt->address, "none",
                                   request->arrival_time,
                                   "%s", request->nexthop);
index b9c37aa01c48af258ffe6ac71eb2197b3fe8d47b..319924c464c98ef0ec6579a5a824c11d05aa6610 100644 (file)
@@ -20,7 +20,8 @@ SRCS  = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
        tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \
        flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
        verp_sender.c match_parent_style.c mime_state.c header_token.c \
-       strip_addr.c virtual8_maps.c hold_message.c
+       strip_addr.c virtual8_maps.c hold_message.c verify_clnt.c \
+       trace.c log_adhoc.c verify.c
 OBJS   = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
        debug_peer.o debug_process.o defer.o deliver_completed.o \
        deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
@@ -42,7 +43,8 @@ OBJS  = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
        tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \
        flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
        verp_sender.o match_parent_style.o mime_state.o header_token.o \
-       strip_addr.o virtual8_maps.o hold_message.o
+       strip_addr.o virtual8_maps.o hold_message.o verify_clnt.o \
+       trace.o log_adhoc.o verify.o
 HDRS   = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
        config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
        deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
@@ -60,7 +62,8 @@ HDRS  = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
        sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
        mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \
        match_parent_style.h quote_flags.h mime_state.h header_token.h \
-       lex_822.h strip_addr.h virtual8_maps.h hold_message.h
+       lex_822.h strip_addr.h virtual8_maps.h hold_message.h verify_clnt.h \
+       trace.h log_adhoc.h verify.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
        -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -74,7 +77,7 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
        off_cvt quote_822_local rec2stream recdump resolve_clnt \
        resolve_local rewrite_clnt stream2rec string_list tok822_parse \
        quote_821_local mail_conf_time mime_state strip_addr \
-       virtual8_maps
+       virtual8_maps verify_clnt
 
 LIBS   = ../../lib/libutil.a
 LIB_DIR        = ../../lib
@@ -232,6 +235,11 @@ virtual8_maps: $(LIB) $(LIBS)
        $(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
        mv junk $@.o
 
+verify_clnt: $(LIB) $(LIBS)
+       mv $@.o junk
+       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+       mv junk $@.o
+
 tests: tok822_test mime_test mime_nest mime_8bit mime_dom mime_trunc \
        mime_cvt mime_cvt2 mime_cvt3 strip_addr_test tok822_limit_test \
        virtual8_test
@@ -357,6 +365,9 @@ abounce.o: ../../include/iostuff.h
 abounce.o: ../../include/attr.h
 abounce.o: abounce.h
 abounce.o: bounce.h
+abounce.o: deliver_request.h
+abounce.o: ../../include/vstring.h
+abounce.o: recipient_list.h
 been_here.o: been_here.c
 been_here.o: ../../include/sys_defs.h
 been_here.o: ../../include/msg.h
@@ -376,8 +387,13 @@ bounce.o: mail_proto.h
 bounce.o: ../../include/vstream.h
 bounce.o: ../../include/iostuff.h
 bounce.o: ../../include/attr.h
+bounce.o: log_adhoc.h
+bounce.o: verify.h
+bounce.o: deliver_request.h
+bounce.o: recipient_list.h
 bounce.o: defer.h
 bounce.o: bounce.h
+bounce.o: trace.h
 bounce_log.o: bounce_log.c
 bounce_log.o: ../../include/sys_defs.h
 bounce_log.o: ../../include/msg.h
@@ -387,6 +403,10 @@ bounce_log.o: ../../include/vbuf.h
 bounce_log.o: ../../include/vstring.h
 bounce_log.o: ../../include/vstring_vstream.h
 bounce_log.o: ../../include/stringops.h
+bounce_log.o: mail_params.h
+bounce_log.o: mail_proto.h
+bounce_log.o: ../../include/iostuff.h
+bounce_log.o: ../../include/attr.h
 bounce_log.o: mail_queue.h
 bounce_log.o: bounce_log.h
 canon_addr.o: canon_addr.c
@@ -440,6 +460,11 @@ defer.o: mail_proto.h
 defer.o: ../../include/iostuff.h
 defer.o: ../../include/attr.h
 defer.o: flush_clnt.h
+defer.o: verify.h
+defer.o: deliver_request.h
+defer.o: recipient_list.h
+defer.o: log_adhoc.h
+defer.o: trace.h
 defer.o: bounce.h
 defer.o: defer.h
 deliver_completed.o: deliver_completed.c
@@ -562,6 +587,12 @@ hold_message.o: hold_message.h
 is_header.o: is_header.c
 is_header.o: ../../include/sys_defs.h
 is_header.o: is_header.h
+log_adhoc.o: log_adhoc.c
+log_adhoc.o: ../../include/sys_defs.h
+log_adhoc.o: ../../include/msg.h
+log_adhoc.o: ../../include/vstring.h
+log_adhoc.o: ../../include/vbuf.h
+log_adhoc.o: log_adhoc.h
 mail_addr.o: mail_addr.c
 mail_addr.o: ../../include/sys_defs.h
 mail_addr.o: ../../include/stringops.h
@@ -1009,6 +1040,8 @@ post_mail.o: ../../include/msg.h
 post_mail.o: ../../include/vstream.h
 post_mail.o: ../../include/vbuf.h
 post_mail.o: ../../include/vstring.h
+post_mail.o: ../../include/mymalloc.h
+post_mail.o: ../../include/events.h
 post_mail.o: mail_params.h
 post_mail.o: record.h
 post_mail.o: rec_type.h
@@ -1120,6 +1153,15 @@ sent.o: ../../include/sys_defs.h
 sent.o: ../../include/msg.h
 sent.o: ../../include/vstring.h
 sent.o: ../../include/vbuf.h
+sent.o: mail_params.h
+sent.o: verify.h
+sent.o: deliver_request.h
+sent.o: ../../include/vstream.h
+sent.o: recipient_list.h
+sent.o: log_adhoc.h
+sent.o: trace.h
+sent.o: defer.h
+sent.o: bounce.h
 sent.o: sent.h
 smtp_stream.o: smtp_stream.c
 smtp_stream.o: ../../include/sys_defs.h
@@ -1210,6 +1252,51 @@ tok822_tree.o: ../../include/vstring.h
 tok822_tree.o: ../../include/vbuf.h
 tok822_tree.o: tok822.h
 tok822_tree.o: resolve_clnt.h
+trace.o: trace.c
+trace.o: ../../include/sys_defs.h
+trace.o: ../../include/msg.h
+trace.o: ../../include/vstring.h
+trace.o: ../../include/vbuf.h
+trace.o: mail_params.h
+trace.o: mail_proto.h
+trace.o: ../../include/vstream.h
+trace.o: ../../include/iostuff.h
+trace.o: ../../include/attr.h
+trace.o: verify_clnt.h
+trace.o: deliver_request.h
+trace.o: recipient_list.h
+trace.o: log_adhoc.h
+trace.o: bounce.h
+trace.o: trace.h
+verify.o: verify.c
+verify.o: ../../include/sys_defs.h
+verify.o: ../../include/msg.h
+verify.o: ../../include/vstring.h
+verify.o: ../../include/vbuf.h
+verify.o: mail_params.h
+verify.o: mail_proto.h
+verify.o: ../../include/vstream.h
+verify.o: ../../include/iostuff.h
+verify.o: ../../include/attr.h
+verify.o: verify_clnt.h
+verify.o: deliver_request.h
+verify.o: recipient_list.h
+verify.o: log_adhoc.h
+verify.o: verify.h
+verify_clnt.o: verify_clnt.c
+verify_clnt.o: ../../include/sys_defs.h
+verify_clnt.o: ../../include/msg.h
+verify_clnt.o: ../../include/vstream.h
+verify_clnt.o: ../../include/vbuf.h
+verify_clnt.o: ../../include/vstring.h
+verify_clnt.o: ../../include/attr.h
+verify_clnt.o: mail_params.h
+verify_clnt.o: mail_proto.h
+verify_clnt.o: ../../include/iostuff.h
+verify_clnt.o: clnt_stream.h
+verify_clnt.o: verify_clnt.h
+verify_clnt.o: deliver_request.h
+verify_clnt.o: recipient_list.h
 verp_sender.o: verp_sender.c
 verp_sender.o: ../../include/sys_defs.h
 verp_sender.o: ../../include/vstring.h
index 8aa513966d17fbde48ebc1cc9677d84a4d59984e..e05c4e88cd997dc1e8c6b3b7b9b68f74bfd847c0 100644 (file)
 /*     records with recipients that were bounced, and the reason why.
 /*
 /*     bounce_append() appends a reason for non-delivery to the
-/*     bounce log for the named recipient.
+/*     bounce log for the named recipient, updates the address
+/*     verification service, or updates a message delivery record
+/*     on request by the sender. The flags argument determines
+/*     the action.
 /*
 /*     vbounce_append() implements an alternative interface.
 /*
 /* .IP BOUNCE_FLAG_CLEAN
 /*     Delete the bounce log in case of an error (as in: pretend
 /*     that we never even tried to bounce this message).
+/* .IP DEL_REQ_FLAG_VERIFY
+/*     The message is an address verification probe. Update the
+/*     address verification database instead of bouncing mail.
+/* .IP DEL_REQ_FLAG_EXPAND
+/*     The message is an address expansion probe. Update the
+/*     message delivery record instead of bouncing mail.
+/* .IP DEL_REQ_FLAG_RECORD
+/*     This is a normal message with logged delivery. Update the
+/*     message delivery record and bounce the mail.
 /* .RE
 /* .IP queue
 /*     The message queue name of the original message file.
 
 #include <sys_defs.h>
 #include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
-#include <time.h>
 #include <stdarg.h>
 #include <string.h>
 
 
 /* Global library. */
 
-#include "mail_params.h"
-#include "mail_proto.h"
-#include "defer.h"
-#include "bounce.h"
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <log_adhoc.h>
+#include <verify.h>
+#include <defer.h>
+#include <trace.h>
+#include <bounce.h>
 
 /* bounce_append - append reason to per-message bounce log */
 
@@ -180,53 +194,76 @@ int     vbounce_append(int flags, const char *id, const char *orig_rcpt,
                               const char *recipient, const char *relay,
                               time_t entry, const char *fmt, va_list ap)
 {
-    VSTRING *why;
     int     status;
-    int     delay;
 
     /*
-     * When we're pretending that we can't bounce, don't create a defer log
-     * file when we wouldn't keep the bounce log file. That's a lot of
-     * negatives in one sentence.
+     * MTA-requested address verification information is stored in the verify
+     * service database.
      */
-    if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN))
+    if (flags & DEL_REQ_FLAG_VERIFY) {
+       status = vverify_append(id, orig_rcpt, recipient, relay, entry,
+                           "undeliverable", DEL_RCPT_STAT_BOUNCE, fmt, ap);
+       return (status);
+    }
+
+    /*
+     * User-requested address verification information is logged and mailed
+     * to the requesting user.
+     */
+    if (flags & DEL_REQ_FLAG_EXPAND) {
+       status = vtrace_append(flags, id, orig_rcpt, recipient, relay,
+                              entry, "5.0.0", "undeliverable", fmt, ap);
+       return (status);
+    }
+
+    /*
+     * Normal (well almost) delivery. When we're pretending that we can't
+     * bounce, don't create a defer log file when we wouldn't keep the bounce
+     * log file. That's a lot of negatives in one sentence.
+     */
+    else if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN)) {
        return (-1);
+    }
 
-    why = vstring_alloc(100);
-    delay = time((time_t *) 0) - entry;
-    vstring_vsprintf(why, fmt, ap);
-    if (orig_rcpt == 0)
-       orig_rcpt = "";
-    if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
-                           var_defer_service : var_bounce_service,
-                           ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
-                           ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
-                           ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
-                           ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
-                           ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
-                           ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
-                           ATTR_TYPE_END) == 0) {
-       if (*orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
-           msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=%s (%s%s)",
-                    id, recipient, orig_rcpt, relay, delay,
-                    var_soft_bounce ? "deferred" : "bounced",
-                    var_soft_bounce ? "SOFT BOUNCE - " : "",
-                    vstring_str(why));
-       else
-           msg_info("%s: to=<%s>, relay=%s, delay=%d, status=%s (%s%s)",
-                    id, recipient, relay, delay,
-                    var_soft_bounce ? "deferred" : "bounced",
-                    var_soft_bounce ? "SOFT BOUNCE - " : "",
-                    vstring_str(why));
-       status = (var_soft_bounce ? -1 : 0);
-    } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
-       status = defer_append(flags, id, orig_rcpt, recipient, "bounce", entry,
-                             "bounce failed");
-    } else {
-       status = -1;
+    /*
+     * Normal mail delivery. May also send a delivery record to the user.
+     */
+    else {
+       VSTRING *why = vstring_alloc(100);
+       char   *dsn_code = var_soft_bounce ? "4.0.0" : "5.0.0";
+       char   *dsn_action = var_soft_bounce ? "delayed" : "failed";
+       char   *log_status = var_soft_bounce ? "SOFTBOUNCE" : "bounced";
+
+       vstring_vsprintf(why, fmt, ap);
+       if (orig_rcpt == 0)
+           orig_rcpt = "";
+       if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
+                               var_defer_service : var_bounce_service,
+                          ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
+                               ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+                               ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+                               ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
+                               ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+                               ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_code,
+                               ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
+                            ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
+                               ATTR_TYPE_END) == 0
+           && ((flags & DEL_REQ_FLAG_RECORD) == 0
+               || vtrace_append(flags, id, orig_rcpt, recipient, relay,
+                             entry, dsn_code, dsn_action, fmt, ap) == 0)) {
+           vlog_adhoc(id, orig_rcpt, recipient, relay,
+                      entry, log_status, fmt, ap);
+           status = (var_soft_bounce ? -1 : 0);
+       } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
+           status = defer_append(flags, id, orig_rcpt, recipient, relay,
+                                 entry, "%s or %s service failure",
+                                 var_bounce_service, var_trace_service);
+       } else {
+           status = -1;
+       }
+       vstring_free(why);
+       return (status);
     }
-    vstring_free(why);
-    return (status);
 }
 
 /* bounce_flush - flush the bounce log and deliver to the sender */
@@ -284,47 +321,73 @@ int     vbounce_one(int flags, const char *queue, const char *id,
                            const char *relay, time_t entry,
                            const char *fmt, va_list ap)
 {
-    VSTRING *why;
     int     status;
-    int     delay;
 
     /*
-     * When we're not bouncing, then use the standard logfile based
-     * procedure.
+     * MTA-requested address verification information is stored in the verify
+     * service database.
      */
-    if (var_soft_bounce)
+    if (flags & DEL_REQ_FLAG_VERIFY) {
+       status = vverify_append(id, orig_rcpt, recipient, relay, entry,
+                           "undeliverable", DEL_RCPT_STAT_BOUNCE, fmt, ap);
+       return (status);
+    }
+
+    /*
+     * User-requested address verification information is logged and mailed
+     * to the requesting user.
+     */
+    if (flags & DEL_REQ_FLAG_EXPAND) {
+       status = vtrace_append(flags, id, orig_rcpt, recipient, relay,
+                              entry, "5.0.0", "undeliverable", fmt, ap);
+       return (status);
+    }
+
+    /*
+     * When we're not bouncing, then use the standard multi-recipient logfile
+     * based procedure.
+     */
+    else if (var_soft_bounce) {
        return (vbounce_append(flags, id, orig_rcpt, recipient,
                               relay, entry, fmt, ap));
+    }
 
-    why = vstring_alloc(100);
-    delay = time((time_t *) 0) - entry;
-    vstring_vsprintf(why, fmt, ap);
-    if (orig_rcpt == 0)
-       orig_rcpt = "";
-    if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
-                           ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE,
-                           ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
-                           ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
-                           ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
-                           ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
-                           ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
-                           ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
-                           ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
-                           ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
-                           ATTR_TYPE_END) == 0) {
-       if (*orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
-           msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=bounced (%s)",
-                 id, recipient, orig_rcpt, relay, delay, vstring_str(why));
-       else
-           msg_info("%s: to=<%s>, relay=%s, delay=%d, status=bounced (%s)",
-                    id, recipient, relay, delay, vstring_str(why));
-       status = 0;
-    } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
-       status = defer_append(flags, id, orig_rcpt, recipient, "bounce", entry,
-                             "bounce failed");
-    } else {
-       status = -1;
+    /*
+     * Normal mail delivery. May also send a delivery record to the user.
+     */
+    else {
+       VSTRING *why = vstring_alloc(100);
+
+       vstring_vsprintf(why, fmt, ap);
+       if (orig_rcpt == 0)
+           orig_rcpt = "";
+       if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
+                             ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE,
+                               ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+                               ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
+                               ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+                               ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
+                               ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+                               ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
+                               ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+                               ATTR_TYPE_STR, MAIL_ATTR_STATUS, "5.0.0",
+                               ATTR_TYPE_STR, MAIL_ATTR_ACTION, "failed",
+                            ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
+                               ATTR_TYPE_END) == 0
+           && ((flags & DEL_REQ_FLAG_RECORD) == 0
+               || vtrace_append(flags, id, orig_rcpt, recipient, relay,
+                                entry, "5.0.0", "failed", fmt, ap) == 0)) {
+           vlog_adhoc(id, orig_rcpt, recipient, relay,
+                      entry, "bounced", fmt, ap);
+           status = 0;
+       } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
+           status = defer_append(flags, id, orig_rcpt, recipient, relay,
+                                 entry, "%s or %s service failure",
+                                 var_bounce_service, var_trace_service);
+       } else {
+           status = -1;
+       }
+       vstring_free(why);
+       return (status);
     }
-    vstring_free(why);
-    return (status);
 }
index caaccbfb704b86b3e987975604827b8f871cf85b..b8bb117573de240374fe99dfaa942c9ea10ccb06 100644 (file)
 #include <time.h>
 #include <stdarg.h>
 
+ /*
+  * Global library.
+  */
+#include <deliver_request.h>
+
  /*
   * Client interface.
   */
@@ -28,10 +33,10 @@ extern int vbounce_append(int, const char *, const char *, const char *,
                               const char *, time_t, const char *, va_list);
 extern int bounce_flush(int, const char *, const char *, const char *, const char *);
 extern int PRINTFLIKE(10, 11) bounce_one(int, const char *, const char *,
-                                               const char *, const char *,
-                                               const char *, const char *,
-                                               const char *, time_t,
-                                               const char *,...);
+                                                const char *, const char *,
+                                                const char *, const char *,
+                                                const char *, time_t,
+                                                const char *,...);
 extern int vbounce_one(int, const char *, const char *, const char *,
                               const char *, const char *, const char *,
                               const char *, time_t, const char *, va_list);
@@ -44,6 +49,7 @@ extern int vbounce_one(int, const char *, const char *, const char *,
 #define BOUNCE_CMD_WARN                2       /* send warning, don't delete log */
 #define BOUNCE_CMD_VERP                3       /* send log, verp style */
 #define BOUNCE_CMD_ONE         4       /* send one recipient notice */
+#define BOUNCE_CMD_TRACE       5       /* send delivery record */
 
  /*
   * Flags.
index a063ede95ab78bf9532db85312c4b23ec0c8ba28..fb9dea27bc2108d31ba1a937c8d3a11a07d7bc29 100644 (file)
@@ -10,7 +10,9 @@
 /* .in +4
 /*         /* public members... */
 /*         const char *recipient;
-/*         const char *status;
+/*         const char *orig_rcpt;
+/*         const char *dsn_status;
+/*         const char *dsn_action;
 /*         const char *text;
 /* .in -4
 /*     } BOUNCE_LOG;
 /*     void    bounce_log_rewind(bp)
 /*     BOUNCE_LOG *bp;
 /*
-/*     BOUNCE_LOG *bounce_log_forge(recipient, dsn, why)
+/*     BOUNCE_LOG *bounce_log_forge(orig_rcpt, recipient, dsn_status,
+/*                                     dsn_action, why)
+/*     const char *orig_rcpt;
 /*     const char *recipient;
-/*     const char *status;
+/*     const char *dsn_status;
+/*     const char *dsn_action;
 /*     const char *why;
 /*
 /*     void    bounce_log_close(bp)
@@ -63,7 +68,7 @@
 /*     of problems.
 /*
 /*     bounce_log_forge() forges one recipient status record
-/*     without actually accessing a logfile. 
+/*     without actually accessing a logfile.
 /*     The result cannot be used for any logfile access operation
 /*     and must be disposed of by passing it to bounce_log_close().
 /*
 /*     The final recipient address.
 /* .IP text
 /*     The text that explains why the recipient was undeliverable.
-/* .IP status
+/* .IP dsn_status
 /*     String with DSN compatible status code (digit.digit.digit).
+/* .IP dsn_action
+/*     "delivered", "failed", "delayed" and so on.
 /* .PP
 /*     Other fields will be added as the code evolves.
 /* LICENSE
 
 /* Global library. */
 
+#include <mail_params.h>
+#include <mail_proto.h>
 #include <mail_queue.h>
 #include <bounce_log.h>
 
 /* Application-specific. */
 
-#define STR(x) vstring_str(x)
+#define STR(x)         vstring_str(x)
 
 /* bounce_log_init - initialize structure */
 
 static BOUNCE_LOG *bounce_log_init(VSTREAM *fp,
                                           VSTRING *buf,
-                                          const char *recipient,
-                                          const char *status,
-                                          const char *text,
+                                          VSTRING *orcp_buf,
+                                          VSTRING *rcpt_buf,
+                                          VSTRING *status_buf,
+                                          const char *compat_status,
+                                          VSTRING *action_buf,
+                                          const char *compat_action,
+                                          VSTRING *text_buf,
                                           long offset)
 {
     BOUNCE_LOG *bp;
 
+#define SET_BUFFER(bp, buf, str) { \
+       bp->buf = buf; \
+       bp->str = (buf && STR(buf)[0] ? STR(buf) : 0); \
+    }
+
     bp = (BOUNCE_LOG *) mymalloc(sizeof(*bp));
     bp->fp = fp;
     bp->buf = buf;
-    bp->recipient = recipient;
-    bp->status = status;
-    bp->text = text;
+    SET_BUFFER(bp, orcp_buf, orig_rcpt);
+    SET_BUFFER(bp, rcpt_buf, recipient);
+    SET_BUFFER(bp, status_buf, dsn_status);
+    bp->compat_status = compat_status;
+    SET_BUFFER(bp, action_buf, dsn_action);
+    bp->compat_action = compat_action;
+    SET_BUFFER(bp, text_buf, text);
     bp->offset = offset;
     return (bp);
 }
@@ -156,21 +178,30 @@ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id,
     VSTREAM *fp;
 
 #define STREQ(x,y)     (strcmp((x),(y)) == 0)
+#define SAVE_TO_VSTRING(s)     vstring_strcpy(vstring_alloc(10), (s))
 
     /*
      * TODO: peek at the first byte to see if this is an old-style log
      * (<recipient>: text) or a new-style extensible log with multiple
-     * attributes per recipient.
+     * attributes per recipient. That would not help during a transition from
+     * old to new style, where one can expect to find mixed format files.
+     * 
+     * Kluge up default DSN status and action for old-style logfiles.
      */
     if ((fp = mail_queue_open(queue_name, queue_id, flags, mode)) == 0) {
        return (0);
     } else {
        return (bounce_log_init(fp,             /* stream */
                                vstring_alloc(100),     /* buffer */
-                               (const char *) 0,       /* recipient */
+                               vstring_alloc(10),      /* orig_rcpt */
+                               vstring_alloc(10),      /* recipient */
+                               vstring_alloc(10),      /* dsn_status */
                                STREQ(queue_name, MAIL_QUEUE_DEFER) ?
-                               "4.0.0" : "5.0.0",      /* status */
-                               (const char *) 0,       /* text */
+                               "4.0.0" : "5.0.0",      /* compatibility */
+                               vstring_alloc(10),      /* dsn_action */
+                               STREQ(queue_name, MAIL_QUEUE_DEFER) ?
+                               "delayed" : "failed",   /* compatibility */
+                               vstring_alloc(10),      /* text */
                                0));            /* offset */
     }
 }
@@ -182,26 +213,117 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
     char   *recipient;
     char   *text;
     char   *cp;
+    int     state;
+    long    offset;
+
+    /*
+     * Our trivial logfile parser state machine.
+     */
+#define START  0                               /* still searching */
+#define FOUND  1                               /* in logfile entry */
+#define SKIP   2                               /* in deleted entry */
 
-    while ((bp->offset = vstream_ftell(bp->fp)),
+    /*
+     * Initialize.
+     */
+    state = START;
+    bp->recipient = "(unavailable)";
+    bp->orig_rcpt = 0;
+    bp->dsn_status = "(unavailable)";
+    bp->dsn_action = "(unavailable)";
+    bp->text = "(unavailable)";
+
+    /*
+     * Support mixed logfile formats to make transitions easier. The same
+     * file can start with old-style records and end with new-style records.
+     * With backwards compatibility, we even have old format followed by new
+     * format within the same logfile entry!
+     */
+    while ((offset = vstream_ftell(bp->fp)),
           (vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF)) {
 
-       if (STR(bp->buf)[0] == 0)
+       /*
+        * Logfile entries are separated by blank lines. Even the old ad-hoc
+        * logfile format has a blank line after the last record. This means
+        * we can safely use blank lines to detect the start and end of
+        * logfile entries.
+        */
+       if (STR(bp->buf)[0] == 0) {
+           if (state == FOUND)
+               return (bp);
+           state = START;
+           continue;
+       }
+
+       /*
+        * Skip over deleted logfile entries.
+        */
+       if (state == SKIP)
            continue;
 
        /*
-        * Sanitize.
+        * Sanitize. XXX This needs to be done more carefully with new-style
+        * logfile entries.
         */
        cp = printable(STR(bp->buf), '?');
 
        /*
         * Skip over deleted recipients.
         */
-       if (*cp == BOUNCE_LOG_STAT_DELETED)
+       if (*cp == BOUNCE_LOG_STAT_DELETED) {
+           state = SKIP;
            continue;
+       }
+
+       /*
+        * Save the first record offset of this logfile entry so that it can
+        * be marked as deleted.
+        */
+       if (state == START) {
+           state = FOUND;
+           bp->offset = offset;
+       }
 
        /*
-        * Find the recipient address.
+        * New style logfile entries are in "name = value" format.
+        */
+       if (ISALNUM(*cp)) {
+           const char *err;
+           char   *name;
+           char   *value;
+
+           /*
+            * Split into name and value.
+            */
+           if ((err = split_nameval(cp, &name, &value)) != 0) {
+               msg_warn("%s: malformed record: %s", VSTREAM_PATH(bp->fp), err);
+               continue;
+           }
+
+           /*
+            * Save attribute value.
+            */
+           if (STREQ(name, MAIL_ATTR_RECIP)) {
+               bp->recipient = STR(vstring_strcpy(bp->rcpt_buf, *value ?
+                                               value : "(MAILER-DAEMON)"));
+           } else if (STREQ(name, MAIL_ATTR_ORCPT)) {
+               bp->orig_rcpt = STR(vstring_strcpy(bp->orcp_buf, *value ?
+                                               value : "(MAILER-DAEMON)"));
+           } else if (STREQ(name, MAIL_ATTR_STATUS)) {
+               bp->dsn_status = STR(vstring_strcpy(bp->status_buf, value));
+           } else if (STREQ(name, MAIL_ATTR_ACTION)) {
+               bp->dsn_action = STR(vstring_strcpy(bp->action_buf, value));
+           } else if (STREQ(name, MAIL_ATTR_WHY)) {
+               bp->text = STR(vstring_strcpy(bp->text_buf, value));
+           } else {
+               msg_warn("%s: unknown attribute name: %s, ignored",
+                        VSTREAM_PATH(bp->fp), name);
+           }
+           continue;
+       }
+
+       /*
+        * Old-style logfile record. Find the recipient address.
         */
        if (*cp != '<') {
            msg_warn("%s: malformed record: %.30s...",
@@ -215,7 +337,9 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
            continue;
        }
        *cp = 0;
-       bp->recipient = *recipient ? recipient : "(MAILER-DAEMON)";
+       vstring_strcpy(bp->rcpt_buf, *recipient ?
+                      recipient : "(MAILER-DAEMON)");
+       bp->recipient = STR(bp->rcpt_buf);
 
        /*
         * Find the text that explains why mail was not deliverable.
@@ -223,9 +347,15 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
        text = cp + 2;
        while (*text && ISSPACE(*text))
            text++;
-       bp->text = text;
+       vstring_strcpy(bp->text_buf, text);
+       bp->text = STR(bp->text_buf);
 
-       return (bp);
+       /*
+        * Add compatibility status and action info, to make up for data that
+        * was not stored in old-style bounce logfiles.
+        */
+       bp->dsn_status = bp->compat_status;
+       bp->dsn_action = bp->compat_action;
     }
     return (0);
 }
@@ -247,11 +377,20 @@ BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *bp)
 
 /* bounce_log_forge - forge one recipient status record */
 
-BOUNCE_LOG *bounce_log_forge(const char *recipient, const char *status,
+BOUNCE_LOG *bounce_log_forge(const char *orig_rcpt, const char *recipient,
+                            const char *dsn_status, const char *dsn_action,
                                     const char *text)
 {
-    return (bounce_log_init((VSTREAM *) 0, (VSTRING *) 0,
-                           recipient, status, text, 0));
+    return (bounce_log_init((VSTREAM *) 0,
+                           (VSTRING *) 0,
+                           SAVE_TO_VSTRING(orig_rcpt),
+                           SAVE_TO_VSTRING(recipient),
+                           SAVE_TO_VSTRING(dsn_status),
+                           "(unavailable)",
+                           SAVE_TO_VSTRING(dsn_action),
+                           "(unavailable)",
+                           SAVE_TO_VSTRING(text),
+                           0));
 }
 
 /* bounce_log_close - close bounce reader stream */
@@ -266,6 +405,16 @@ int     bounce_log_close(BOUNCE_LOG *bp)
        ret = 0;
     if (bp->buf)
        vstring_free(bp->buf);
+    if (bp->rcpt_buf)
+       vstring_free(bp->rcpt_buf);
+    if (bp->orcp_buf)
+       vstring_free(bp->orcp_buf);
+    if (bp->status_buf)
+       vstring_free(bp->status_buf);
+    if (bp->action_buf)
+       vstring_free(bp->action_buf);
+    if (bp->text_buf)
+       vstring_free(bp->text_buf);
     myfree((char *) bp);
     return (ret);
 }
index a478b7486ba96caf13976e270b4d847575cfec69..e09da9bacd77e5ae4a1707feeb0d5d745f161872 100644 (file)
@@ -24,17 +24,26 @@ typedef struct {
     /* Private. */
     VSTREAM *fp;                       /* open file */
     VSTRING *buf;                      /* I/O buffer */
+    VSTRING *rcpt_buf;                 /* final recipient */
+    VSTRING *orcp_buf;                 /* original recipient */
+    VSTRING *status_buf;               /* dsn code */
+    const char *compat_status;         /* old logfile compatibility */
+    VSTRING *action_buf;               /* dsn action */
+    const char *compat_action;         /* old logfile compatibility */
+    VSTRING *text_buf;                 /* descriptive text */
     /* Public. */
     const char *recipient;             /* final recipient */
-    const char *status;                        /* recipient status */
-    const char *text;                  /* why undeliverable */
+    const char *orig_rcpt;             /* original recipient */
+    const char *dsn_status;            /* dsn code */
+    const char *dsn_action;            /* dsn action */
+    const char *text;                  /* descriptive text */
     long    offset;                    /* start of current record */
 } BOUNCE_LOG;
 
 extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, int);
 extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *);
 extern BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *);
-extern BOUNCE_LOG *bounce_log_forge(const char *, const char *, const char *);
+extern BOUNCE_LOG *bounce_log_forge(const char *, const char *, const char *, const char *, const char *);
 extern int bounce_log_close(BOUNCE_LOG *);
 
 #define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET)
index 324d9fc131220c2901b17146a9d997494156ec82..974eaaadfafb5bcc77e5079cfa39e9aad10a6707 100644 (file)
 /*     each recipient whose delivery is deferred, and the reason why.
 /*
 /*     defer_append() appends a record to the per-message defer log,
-/*     with the reason for delayed delivery to the named recipient.
+/*     with the reason for delayed delivery to the named recipient,
+/*     updates the address verification service, or updates a message
+/*     delivery record on request by the sender. The flags argument
+/*     determines the action.
 /*     The result is a convenient non-zero value.
 /*     When the fast flush cache is enabled, the fast flush server is
 /*     notified of deferred mail.
 /* .IP BOUNCE_FLAG_CLEAN
 /*     Delete the defer log in case of an error (as in: pretend
 /*     that we never even tried to defer this message).
+/* .IP DEL_REQ_FLAG_VERIFY
+/*     The message is an address verification probe. Update the
+/*     address verification database instead of deferring mail.
+/* .IP DEL_REQ_FLAG_EXPAND
+/*     The message is an address expansion probe. Update the
+/*     the message delivery record instead of deferring mail.
+/* .IP DEL_REQ_FLAG_RECORD
+/*     This is a normal message with logged delivery. Update the
+/*     message delivery record and defer mail delivery.
 /* .RE
 /* .IP queue
 /*     The message queue name of the original message file.
 
 /* Global library. */
 
-#include "mail_params.h"
-#include "mail_queue.h"
-#include "mail_proto.h"
-#include "flush_clnt.h"
-#include "bounce.h"
-#include "defer.h"
+#include <mail_params.h>
+#include <mail_queue.h>
+#include <mail_proto.h>
+#include <flush_clnt.h>
+#include <verify.h>
+#include <log_adhoc.h>
+#include <trace.h>
+#include <bounce.h>
+#include <defer.h>
 
 #define STR(x) vstring_str(x)
 
@@ -158,45 +173,76 @@ int     vdefer_append(int flags, const char *id, const char *orig_rcpt,
                              const char *recipient, const char *relay,
                              time_t entry, const char *fmt, va_list ap)
 {
-    VSTRING *why = vstring_alloc(100);
-    int     delay = time((time_t *) 0) - entry;
     const char *rcpt_domain;
+    int     status;
 
-    vstring_vsprintf(why, fmt, ap);
-    if (orig_rcpt == 0)
-       orig_rcpt = "";
-    if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
+    /*
+     * MTA-requested address verification information is stored in the verify
+     * service database.
+     */
+    if (flags & DEL_REQ_FLAG_VERIFY) {
+       status = vverify_append(id, orig_rcpt, recipient, relay, entry,
+                            "undeliverable", DEL_RCPT_STAT_DEFER, fmt, ap);
+       return (status);
+    }
+
+    /*
+     * User-requested address verification information is logged and mailed
+     * to the requesting user.
+     */
+    if (flags & DEL_REQ_FLAG_EXPAND) {
+       status = vtrace_append(flags, id, orig_rcpt, recipient, relay,
+                              entry, "4.0.0", "undeliverable", fmt, ap);
+       return (status);
+    }
+
+    /*
+     * Normal mail delivery. May also send a delivery record to the user.
+     */
+    else {
+       VSTRING *why = vstring_alloc(100);
+
+       vstring_vsprintf(why, fmt, ap);
+
+       if (orig_rcpt == 0)
+           orig_rcpt = "";
+       if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
                           ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
                                ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
                                ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
                                ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
                                ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+                               ATTR_TYPE_STR, MAIL_ATTR_STATUS, "4.0.0",
+                               ATTR_TYPE_STR, MAIL_ATTR_ACTION, "delayed",
                             ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
                                ATTR_TYPE_END) != 0)
-           msg_warn("%s: defer service failure", id);
-    if (*orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
-       msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=deferred (%s)",
-                id, recipient, orig_rcpt, relay, delay, vstring_str(why));
-    else
-       msg_info("%s: to=<%s>, relay=%s, delay=%d, status=deferred (%s)",
-                id, recipient, relay, delay, vstring_str(why));
-    vstring_free(why);
+           msg_warn("%s: %s service failure", id, var_defer_service);
+       vlog_adhoc(id, orig_rcpt, recipient, relay, entry, "deferred", fmt, ap);
 
-    /*
-     * Notify the fast flush service. XXX Should not this belong in the
-     * bounce/defer daemon? Well, doing it here is more robust.
-     */
-    if ((rcpt_domain = strrchr(recipient, '@')) != 0 && *++rcpt_domain != 0)
-       switch (flush_add(rcpt_domain, id)) {
-       case FLUSH_STAT_OK:
-       case FLUSH_STAT_DENY:
-           break;
-       default:
-           msg_warn("unable to talk to fast flush service");
-           break;
-       }
-
-    return (-1);
+       /*
+        * Traced delivery.
+        */
+       if (flags & DEL_REQ_FLAG_RECORD)
+           if (vtrace_append(flags, id, orig_rcpt, recipient, relay,
+                             entry, "4.0.0", "deferred", fmt, ap) != 0)
+               msg_warn("%s: %s service failure", id, var_trace_service);
+
+       /*
+        * Notify the fast flush service. XXX Should not this belong in the
+        * bounce/defer daemon? Well, doing it here is more robust.
+        */
+       if ((rcpt_domain = strrchr(recipient, '@')) != 0 && *++rcpt_domain != 0)
+           switch (flush_add(rcpt_domain, id)) {
+           case FLUSH_STAT_OK:
+           case FLUSH_STAT_DENY:
+               break;
+           default:
+               msg_warn("%s: %s service failure", id, var_flush_service);
+               break;
+           }
+       vstring_free(why);
+       return (-1);
+    }
 }
 
 /* defer_flush - flush the defer log and deliver to the sender */
index acc7bfb9129cbf8da482cd80e8cb8a888cf7ded8..3bb8827f604fa5ab980b9e3058cf81363d893f29 100644 (file)
@@ -21,6 +21,7 @@
   * Global library.
   */
 #include <bounce.h>
+#include <deliver_request.h>
 
  /*
   * External interface.
index c7435afa7343da6681d5a260d52aaa07b2e0cc23..124204a60a761f93c436ed708d992be2697eecfa 100644 (file)
@@ -46,16 +46,38 @@ typedef struct DELIVER_REQUEST {
 #define DEL_REQ_FLAG_SUCCESS   (1<<0)  /* delete successful recipients */
 #define DEL_REQ_FLAG_BOUNCE    (1<<1)  /* unimplemented */
 
+#define DEL_REQ_FLAG_VERIFY    (1<<8)  /* verify recipient, don't deliver */
+#define DEL_REQ_FLAG_EXPAND    (1<<9)  /* verify expansion, don't deliver */
+#define DEL_REQ_FLAG_RECORD    (1<<10) /* record and deliver */
+
+#define DEL_REQ_TRACE_FLAGS_MASK \
+       (DEL_REQ_FLAG_VERIFY | DEL_REQ_FLAG_EXPAND | DEL_REQ_FLAG_RECORD)
+#define DEL_REQ_TRACE_FLAGS(f) ((f) & DEL_REQ_TRACE_FLAGS_MASK)
+
+#define DEL_REQ_TRACE_ONLY_MASK \
+       (DEL_REQ_FLAG_VERIFY | DEL_REQ_FLAG_EXPAND)
+#define DEL_REQ_TRACE_ONLY(f)  ((f) & DEL_REQ_TRACE_ONLY_MASK)
+
+ /*
+  * Per-recipient delivery status. Not to be confused with per-delivery
+  * request status.
+  */
+#define DEL_RCPT_STAT_OK       0
+#define DEL_RCPT_STAT_DEFER    1
+#define DEL_RCPT_STAT_BOUNCE   2
+#define DEL_RCPT_STAT_TODO     3
+
  /*
-  * Delivery status. Note that there are only FINAL and DEFER. This is
-  * because delivery status information can be lost when a delivery agent or
-  * queue manager process terminates prematurely. The only distinctions we
-  * can rely on are "final delivery completed" and "everything else". In the
-  * absence of a definitive statement the queue manager will always have to
-  * be prepared for all possibilities.
+  * Delivery request status. Note that there are only FINAL and DEFER. This
+  * is because delivery status information can be lost when a delivery agent
+  * or queue manager process terminates prematurely. The only distinctions we
+  * can rely on are "final delivery completed" (positive confirmation that
+  * all recipients are marked as done) and "everything else". In the absence
+  * of a definitive statement the queue manager will always have to be
+  * prepared for all possibilities.
   */
-#define DEL_STAT_FINAL         0       /* delivered or bounced */
-#define DEL_STAT_DEFER         (-1)    /* not delivered or bounced */
+#define DEL_STAT_FINAL 0               /* delivered or bounced */
+#define DEL_STAT_DEFER (-1)            /* not delivered or bounced */
 
 typedef struct VSTREAM _deliver_vstream_;
 extern DELIVER_REQUEST *deliver_request_read(_deliver_vstream_ *);
diff --git a/postfix/src/global/log_adhoc.c b/postfix/src/global/log_adhoc.c
new file mode 100644 (file)
index 0000000..e42df74
--- /dev/null
@@ -0,0 +1,127 @@
+/*++
+/* NAME
+/*     log_adhoc 3
+/* SUMMARY
+/*     ad-hoc delivery event logging
+/* SYNOPSIS
+/*     #include <log_adhoc.h>
+/*
+/*     void    log_adhoc(id, orig_rcpt, recipient, relay,
+/*                             entry, status, format, ...)
+/*     const char *id;
+/*     const char *orig_rcpt;
+/*     const char *recipient;
+/*     const char *relay;
+/*     time_t  entry;
+/*     const char *status;
+/*     const char *format;
+/*
+/*     void    vlog_adhoc(id, orig_rcpt, recipient, relay,
+/*                             entry, status, format, ap)
+/*     const char *id;
+/*     const char *orig_rcpt;
+/*     const char *recipient;
+/*     const char *relay;
+/*     time_t  entry;
+/*     const char *status;
+/*     const char *format;
+/*     va_list ap;
+/* DESCRIPTION
+/*     This module logs delivery events in an ad-hoc manner.
+/*
+/*     log_adhoc() appends a record to the mail logfile
+/*
+/*     vlog_adhoc() implements an alternative client interface.
+/*
+/*     Arguments:
+/* .IP queue
+/*     The message queue name of the original message file.
+/* .IP id
+/*     The queue id of the original message file.
+/* .IP orig_rcpt
+/*     The original envelope recipient address. If unavailable,
+/*     specify a null string or null pointer.
+/* .IP recipient
+/*     A recipient address that is being deferred. The domain part
+/*     of the address is marked dead (for a limited amount of time).
+/* .IP sender
+/*     The sender envelope address.
+/* .IP relay
+/*     Host we could (not) talk to.
+/* .IP status
+/*     bounced, deferred, sent, and so on.
+/* .IP entry
+/*     Message arrival time.
+/* .IP format
+/*     Descriptive text.
+/* .IP ap
+/*     Variable-length argument list.
+/* BUGS
+/*     Should be replaced by routines with an attribute-value based
+/*     interface instead of an interface that uses a rigid argument list.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <log_adhoc.h>
+
+/* log_adhoc - defer message delivery */
+
+void    log_adhoc(const char *id, const char *orig_rcpt,
+                         const char *recipient, const char *relay,
+                         time_t entry, const char *status,
+                         const char *fmt,...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vlog_adhoc(id, orig_rcpt, recipient, relay, entry, status, fmt, ap);
+    va_end(ap);
+}
+
+/* vlog_adhoc - defer delivery of queue file */
+
+void    vlog_adhoc(const char *id, const char *orig_rcpt,
+                          const char *recipient, const char *relay,
+                          time_t entry, const char *status,
+                          const char *fmt, va_list ap)
+{
+    VSTRING *why = vstring_alloc(100);
+    int     delay = time((time_t *) 0) - entry;
+
+    vstring_vsprintf(why, fmt, ap);
+    if (orig_rcpt == 0)
+       orig_rcpt = "";
+    if (strcasecmp(recipient, orig_rcpt) != 0)
+       msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=%s (%s)",
+         id, recipient, orig_rcpt, relay, delay, status, vstring_str(why));
+    else
+       msg_info("%s: to=<%s>, relay=%s, delay=%d, status=%s (%s)",
+                id, recipient, relay, delay, status, vstring_str(why));
+    vstring_free(why);
+}
diff --git a/postfix/src/global/log_adhoc.h b/postfix/src/global/log_adhoc.h
new file mode 100644 (file)
index 0000000..7e3108c
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _LOG_ADHOC_H_INCLUDED_
+#define _LOG_ADHOC_H_INCLUDED_
+
+/*++
+/* NAME
+/*     log_adhoc 3h
+/* SUMMARY
+/*     ad-hoc delivery event logging
+/* SYNOPSIS
+/*     #include <log_adhoc.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * System library.
+  */
+#include <stdarg.h>
+#include <time.h>
+
+ /*
+  * Client interface.
+  */
+extern void PRINTFLIKE(7, 8) log_adhoc(const char *, const char *,
+                                              const char *, const char *,
+                                              time_t, const char *,
+                                              const char *,...);
+extern void vlog_adhoc(const char *, const char *,
+                              const char *, const char *,
+                              time_t, const char *,
+                              const char *, va_list);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index 62c849a822c0db10ccc7376d7570bf4328a92364..6d8389974c54aaed4a2c9357722b48c4c58aa3f4 100644 (file)
@@ -86,6 +86,8 @@
 /*     char   *var_showq_service;
 /*     char   *var_error_service;
 /*     char   *var_flush_service;
+/*     char   *var_verify_service;
+/*     char   *var_trace_service;
 /*     int     var_db_create_buf;
 /*     int     var_db_read_buf;
 /*     int     var_mime_maxdepth;
 /*     int     var_strict_7bit_hdrs;
 /*     int     var_strict_8bit_body;
 /*     int     var_strict_encoding;
+/*     int     var_verify_neg_cache;
+/*     int     var_oldlog_compat;
 /*
 /*     void    mail_params_init()
 /* DESCRIPTION
@@ -240,6 +244,8 @@ char   *var_rewrite_service;
 char   *var_showq_service;
 char   *var_error_service;
 char   *var_flush_service;
+char   *var_verify_service;
+char   *var_trace_service;
 int     var_db_create_buf;
 int     var_db_read_buf;
 int     var_mime_maxdepth;
@@ -252,6 +258,8 @@ int     var_strict_8bitmime;
 int     var_strict_7bit_hdrs;
 int     var_strict_8bit_body;
 int     var_strict_encoding;
+int     var_verify_neg_cache;
+int     var_oldlog_compat;
 
 /* check_myhostname - lookup hostname and validate */
 
@@ -467,6 +475,8 @@ void    mail_params_init()
        VAR_SHOWQ_SERVICE, DEF_SHOWQ_SERVICE, &var_showq_service, 1, 0,
        VAR_ERROR_SERVICE, DEF_ERROR_SERVICE, &var_error_service, 1, 0,
        VAR_FLUSH_SERVICE, DEF_FLUSH_SERVICE, &var_flush_service, 1, 0,
+       VAR_VERIFY_SERVICE, DEF_VERIFY_SERVICE, &var_verify_service, 1, 0,
+       VAR_TRACE_SERVICE, DEF_TRACE_SERVICE, &var_trace_service, 1, 0,
        0,
     };
     static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
@@ -513,6 +523,8 @@ void    mail_params_init()
        VAR_STRICT_ENCODING, DEF_STRICT_ENCODING, &var_strict_encoding,
        VAR_DISABLE_MIME_INPUT, DEF_DISABLE_MIME_INPUT, &var_disable_mime_input,
        VAR_DISABLE_MIME_OCONV, DEF_DISABLE_MIME_OCONV, &var_disable_mime_oconv,
+       VAR_VERIFY_NEG_CACHE, DEF_VERIFY_NEG_CACHE, &var_verify_neg_cache,
+       VAR_OLDLOG_COMPAT, DEF_OLDLOG_COMPAT, &var_oldlog_compat,
        VAR_HELPFUL_WARNINGS, DEF_HELPFUL_WARNINGS, &var_helpful_warnings,
        0,
     };
index e2e7894c71ab123c647ade955cda704516483bf1..1da702a1e7bdd1e767b8d4d9dd08eb47a11e0d08 100644 (file)
@@ -683,7 +683,7 @@ extern int var_debug_peer_level;
   * subdirectories, and how deep the forest is.
   */
 #define VAR_HASH_QUEUE_NAMES   "hash_queue_names"
-#define DEF_HASH_QUEUE_NAMES   "incoming,active,deferred,bounce,defer,flush,hold"
+#define DEF_HASH_QUEUE_NAMES   "incoming,active,deferred,bounce,defer,flush,hold,trace"
 extern char *var_hash_queue_names;
 
 #define VAR_HASH_QUEUE_DEPTH   "hash_queue_depth"
@@ -731,6 +731,10 @@ extern int var_smtp_data1_tmout;
 #define DEF_SMTP_DATA2_TMOUT   "600s"
 extern int var_smtp_data2_tmout;
 
+#define VAR_SMTP_RSET_TMOUT    "smtp_rset_timeout"
+#define DEF_SMTP_RSET_TMOUT    "120s"
+extern int var_smtp_rset_tmout;
+
 #define VAR_SMTP_QUIT_TMOUT    "smtp_quit_timeout"
 #define DEF_SMTP_QUIT_TMOUT    "300s"
 extern int var_smtp_quit_tmout;
@@ -955,7 +959,7 @@ extern bool var_lmtp_skip_quit_resp;
 extern int var_lmtp_conn_tmout;
 
 #define VAR_LMTP_RSET_TMOUT    "lmtp_rset_timeout"
-#define DEF_LMTP_RSET_TMOUT    "300s"
+#define DEF_LMTP_RSET_TMOUT    "120s"
 extern int var_lmtp_rset_tmout;
 
 #define VAR_LMTP_LHLO_TMOUT    "lmtp_lhlo_timeout"
@@ -1226,6 +1230,21 @@ extern int var_non_fqdn_code;
 #define DEF_UNK_ADDR_CODE      450
 extern int var_unk_addr_code;
 
+#define REJECT_UNVERIFIED_RECIP "reject_unverified_recipient"
+#define VAR_UNV_RCPT_CODE      "unverified_recipient_reject_code"
+#define DEF_UNV_RCPT_CODE      450
+extern int var_unv_rcpt_code;
+
+#define REJECT_UNVERIFIED_SENDER "reject_unverified_sender"
+#define VAR_UNV_FROM_CODE      "unverified_sender_reject_code"
+#define DEF_UNV_FROM_CODE      450
+extern int var_unv_from_code;
+
+#define REJECT_MUL_RCPT_BOUNCE "reject_multi_recipient_bounce"
+#define VAR_MUL_RCPT_CODE      "multi_recipient_bounce_reject_code"
+#define DEF_MUL_RCPT_CODE      550
+extern int var_mul_rcpt_code;
+
 #define PERMIT_AUTH_DEST       "permit_auth_destination"
 #define REJECT_UNAUTH_DEST     "reject_unauth_destination"
 #define CHECK_RELAY_DOMAINS    "check_relay_domains"
@@ -1589,6 +1608,48 @@ extern char *var_error_service;
 #define DEF_FLUSH_SERVICE              MAIL_SERVICE_FLUSH
 extern char *var_flush_service;
 
+ /*
+  * Address verification service.
+  */
+#define VAR_VERIFY_SERVICE             "address_verify_service_name"
+#define DEF_VERIFY_SERVICE             MAIL_SERVICE_VERIFY
+extern char *var_verify_service;
+
+#define VAR_VERIFY_MAP                 "address_verify_map"
+#define DEF_VERIFY_MAP                 ""
+extern char *var_verify_map;
+
+#define VAR_VERIFY_POS_EXP             "address_verify_positive_expire_time"
+#define DEF_VERIFY_POS_EXP             "31d"
+extern int var_verify_pos_exp;
+
+#define VAR_VERIFY_POS_TRY             "address_verify_positive_refresh_time"
+#define DEF_VERIFY_POS_TRY             "7d"
+extern int var_verify_pos_try;
+
+#define VAR_VERIFY_NEG_EXP             "address_verify_negative_expire_time"
+#define DEF_VERIFY_NEG_EXP             "3d"
+extern int var_verify_neg_exp;
+
+#define VAR_VERIFY_NEG_TRY             "address_verify_negative_refresh_time"
+#define DEF_VERIFY_NEG_TRY             "2h"
+extern int var_verify_neg_try;
+
+#define VAR_VERIFY_NEG_CACHE           "address_verify_negative_cache"
+#define DEF_VERIFY_NEG_CACHE           1
+extern bool var_verify_neg_cache;
+
+#define VAR_VERIFY_SENDER              "address_verify_sender"
+#define DEF_VERIFY_SENDER              "postmaster"
+extern char *var_verify_sender;
+
+ /*
+  * Message delivery trace service.
+  */
+#define VAR_TRACE_SERVICE              "trace_service_name"
+#define DEF_TRACE_SERVICE              MAIL_SERVICE_TRACE
+extern char *var_trace_service;
+
  /*
   * Mailbox/maildir delivery errors that cause delivery to be tried again.
   */
@@ -1664,6 +1725,13 @@ extern bool var_sender_routing;
 #define DEF_XPORT_NULL_KEY     "<>"
 extern char *var_xport_null_key;
 
+ /*
+  * Bounce service controls.
+  */
+#define VAR_OLDLOG_COMPAT              "backwards_bounce_logfile_compatibility"
+#define DEF_OLDLOG_COMPAT              1
+extern bool var_oldlog_compat;
+
 /* LICENSE
 /* .ad
 /* .fi
index 6f6ab8ced9b88029b4d3733172d4686f8cd7ae90..2b55f5cf8e89fbbe2f881a7d13b072ce0031432f 100644 (file)
@@ -49,6 +49,8 @@
 #define MAIL_SERVICE_SHOWQ     "showq"
 #define MAIL_SERVICE_ERROR     "error"
 #define MAIL_SERVICE_FLUSH     "flush"
+#define MAIL_SERVICE_VERIFY    "verify"
+#define MAIL_SERVICE_TRACE     "trace"
 #define MAIL_SERVICE_RELAY     "relay"
 
  /*
@@ -106,6 +108,9 @@ extern char *mail_pathname(const char *, const char *);
 #define MAIL_ATTR_ADDR         "address"
 #define MAIL_ATTR_TRANSPORT    "transport"
 #define MAIL_ATTR_NEXTHOP      "nexthop"
+#define MAIL_ATTR_TRACE_FLAGS  "trace_flags"
+#define MAIL_ATTR_ADDR_STATUS  "recipient_status"
+#define MAIL_ATTR_ACTION       "action"
 
  /*
   * Suffixes for sender_name, sender_domain etc.
index f18fb4516483e81f2126e00edbe6c361a58e2098..b3d692821d440b3d3a13744d08f7f2b9f749ba74 100644 (file)
@@ -25,6 +25,7 @@
 #define MAIL_QUEUE_INCOMING    "incoming"
 #define MAIL_QUEUE_ACTIVE      "active"
 #define MAIL_QUEUE_DEFERRED    "deferred"
+#define MAIL_QUEUE_TRACE       "trace"
 #define MAIL_QUEUE_DEFER       "defer"
 #define MAIL_QUEUE_BOUNCE      "bounce"
 #define MAIL_QUEUE_CORRUPT     "corrupt"
index d27282ccd3f7b8eb143e0556828b6e6d08c59423..bbc64e6fb78342160f9249042573dfffafccea9e 100644 (file)
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only, unless they include the same bugfix as a patch release.
   */
-#define MAIL_RELEASE_DATE      "20021221"
+#define MAIL_RELEASE_DATE      "20021222"
 
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "1.1.12-" MAIL_RELEASE_DATE
+#define DEF_MAIL_VERSION       "2.0.0-" MAIL_RELEASE_DATE
 extern char *var_mail_version;
 
  /*
index 02e3faf0e0e09a819c9a5f6411ea7fc1a3c5fb3e..88a10943c74794110611a6efb29bcdbc23b8bde8 100644 (file)
@@ -6,15 +6,28 @@
 /* SYNOPSIS
 /*     #include <post_mail.h>
 /*
-/*     VSTREAM *post_mail_fopen(sender, recipient, flags)
+/*     VSTREAM *post_mail_fopen(sender, recipient, cleanup_flags, trace_flags)
 /*     const char *sender;
 /*     const char *recipient;
-/*     int     flags;
+/*     int     cleanup_flags;
+/*     int     trace_flags;
 /*
-/*     VSTREAM *post_mail_fopen_nowait(sender, recipient, flags)
+/*     VSTREAM *post_mail_fopen_nowait(sender, recipient, 
+/*                                     cleanup_flags, trace_flags)
 /*     const char *sender;
 /*     const char *recipient;
-/*     int     flags;
+/*     int     cleanup_flags;
+/*     int     trace_flags;
+/*
+/*     VSTREAM *post_mail_fopen_async(sender, recipient, 
+/*                                     cleanup_flags, trace_flags,
+/*                                     notify, context)
+/*     const char *sender;
+/*     const char *recipient;
+/*     int     cleanup_flags;
+/*     int     trace_flags;
+/*     void    (*notify)(char *context);
+/*     char    *context;
 /*
 /*     int     post_mail_fprintf(stream, format, ...)
 /*     VSTREAM *stream;
 /*     only once, and does not wait until the cleanup service is
 /*     available.  Otherwise it is identical to post_mail_fopen().
 /*
+/*     post_mail_fopen_async() contacts the cleanup service and
+/*     invokes the caller-specified notify routine, with the
+/*     caller-specified context, when the service responds.
+/*     IMPORTANT NOTE: closing the stream will not cancel any
+/*     pending I/O or timeout call-back notification.
+/*
 /*     post_mail_fprintf() formats message content (header or body)
 /*     and sends it to the cleanup service.
 /*
 /* .IP recipient
 /*     The recipient envelope address. It is up to the application
 /*     to produce To: headers.
-/* .IP flags
+/* .IP cleanup_flags
 /*     The binary OR of zero or more of the options defined in
-/*     \fI<cleanup_user.h>\fR.
+/*     \fB<cleanup_user.h>\fR.
+/* .IP trace_flags
+/*     Message tracing flags as specified in \fB<deliver_request.h>\fR.
 /* .IP via
 /*     The name of the service responsible for posting this message.
 /* .IP stream
 /*     A stream opened by mail_post_fopen().
+/* .IP notify
+/*     Application call-back routine.
+/* .IP context
+/*     Application call-back context.
 /* DIAGNOSTICS
 /*     post_mail_fopen_nowait() returns a null pointer when the
 /*     cleanup service is not available immediately.
 /*
+/*     post_mail_fopen_async() returns a null pointer when the
+/*     attempt to contact the cleanup service fails immediately.
+/*
 /*     post_mail_fprintf(), post_mail_fputs() post_mail_fclose(),
 /*     and post_mail_buffer() return the binary OR of the error
 /*     status codes defined in \fI<cleanup_user.h>\fR.
 #include <msg.h>
 #include <vstream.h>
 #include <vstring.h>
+#include <mymalloc.h>
+#include <events.h>
 
 /* Global library. */
 
 #include <post_mail.h>
 #include <mail_date.h>
 
+ /*
+  * Call-back state for asynchronous connection requests.
+  */
+typedef struct {
+    char   *sender;
+    char   *recipient;
+    int     cleanup_flags;
+    int     trace_flags;
+    POST_MAIL_NOTIFY notify;
+    void   *context;
+    VSTREAM *stream;
+} POST_MAIL_STATE;
+
 /* post_mail_init - initial negotiations */
 
 static void post_mail_init(VSTREAM *stream, const char *sender,
-                                  const char *recipient, int flags)
+                                  const char *recipient,
+                                  int cleanup_flags, int trace_flags)
 {
     VSTRING *id = vstring_alloc(100);
     long    now = time((time_t *) 0);
@@ -143,7 +187,7 @@ static void post_mail_init(VSTREAM *stream, const char *sender,
                  ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
                  ATTR_TYPE_END) != 1
        || attr_print(stream, ATTR_FLAG_NONE,
-                     ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+                     ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, cleanup_flags,
                      ATTR_TYPE_END) != 0)
        msg_fatal("unable to contact the %s service", var_cleanup_service);
 
@@ -154,6 +198,8 @@ static void post_mail_init(VSTREAM *stream, const char *sender,
     rec_fprintf(stream, REC_TYPE_TIME, "%ld", (long) now);
     rec_fprintf(stream, REC_TYPE_ATTR, "%s=%s",
                MAIL_ATTR_ORIGIN, MAIL_ATTR_ORG_LOCAL);
+    rec_fprintf(stream, REC_TYPE_ATTR, "%s=%d",
+               MAIL_ATTR_TRACE_FLAGS, trace_flags);
     rec_fputs(stream, REC_TYPE_FROM, sender);
     rec_fputs(stream, REC_TYPE_RCPT, recipient);
     rec_fputs(stream, REC_TYPE_MESG, "");
@@ -171,25 +217,111 @@ static void post_mail_init(VSTREAM *stream, const char *sender,
 
 /* post_mail_fopen - prepare for posting a message */
 
-VSTREAM *post_mail_fopen(const char *sender, const char *recipient, int flags)
+VSTREAM *post_mail_fopen(const char *sender, const char *recipient,
+                                int cleanup_flags, int trace_flags)
 {
     VSTREAM *stream;
 
     stream = mail_connect_wait(MAIL_CLASS_PUBLIC, var_cleanup_service);
-    post_mail_init(stream, sender, recipient, flags);
+    post_mail_init(stream, sender, recipient, cleanup_flags, trace_flags);
     return (stream);
 }
 
 /* post_mail_fopen_nowait - prepare for posting a message */
 
 VSTREAM *post_mail_fopen_nowait(const char *sender, const char *recipient,
-                                       int flags)
+                                       int cleanup_flags, int trace_flags)
 {
     VSTREAM *stream;
 
     if ((stream = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service,
                               BLOCKING)) != 0)
-       post_mail_init(stream, sender, recipient, flags);
+       post_mail_init(stream, sender, recipient, cleanup_flags, trace_flags);
+    return (stream);
+}
+
+/* post_mail_open_event - handle asynchronous connection events */
+
+static void post_mail_open_event(int event, char *context)
+{
+    POST_MAIL_STATE *state = (POST_MAIL_STATE *) context;
+    char   *myname = "post_mail_open_event";
+
+    switch (event) {
+
+       /*
+        * Connection established. Request notification when the server sends
+        * the initial response. This intermediate case is necessary for some
+        * versions of LINUX and perhaps Solaris, where UNIX-domain
+        * connect(2) blocks until the server performs an accept(2).
+        */
+    case EVENT_WRITE:
+       if (msg_verbose)
+           msg_info("%s: write event", myname);
+       event_disable_readwrite(vstream_fileno(state->stream));
+       non_blocking(vstream_fileno(state->stream), BLOCKING);
+       event_enable_read(vstream_fileno(state->stream),
+                         post_mail_open_event, (char *) state);
+       return;
+
+       /*
+        * Initial server reply. Stop the watchdog timer, disable further
+        * read events that end up calling this function, and notify the
+        * requestor.
+        */
+    case EVENT_READ:
+       if (msg_verbose)
+           msg_info("%s: read event", myname);
+       event_cancel_timer(post_mail_open_event, context);
+       event_disable_readwrite(vstream_fileno(state->stream));
+       post_mail_init(state->stream, state->sender,
+                      state->recipient, state->cleanup_flags,
+                      state->trace_flags);
+       state->notify(state->context);
+       myfree(state->sender);
+       myfree(state->recipient);
+       myfree((char *) state);
+       return;
+
+       /*
+        * No connection or no initial reply within a conservative time
+        * limit. The system is broken and we give up.
+        */
+    case EVENT_TIME:
+       msg_fatal("timeout connecting to service: %s", var_cleanup_service);
+
+       /*
+        * Broken software or hardware.
+        */
+    default:
+       msg_panic("%s: unknown event type %d", myname, event);
+    }
+}
+
+/* post_mail_fopen_async - prepare for posting a message */
+
+VSTREAM *post_mail_fopen_async(const char *sender, const char *recipient,
+                                      int cleanup_flags, int trace_flags,
+                                    void (*notify) (void *), void *context)
+{
+    VSTREAM *stream;
+    POST_MAIL_STATE *state;
+
+    stream = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, NON_BLOCKING);
+    if (stream != 0) {
+       state = (POST_MAIL_STATE *) mymalloc(sizeof(*state));
+       state->sender = mystrdup(sender);
+       state->recipient = mystrdup(recipient);
+       state->cleanup_flags = cleanup_flags;
+       state->trace_flags = trace_flags;
+       state->notify = notify;
+       state->context = context;
+       state->stream = stream;
+       event_enable_write(vstream_fileno(stream), post_mail_open_event,
+                          (void *) state);
+       event_request_timer(post_mail_open_event, (void *) state,
+                           var_daemon_timeout);
+    }
     return (stream);
 }
 
index 264afc77bfffda24b16f437dd7ca5adf72f154cc..6863d4c6378fb37e4344b02fd22c2c8600070bc3 100644 (file)
  /*
   * External interface.
   */
-extern VSTREAM *post_mail_fopen(const char *, const char *, int);
-extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int);
+typedef void (*POST_MAIL_NOTIFY)(void *);
+extern VSTREAM *post_mail_fopen(const char *, const char *, int, int);
+extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int, int);
+extern VSTREAM *post_mail_fopen_async(const char *, const char *, int, int, POST_MAIL_NOTIFY, void *);
 extern int PRINTFLIKE(2, 3) post_mail_fprintf(VSTREAM *, const char *,...);
 extern int post_mail_fputs(VSTREAM *, const char *);
 extern int post_mail_buffer(VSTREAM *, const char *, int);
index 37c1f207883be48735d5a3c0a278d70573c53fed..b2db87b8562716fa85d163297b0e1c3917a99ef0 100644 (file)
@@ -6,7 +6,9 @@
 /* SYNOPSIS
 /*     #include <sent.h>
 /*
-/*     int     sent(queue_id, orig_rcpt, recipient, relay, entry, format, ...)
+/*     int     sent(flags, queue_id, orig_rcpt, recipient, relay,
+/*                     entry, format, ...)
+/*     int     flags;
 /*     const char *queue_id;
 /*     const char *orig_rcpt;
 /*     const char *recipient;
@@ -14,7 +16,9 @@
 /*     time_t  entry;
 /*     const char *format;
 /*
-/*     int     vsent(queue_id, orig_rcpt, recipient, relay, entry, format, ap)
+/*     int     vsent(flags, queue_id, orig_rcpt, recipient, relay,
+/*                     entry, format, ap)
+/*     int     flags;
 /*     const char *queue_id;
 /*     const char *orig_rcpt;
 /*     const char *recipient;
 /*     const char *format;
 /*     va_list ap;
 /* DESCRIPTION
-/*     sent() logs that a message was successfully delivered.
+/*     sent() logs that a message was successfully delivered,
+/*     updates the address verification service, or updates a
+/*     message delivery record on request by the sender. The
+/*     flags argument determines the action.
 /*
 /*     vsent() implements an alternative interface.
 /*
 /*     Arguments:
+/* .IP flags
+/*     Zero or more of the following:
+/* .RS
+/* .IP SENT_FLAG_NONE
+/*     The message is a normal delivery request.
+/* .IP DEL_REQ_FLAG_VERIFY
+/*     The message is an address verification probe. Update the
+/*     address verification database.
+/* .IP DEL_REQ_FLAG_EXPAND
+/*     The message is an address expansion probe. Update the
+/*     message delivery record.
+/* .IP DEL_REQ_FLAG_RECORD
+/*     This is a normal message with logged delivery. Update the
+/*     the message delivery record.
+/* .RE
 /* .IP queue_id
 /*     The message queue id.
 /* .IP orig_rcpt
@@ -41,9 +63,9 @@
 /*     Message arrival time.
 /* .IP format
 /*     Optional additional information.
-/* .PP
-/*     For convenience, sent() always returns a zero result.
 /* DIAGNOSTICS
+/*     A non-zero result means the operation failed.
+/*
 /*     Fatal: out of memory.
 /* BUGS
 /*     Should be replaced by routines with an attribute-value based
 
 /* Global library. */
 
-#include "sent.h"
+#include <mail_params.h>
+#include <verify.h>
+#include <log_adhoc.h>
+#include <trace.h>
+#include <defer.h>
+#include <sent.h>
+
+/* Application-specific. */
 
 /* sent - log that a message was sent */
 
-int     sent(const char *queue_id, const char *orig_rcpt,
+int     sent(int flags, const char *id, const char *orig_rcpt,
                     const char *recipient, const char *relay,
                     time_t entry, const char *fmt,...)
 {
     va_list ap;
+    int     status;
 
     va_start(ap, fmt);
-    vsent(queue_id, orig_rcpt, recipient, relay, entry, fmt, ap);
+    status = vsent(flags, id, orig_rcpt, recipient, relay, entry, fmt, ap);
     va_end(ap);
-    return (0);
+    return (status);
 }
 
 /* vsent - log that a message was sent */
 
-int     vsent(const char *queue_id, const char *orig_rcpt,
+int     vsent(int flags, const char *id, const char *orig_rcpt,
                      const char *recipient, const char *relay,
                      time_t entry, const char *fmt, va_list ap)
 {
-#define TEXT (vstring_str(text))
-    VSTRING *text = vstring_alloc(100);
-    int     delay = time((time_t *) 0) - entry;
-
-    vstring_vsprintf(text, fmt, ap);
-    if (orig_rcpt && *orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
-       msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=sent%s%s%s",
-                queue_id, recipient, orig_rcpt, relay, delay,
-                *TEXT ? " (" : "", TEXT, *TEXT ? ")" : "");
-    else
-       msg_info("%s: to=<%s>, relay=%s, delay=%d, status=sent%s%s%s",
-                queue_id, recipient, relay, delay,
-                *TEXT ? " (" : "", TEXT, *TEXT ? ")" : "");
-    vstring_free(text);
-    return (0);
+    int     status;
+
+    /*
+     * MTA-requested address verification information is stored in the verify
+     * service database.
+     */
+    if (flags & DEL_REQ_FLAG_VERIFY) {
+       status = vverify_append(id, orig_rcpt, recipient, relay, entry,
+                               "deliverable", DEL_RCPT_STAT_OK, fmt, ap);
+       return (status);
+    }
+
+    /*
+     * User-requested address verification information is logged and mailed
+     * to the requesting user.
+     */
+    if (flags & DEL_REQ_FLAG_EXPAND) {
+       status = vtrace_append(flags, id, orig_rcpt, recipient, relay,
+                              entry, "2.0.0", "deliverable", fmt, ap);
+       return (status);
+    }
+
+    /*
+     * Normal mail delivery. May also send a delivery record to the user.
+     */
+    else {
+       if ((flags & DEL_REQ_FLAG_RECORD) == 0
+           || vtrace_append(flags, id, orig_rcpt, recipient, relay,
+                            entry, "2.0.0", "delivered", fmt, ap) == 0) {
+           vlog_adhoc(id, orig_rcpt, recipient, relay,
+                      entry, "sent", fmt, ap);
+           status = 0;
+       } else {
+           status = defer_append(flags, id, orig_rcpt, recipient,
+                                 relay, entry, "%s: %s service failed",
+                                 id, var_trace_service);
+       }
+       return (status);
+    }
 }
index 92c441427ce2616272435b52f1067cde4cae8072..c552423d5053a528781e84edbf3beda458decf14 100644 (file)
 #include <time.h>
 #include <stdarg.h>
 
+ /*
+  * Global library.
+  */
+#include <deliver_request.h>
+
  /*
   * External interface.
   */
-extern int PRINTFLIKE(6, 7) sent(const char *, const char *, const char *,
+#define SENT_FLAG_NONE (0)
+
+extern int PRINTFLIKE(7, 8) sent(int, const char *, const char *, const char *,
                                    const char *, time_t, const char *,...);
-extern int vsent(const char *, const char *, const char *, const char *,
+extern int vsent(int, const char *, const char *, const char *, const char *,
                         time_t, const char *, va_list);
 
 /* LICENSE
diff --git a/postfix/src/global/trace.c b/postfix/src/global/trace.c
new file mode 100644 (file)
index 0000000..c517a4b
--- /dev/null
@@ -0,0 +1,199 @@
+/*++
+/* NAME
+/*     trace 3
+/* SUMMARY
+/*     user requested delivery tracing
+/* SYNOPSIS
+/*     #include <trace.h>
+/*
+/*     int     trace_append(flags, queue_id, orig_rcpt, recipient, relay,
+/*                             entry, dsn_code, dsn_action, format, ...)
+/*     int     flags;
+/*     const char *queue_id;
+/*     const char *orig_rcpt;
+/*     const char *recipient;
+/*     const char *relay;
+/*     time_t  entry;
+/*     const char *dsn_code;
+/*     const char *dsn_action;
+/*     const char *format;
+/*
+/*     int     vtrace_append(flags, queue_id, orig_rcpt, recipient, relay,
+/*                             entry, dsn_code, dsn_action, format, ap)
+/*     int     flags;
+/*     const char *queue_id;
+/*     const char *orig_rcpt;
+/*     const char *recipient;
+/*     const char *relay;
+/*     time_t  entry;
+/*     const char *dsn_code;
+/*     const char *dsn_action;
+/*     const char *format;
+/*     va_list ap;
+/*
+/*     int     trace_flush(flags, queue, id, encoding, sender)
+/*     int     flags;
+/*     const char *queue;
+/*     const char *id;
+/*     const char *encoding;
+/*     const char *sender;
+/* DESCRIPTION
+/*     trace_append() updates the message delivery record that is
+/*     mailed back to the originator. In case of a trace-only
+/*     message, the recipient status is also written to the
+/*     mailer logfile.
+/*
+/*     vtrace_append() implements an alternative interface.
+/*
+/*     trace_flush() returns the specified message to the specified
+/*     sender, including the message delivery record log that was built
+/*     with vtrace_append().
+/*
+/*     Arguments:
+/* .IP flags
+/*     The bitwise OR of zero or more of the following (specify
+/*     BOUNCE_FLAG_NONE to request no special processing):
+/* .RS
+/* .IP BOUNCE_FLAG_CLEAN
+/*     Delete the logfile in case of an error (as in: pretend
+/*     that we never even tried to deliver this message).
+/* .RE
+/* .IP queue_id
+/*     The message queue id.
+/* .IP orig_rcpt
+/*     The original envelope recipient address. If unavailable,
+/*     specify a null string or a null pointer.
+/* .IP recipient
+/*     The recipient address.
+/* .IP relay
+/*     The host we sent the mail to.
+/* .IP entry
+/*     Message arrival time.
+/* .IP dsn_code
+/*     three-digit dot-separated code.
+/* .IP dsn_action
+/*     "deliverable", "undeliverable", and so on.
+/* .IP format
+/*     Optional additional information.
+/* DIAGNOSTICS
+/*     A non-zero result means the operation failed.
+/*
+/*     Fatal: out of memory.
+/* BUGS
+/*     Should be replaced by routines with an attribute-value based
+/*     interface instead of an interface that uses a rigid argument list.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdio.h>
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <verify_clnt.h>
+#include <log_adhoc.h>
+#include <bounce.h>
+#include <trace.h>
+
+/* trace_append - append to message delivery record */
+
+int     trace_append(int flags, const char *queue_id,
+                            const char *orig_rcpt, const char *recipient,
+                            const char *relay, time_t entry,
+                            const char *dsn_code, const char *dsn_action,
+                            const char *fmt,...)
+{
+    va_list ap;
+    int     req_stat;
+
+    va_start(ap, fmt);
+    req_stat = vtrace_append(flags, queue_id, orig_rcpt, recipient,
+                            relay, entry, dsn_code, dsn_action, fmt, ap);
+    va_end(ap);
+    return (req_stat);
+}
+
+/* vtrace_append - append to message delivery record */
+
+int     vtrace_append(int flags, const char *queue_id,
+                             const char *orig_rcpt, const char *recipient,
+                             const char *relay, time_t entry,
+                             const char *dsn_code, const char *dsn_action,
+                             const char *fmt, va_list ap)
+{
+    VSTRING *why = vstring_alloc(100);
+    int     req_stat;
+
+    /*
+     * User-requested address verification or verbose delivery. Mail the
+     * report to the requesting user.
+     */
+    vstring_sprintf(why, "delivery via %s: ", relay);
+    vstring_vsprintf_append(why, fmt, ap);
+
+    if (orig_rcpt == 0)
+       orig_rcpt = "";
+    if (mail_command_client(MAIL_CLASS_PRIVATE, var_trace_service,
+                           ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
+                           ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+                           ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
+                           ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
+                           ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+                           ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_code,
+                           ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
+                           ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
+                           ATTR_TYPE_END) != 0) {
+       msg_warn("%s: %s service failure", queue_id, var_trace_service);
+       req_stat = -1;
+    } else {
+       if (flags & DEL_REQ_FLAG_EXPAND)
+           vlog_adhoc(queue_id, orig_rcpt, recipient, relay,
+                      entry, dsn_action, fmt, ap);
+       req_stat = 0;
+    }
+    vstring_free(why);
+    return (req_stat);
+}
+
+/* trace_flush - deliver delivery record to the sender */
+
+int     trace_flush(int flags, const char *queue, const char *id,
+                           const char *encoding, const char *sender)
+{
+    if (mail_command_client(MAIL_CLASS_PRIVATE, var_trace_service,
+                           ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_TRACE,
+                           ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+                           ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
+                           ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+                           ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
+                           ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+                           ATTR_TYPE_END) == 0) {
+       return (0);
+    } else {
+       return (-1);
+    }
+}
diff --git a/postfix/src/global/trace.h b/postfix/src/global/trace.h
new file mode 100644 (file)
index 0000000..b024c32
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _TRACE_H_INCLUDED_
+#define _TRACE_H_INCLUDED_
+
+/*++
+/* NAME
+/*     trace 3h
+/* SUMMARY
+/*     update user message delivery record
+/* SYNOPSIS
+/*     #include <trace.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * System library.
+  */
+#include <time.h>
+#include <stdarg.h>
+
+ /*
+  * Global library.
+  */
+#include <deliver_request.h>
+
+ /*
+  * External interface.
+  */
+extern int PRINTFLIKE(9, 10) trace_append(int, const char *,
+                                                 const char *, const char *,
+                                                 const char *, time_t,
+                                                 const char *, const char *,
+                                                 const char *,...);
+extern int vtrace_append(int, const char *,
+                                const char *, const char *,
+                                const char *, time_t,
+                                const char *, const char *,
+                                const char *, va_list);
+extern int trace_flush(int, const char *, const char *, const char *, const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/global/verify.c b/postfix/src/global/verify.c
new file mode 100644 (file)
index 0000000..6effb49
--- /dev/null
@@ -0,0 +1,159 @@
+/*++
+/* NAME
+/*     verify 3
+/* SUMMARY
+/*     update verify database
+/* SYNOPSIS
+/*     #include <verify.h>
+/*
+/*     int     verify_append(queue_id, orig_rcpt, recipient,
+/*                             relay, entry, status,
+/*                             recipient_status, format, ...)
+/*     const char *queue_id;
+/*     const char *orig_rcpt;
+/*     const char *recipient;
+/*     const char *relay;
+/*     time_t  entry;
+/*     const char *status;
+/*     int     recipient_status;
+/*     const char *format;
+/*
+/*     int     vverify_append(queue_id, orig_rcpt, recipient,
+/*                             relay, entry, status,
+/*                             recipient_status, format, ap)
+/*     int     recipient_status;
+/*     const char *queue_id;
+/*     const char *orig_rcpt;
+/*     const char *recipient;
+/*     const char *relay;
+/*     time_t  entry;
+/*     const char *status;
+/*     int     recipient_status;
+/*     const char *format;
+/*     va_list ap;
+/* DESCRIPTION
+/*     This module implements an impedance adaptor between the
+/*     verify_clnt interface and the interface expected by the
+/*     bounce/defer/sent modules.
+/*
+/*     verify_append() updates the address verification database
+/*     and logs the action to the mailer logfile.
+/*
+/*     vverify_append() implements an alternative interface.
+/*
+/*     Arguments:
+/* .IP queue_id
+/*     The message queue id.
+/* .IP orig_rcpt
+/*     The original envelope recipient address. If unavailable,
+/*     specify a null string or a null pointer.
+/* .IP recipient
+/*     The recipient address.
+/* .IP relay
+/*     Name of the host we're talking to.
+/* .IP entry
+/*     Message arrival time.
+/* .IP status
+/*     "deliverable", "undeliverable", and so on.
+/* .IP recipient_status
+/*     One of the following recipient verification status codes:
+/* .RS
+/* .IP DEL_REQ_RCPT_STAT_OK
+/*     Successful delivery.
+/* .IP DEL_REQ_RCPT_STAT_DEFER
+/*     Temporary delivery error.
+/* .IP DEL_REQ_RCPT_STAT_BOUNCE
+/*     Hard delivery error.
+/* .RE
+/* .IP format
+/*     Optional additional information.
+/* DIAGNOSTICS
+/*     A non-zero result means the operation failed.
+/*
+/*     Fatal: out of memory.
+/* BUGS
+/*     Should be replaced by routines with an attribute-value based
+/*     interface instead of an interface that uses a rigid argument list.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdio.h>
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <verify_clnt.h>
+#include <log_adhoc.h>
+#include <verify.h>
+
+/* verify_append - update address verification database */
+
+int     verify_append(const char *queue_id, const char *orig_rcpt,
+                            const char *recipient, const char *relay,
+                            time_t entry, const char *status,
+                            int rcpt_stat, const char *fmt,...)
+{
+    va_list ap;
+    int     req_stat;
+
+    va_start(ap, fmt);
+    req_stat = vverify_append(queue_id, orig_rcpt, recipient, relay,
+                            entry, status, rcpt_stat, fmt, ap);
+    va_end(ap);
+    return (req_stat);
+}
+
+/* vverify_append - update address verification database */
+
+int     vverify_append(const char *queue_id, const char *orig_rcpt,
+                             const char *recipient, const char *relay,
+                             time_t entry, const char *status,
+                             int rcpt_stat, const char *fmt, va_list ap)
+{
+    int     req_stat;
+
+    /*
+     * Impedance adaptor between bounce/defer/sent and verify_clnt.
+     */
+    if (var_verify_neg_cache || rcpt_stat == DEL_RCPT_STAT_OK) {
+       req_stat = verify_clnt_vupdate(orig_rcpt, rcpt_stat, fmt, ap);
+       if (req_stat == VRFY_STAT_OK && strcasecmp(recipient, orig_rcpt) != 0)
+           req_stat = verify_clnt_vupdate(recipient, rcpt_stat, fmt, ap);
+    } else {
+       status = "undeliverable-but-not-cached";
+       req_stat = VRFY_STAT_OK;
+    }
+    if (req_stat == VRFY_STAT_OK) {
+       vlog_adhoc(queue_id, orig_rcpt, recipient, relay,
+                  entry, status, fmt, ap);
+       req_stat = 0;
+    } else {
+       msg_warn("%s: %s service failure", queue_id, var_verify_service);
+       req_stat = -1;
+    }
+    return (req_stat);
+}
diff --git a/postfix/src/global/verify.h b/postfix/src/global/verify.h
new file mode 100644 (file)
index 0000000..1ecd4da
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _VERIFY_H_INCLUDED_
+#define _VERIFY_H_INCLUDED_
+
+/*++
+/* NAME
+/*     verify 3h
+/* SUMMARY
+/*     update user message delivery record
+/* SYNOPSIS
+/*     #include <verify.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * System library.
+  */
+#include <time.h>
+#include <stdarg.h>
+
+ /*
+  * Global library.
+  */
+#include <deliver_request.h>
+
+ /*
+  * External interface.
+  */
+extern int PRINTFLIKE(8, 9) verify_append(const char *, const char *,
+                                                 const char *, const char *,
+                                                 time_t, const char *,
+                                                 int, const char *,...);
+extern int vverify_append(const char *, const char *,
+                                const char *, const char *,
+                                time_t, const char *,
+                                int, const char *, va_list);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/global/verify_clnt.c b/postfix/src/global/verify_clnt.c
new file mode 100644 (file)
index 0000000..31532a3
--- /dev/null
@@ -0,0 +1,327 @@
+/*++
+/* NAME
+/*     verify_clnt 3
+/* SUMMARY
+/*     address verification client interface
+/* SYNOPSIS
+/*     #include <verify_clnt.h>
+/*
+/*     int     verify_clnt_query(addr, status, why)
+/*     const char *addr;
+/*     int     *status;
+/*     VSTRING *why;
+/*
+/*     int     verify_clnt_update(addr, status, format, ...)
+/*     const char *addr;
+/*     int     status;
+/*     const char *format;
+/*
+/*     int     verify_clnt_vupdate(addr, status, format, ap)
+/*     const char *addr;
+/*     int     status;
+/*     const char *format;
+/*     va_list ap;
+/* DESCRIPTION
+/*     verify_clnt_query() requests information about the given address.
+/*     The result value is one of the valud status values (see
+/*     status description below).
+/*     In all cases the \fBwhy\fR argument provides additional
+/*     information.
+/*
+/*     verify_clnt_update() requests that the status of the specified
+/*     address be updated. The result status is DEL_REQ_RCPT_STAT_OK upon
+/*     success, DEL_REQ_RCPT_STAT_DEFER upon failure.
+/*
+/*     verify_clnt_vupdate() presents the function of verify_clnt_update()
+/*     with a different user interface.
+/*
+/*     Arguments
+/* .IP addr
+/*     The email address in question.
+/* .IP status
+/*     One of the following status codes:
+/* .RS
+/* .IP DEL_REQ_RCPT_STAT_OK
+/*     The mail system did not detect any problems.
+/* .IP DEL_REQ_RCPT_STAT_DEFER
+/*     The status of the address is indeterminate.
+/* .IP DEL_REQ_RCPT_STAT_BOUNCE
+/*     The address is permanently undeliverable.
+/* .RE
+/* .IP why
+/*     textual description of the status.
+/* DIAGNOSTICS
+/*     These functions return VRFY_STAT_OK in case of success,
+/*     VRFY_STAT_BAD in case of a malformed request, and
+/*     VRFY_STAT_FAIL when the operation failed.
+/* SEE ALSO
+/*     verify(8) Postfix address verification server
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <attr.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <clnt_stream.h>
+#include <verify_clnt.h>
+
+CLNT_STREAM *vrfy_clnt;
+
+/* verify_clnt_init - initialize */
+
+static void verify_clnt_init(void)
+{
+    if (vrfy_clnt != 0)
+       msg_panic("verify_clnt_init: multiple initialization");
+    vrfy_clnt = clnt_stream_create(MAIL_CLASS_PRIVATE, var_verify_service,
+                                  var_ipc_idle_limit);
+}
+
+/* verify_clnt_query - request address verification status */
+
+int     verify_clnt_query(const char *addr, int *addr_status, VSTRING *why)
+{
+    VSTREAM *stream;
+    int     request_status;
+
+    /*
+     * Do client-server plumbing.
+     */
+    if (vrfy_clnt == 0)
+       verify_clnt_init();
+
+    /*
+     * Request status for this address.
+     */
+    for (;;) {
+       stream = clnt_stream_access(vrfy_clnt);
+       if (attr_print(stream, ATTR_FLAG_NONE,
+                      ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_QUERY,
+                      ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+                      ATTR_TYPE_END) != 0
+           || vstream_fflush(stream)) {
+           if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
+               msg_warn("service %s: bad write: %m", var_verify_service);
+               sleep(10);                      /* XXX make configurable */
+           }
+       } else if (attr_scan(stream, ATTR_FLAG_MISSING,
+                          ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
+                         ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+                            ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
+                            ATTR_TYPE_END) != 3) {
+           if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
+               msg_warn("service %s: bad read: %m", var_verify_service);
+               sleep(10);                      /* XXX make configurable */
+           }
+       } else {
+           break;
+       }
+       sleep(1);
+       clnt_stream_recover(vrfy_clnt);
+    }
+    return (request_status);
+}
+
+/* verify_clnt_update - request address status update */
+
+int     verify_clnt_update(const char *addr, int addr_status,
+                                  const char *format,...)
+{
+    va_list ap;
+    int     status;
+
+    va_start(ap, format);
+    status = verify_clnt_vupdate(addr, addr_status, format, ap);
+    va_end(ap);
+    return (status);
+}
+
+/* verify_clnt_update - request address status update */
+
+int     verify_clnt_vupdate(const char *addr, int addr_status,
+                                   const char *format, va_list ap)
+{
+    VSTRING *text;
+    VSTREAM *stream;
+    int     request_status;
+
+    /*
+     * Do client-server plumbing.
+     */
+    if (vrfy_clnt == 0)
+       verify_clnt_init();
+
+    /*
+     * Send status for this address. Supply a default status if the address
+     * verification service is unavailable.
+     */
+    text = vstring_alloc(100);
+    vstring_vsprintf(text, format, ap);
+    for (;;) {
+       stream = clnt_stream_access(vrfy_clnt);
+       if (attr_print(stream, ATTR_FLAG_NONE,
+                      ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_UPDATE,
+                      ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+                      ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+                      ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(text),
+                      ATTR_TYPE_END) != 0
+           || vstream_fflush(stream)) {
+           if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
+               msg_warn("service %s: bad write: %m", var_verify_service);
+               msg_warn("service %s: bad write: %m", var_verify_service);
+               sleep(10);                      /* XXX make configurable */
+           }
+       } else if (attr_scan(stream, ATTR_FLAG_MISSING,
+                          ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
+                            ATTR_TYPE_END) != 1) {
+           if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
+               msg_warn("service %s: bad read: %m", var_verify_service);
+               sleep(10);                      /* XXX make configurable */
+           }
+       } else {
+           break;
+       }
+       sleep(1);
+       clnt_stream_recover(vrfy_clnt);
+    }
+    vstring_free(text);
+    return (request_status);
+}
+
+ /*
+  * Proof-of-concept test client program.
+  */
+#ifdef TEST
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <msg_vstream.h>
+#include <stringops.h>
+#include <vstring_vstream.h>
+#include <mail_conf.h>
+
+#define STR(x) vstring_str(x)
+
+static NORETURN usage(char *myname)
+{
+    msg_fatal("usage: %s [-v]", myname);
+}
+
+static void query(char *query, VSTRING *buf)
+{
+    int     status;
+
+    switch (verify_clnt_query(query, &status, buf)) {
+    case VRFY_STAT_OK:
+       vstream_printf("%-10s %d\n", "status", status);
+       vstream_printf("%-10s %s\n", "text", STR(buf));
+       vstream_fflush(VSTREAM_OUT);
+       break;
+    case VRFY_STAT_BAD:
+       msg_warn("bad request format");
+       break;
+    case VRFY_STAT_FAIL:
+       msg_warn("request failed");
+       break;
+    }
+}
+
+static void update(char *query)
+{
+    char   *addr;
+    char   *status_text;
+    char   *cp = query;
+
+    if ((addr = mystrtok(&cp, " \t\r\n")) == 0
+       || (status_text = mystrtok(&cp, " \t\r\n")) == 0) {
+       msg_warn("bad request format");
+       return;
+    }
+    while (*cp && ISSPACE(*cp))
+       cp++;
+    if (*cp == 0) {
+       msg_warn("bad request format");
+       return;
+    }
+    switch (verify_clnt_update(query, atoi(status_text), cp)) {
+    case VRFY_STAT_OK:
+       vstream_printf("OK\n");
+       vstream_fflush(VSTREAM_OUT);
+       break;
+    case VRFY_STAT_BAD:
+       msg_warn("bad request format");
+       break;
+    case VRFY_STAT_FAIL:
+       msg_warn("request failed");
+       break;
+    }
+}
+
+int     main(int argc, char **argv)
+{
+    VSTRING *buffer = vstring_alloc(1);
+    char   *cp;
+    int     ch;
+    char   *command;
+
+    signal(SIGPIPE, SIG_IGN);
+
+    msg_vstream_init(argv[0], VSTREAM_ERR);
+
+    mail_conf_read();
+    msg_info("using config files in %s", var_config_dir);
+    if (chdir(var_queue_dir) < 0)
+       msg_fatal("chdir %s: %m", var_queue_dir);
+
+    while ((ch = GETOPT(argc, argv, "v")) > 0) {
+       switch (ch) {
+       case 'v':
+           msg_verbose++;
+           break;
+       default:
+           usage(argv[0]);
+       }
+    }
+    if (argc - optind > 1)
+       usage(argv[0]);
+
+    while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
+       cp = STR(buffer);
+       if ((command = mystrtok(&cp, " \t\r\n")) == 0)
+           continue;
+       if (strcmp(command, "query") == 0)
+           query(cp, buffer);
+       else if (strcmp(command, "update") == 0)
+           update(cp);
+       else
+           msg_warn("unrecognized command: %s", command);
+    }
+    vstring_free(buffer);
+}
+
+#endif
diff --git a/postfix/src/global/verify_clnt.h b/postfix/src/global/verify_clnt.h
new file mode 100644 (file)
index 0000000..ebcac03
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _VRFY_STAT_H_INCLUDED_
+#define _VRFY_STAT_H_INCLUDED_
+
+/*++
+/* NAME
+/*     mail_proto 3h
+/* SUMMARY
+/*     mail internal IPC support
+/* SYNOPSIS
+/*     #include <mail_proto.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * System library.
+  */
+#include <stdarg.h>
+
+ /*
+  * Global library.
+  */
+#include <deliver_request.h>
+
+ /*
+  * Address verification requests.
+  */
+#define VRFY_REQ_QUERY         "query"
+#define VRFY_REQ_UPDATE                "update"
+
+ /*
+  * Request (NOT: address) status codes.
+  */
+#define VRFY_STAT_OK           0
+#define VRFY_STAT_FAIL         (-1)
+#define VRFY_STAT_BAD          (-2)
+
+ /*
+  * Functional interface.
+  */
+extern int verify_clnt_query(const char *, int *, VSTRING *);
+extern int PRINTFLIKE(3, 4) verify_clnt_update(const char *, int, const char *,...);
+extern int verify_clnt_vupdate(const char *, int, const char *, va_list);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index 40f5947165a5cd60a587e41fbfd8a1879296949e..dfbeb49439d6c1c507996c0f1a3fd326c073ac91 100644 (file)
@@ -263,12 +263,14 @@ void    lmtp_chat_notify(LMTP_STATE *state)
      * generate from untrusted data.
      */
 #define NULL_CLEANUP_FLAGS     0
+#define NULL_TRACE_FLAGS       0
 #define LENGTH 78
 #define INDENT 4
 
     notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                    var_error_rcpt,
-                                   NULL_CLEANUP_FLAGS);
+                                   NULL_CLEANUP_FLAGS,
+                                   NULL_TRACE_FLAGS);
     if (notice == 0) {
        msg_warn("postmaster notify: %m");
        return;
index ee990474ba55775b0e5df0dbb46ec86c0ec79185..b4afc37d0350266ce86d49fc4f2a2bd2f5d3556b 100644 (file)
@@ -178,7 +178,8 @@ char   *xfer_request[LMTP_STATE_LAST] = {
     "RCPT TO command",
     "DATA command",
     "end of DATA command",
-    "final RSET command",
+    "RSET command",
+    "RSET command",
     "QUIT command",
 };
 
@@ -394,7 +395,8 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
            vstring_sprintf(next_command, "RCPT TO:<%s>",
                            vstring_str(state->scratch));
            if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
-               next_state = LMTP_STATE_DATA;
+               next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
+                   LMTP_STATE_ABORT : LMTP_STATE_DATA;
            break;
 
            /*
@@ -423,10 +425,8 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
            msg_panic("%s: sender abort state", myname);
 
            /*
-            * Build the RSET command.  This command does not really belong
-            * here because it is always sent without pipelining, but having
-            * it here means that we can reuse a lot of error handling code
-            * that already exists.
+            * Build the RSET command.  This is used between pipelined
+            * deliveries, and to abort a trace-only delivery request.
             */
        case LMTP_STATE_RSET:
            vstring_strcpy(next_command, "RSET");
@@ -530,6 +530,17 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                                    mymalloc(request->rcpt_list.len
                                             * sizeof(int));
                            survivors[nrcpt++] = recv_rcpt;
+                           /* If trace-only, mark the recipient done. */
+                           if (DEL_REQ_TRACE_ONLY(request->flags)
+                               && sent(DEL_REQ_TRACE_FLAGS(request->flags),
+                                       request->queue_id, rcpt->orig_addr,
+                                       rcpt->address, session->namaddr,
+                                       request->arrival_time, "%s", 
+                                       translit(resp->str, "\n", " ")) == 0) {
+                               if (request->flags & DEL_REQ_FLAG_SUCCESS)
+                                   deliver_completed(state->src, rcpt->offset);
+                               rcpt->offset = 0;       /* in case deferred */
+                           }
                        } else {
                            lmtp_rcpt_fail(state, resp->code, rcpt,
                                        "host %s said: %s (in reply to %s)",
@@ -539,8 +550,10 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                            rcpt->offset = 0;   /* in case deferred */
                        }
                    }
+                   /* If trace-only, send RSET instead of DATA. */
                    if (++recv_rcpt == request->rcpt_list.len)
-                       recv_state = LMTP_STATE_DATA;
+                       recv_state = DEL_REQ_TRACE_ONLY(request->flags) ?
+                           LMTP_STATE_ABORT : LMTP_STATE_DATA;
                    break;
 
                    /*
@@ -575,12 +588,15 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                        rcpt = request->rcpt_list.info + survivors[recv_dot];
                        if (resp->code / 100 == 2) {
                            if (rcpt->offset) {
-                               sent(request->queue_id, rcpt->orig_addr,
-                                    rcpt->address, session->namaddr,
-                                    request->arrival_time, "%s", resp->str);
-                               if (request->flags & DEL_REQ_FLAG_SUCCESS)
-                                   deliver_completed(state->src, rcpt->offset);
-                               rcpt->offset = 0;
+                               if (sent(DEL_REQ_TRACE_FLAGS(request->flags),
+                                        request->queue_id, rcpt->orig_addr,
+                                        rcpt->address, session->namaddr,
+                                        request->arrival_time,
+                                        "%s", resp->str) == 0) {
+                                   if (request->flags & DEL_REQ_FLAG_SUCCESS)
+                                       deliver_completed(state->src, rcpt->offset);
+                                   rcpt->offset = 0;
+                               }
                            }
                        } else {
                            lmtp_rcpt_fail(state, resp->code, rcpt,
index 9a15d4d8e50ff5c8d9ef46e7dd2054aaf7027c62..4c2916e3d733e51ac9ce0826a24fad2e18fea59f 100644 (file)
 
 #define LMTP_SOFT(code) (((code) / 100) == 4)
 #define LMTP_HARD(code) (((code) / 100) == 5)
-#define KEEP           BOUNCE_FLAG_KEEP
 
 /* lmtp_check_code - check response code */
 
@@ -178,7 +177,8 @@ int     lmtp_site_fail(LMTP_STATE *state, int code, char *format,...)
        if (rcpt->offset == 0)
            continue;
        status = (soft_error ? defer_append : bounce_append)
-           (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+           (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+            rcpt->orig_addr, rcpt->address,
             session ? session->namaddr : "none",
             request->arrival_time, "%s", vstring_str(why));
        if (status == 0) {
@@ -225,7 +225,8 @@ int     lmtp_mesg_fail(LMTP_STATE *state, int code, char *format,...)
        if (rcpt->offset == 0)
            continue;
        status = (LMTP_SOFT(code) ? defer_append : bounce_append)
-           (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+           (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+            rcpt->orig_addr, rcpt->address,
             session->namaddr, request->arrival_time,
             "%s", vstring_str(why));
        if (status == 0) {
@@ -259,7 +260,8 @@ void    lmtp_rcpt_fail(LMTP_STATE *state, int code, RECIPIENT *rcpt,
      */
     va_start(ap, format);
     status = (LMTP_SOFT(code) ? vdefer_append : vbounce_append)
-       (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+       (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+        rcpt->orig_addr, rcpt->address,
         session->namaddr, request->arrival_time, format, ap);
     va_end(ap);
     if (status == 0) {
@@ -304,7 +306,8 @@ int     lmtp_stream_except(LMTP_STATE *state, int code, char *description)
        rcpt = request->rcpt_list.info + nrcpt;
        if (rcpt->offset == 0)
            continue;
-       state->status |= defer_append(KEEP, request->queue_id,
+       state->status |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
+                                     request->queue_id,
                                      rcpt->orig_addr, rcpt->address,
                                      session->namaddr,
                                      request->arrival_time,
index 15539ceed12a8c1e4605f46b90522571710751d8..96dcf6b9e1f39a0549d3e48460ef3a4b6329ec93 100644 (file)
@@ -76,15 +76,16 @@ alias.o: ../../include/mymalloc.h
 alias.o: ../../include/mail_params.h
 alias.o: ../../include/defer.h
 alias.o: ../../include/bounce.h
+alias.o: ../../include/deliver_request.h
+alias.o: ../../include/recipient_list.h
 alias.o: ../../include/maps.h
 alias.o: ../../include/mypwd.h
 alias.o: ../../include/canon_addr.h
+alias.o: ../../include/sent.h
 alias.o: local.h
 alias.o: ../../include/been_here.h
 alias.o: ../../include/tok822.h
 alias.o: ../../include/resolve_clnt.h
-alias.o: ../../include/deliver_request.h
-alias.o: ../../include/recipient_list.h
 alias.o: ../../include/mbox_conf.h
 biff_notify.o: biff_notify.c
 biff_notify.o: ../../include/sys_defs.h
@@ -100,6 +101,8 @@ command.o: ../../include/vstream.h
 command.o: ../../include/argv.h
 command.o: ../../include/defer.h
 command.o: ../../include/bounce.h
+command.o: ../../include/deliver_request.h
+command.o: ../../include/recipient_list.h
 command.o: ../../include/sent.h
 command.o: ../../include/been_here.h
 command.o: ../../include/mail_params.h
@@ -108,8 +111,6 @@ command.o: ../../include/mail_copy.h
 command.o: local.h
 command.o: ../../include/tok822.h
 command.o: ../../include/resolve_clnt.h
-command.o: ../../include/deliver_request.h
-command.o: ../../include/recipient_list.h
 command.o: ../../include/mbox_conf.h
 command.o: ../../include/maps.h
 command.o: ../../include/dict.h
@@ -171,15 +172,16 @@ dotforward.o: ../../include/mac_expand.h
 dotforward.o: ../../include/mac_parse.h
 dotforward.o: ../../include/mypwd.h
 dotforward.o: ../../include/bounce.h
+dotforward.o: ../../include/deliver_request.h
+dotforward.o: ../../include/recipient_list.h
 dotforward.o: ../../include/been_here.h
 dotforward.o: ../../include/mail_params.h
 dotforward.o: ../../include/mail_conf.h
 dotforward.o: ../../include/ext_prop.h
+dotforward.o: ../../include/sent.h
 dotforward.o: local.h
 dotforward.o: ../../include/tok822.h
 dotforward.o: ../../include/resolve_clnt.h
-dotforward.o: ../../include/deliver_request.h
-dotforward.o: ../../include/recipient_list.h
 dotforward.o: ../../include/mbox_conf.h
 dotforward.o: ../../include/argv.h
 dotforward.o: ../../include/maps.h
@@ -196,6 +198,8 @@ file.o: ../../include/myflock.h
 file.o: ../../include/set_eugid.h
 file.o: ../../include/mail_copy.h
 file.o: ../../include/bounce.h
+file.o: ../../include/deliver_request.h
+file.o: ../../include/recipient_list.h
 file.o: ../../include/defer.h
 file.o: ../../include/sent.h
 file.o: ../../include/been_here.h
@@ -207,8 +211,6 @@ file.o: ../../include/safe_open.h
 file.o: local.h
 file.o: ../../include/tok822.h
 file.o: ../../include/resolve_clnt.h
-file.o: ../../include/deliver_request.h
-file.o: ../../include/recipient_list.h
 file.o: ../../include/maps.h
 file.o: ../../include/dict.h
 forward.o: forward.c
@@ -227,6 +229,8 @@ forward.o: ../../include/mail_proto.h
 forward.o: ../../include/attr.h
 forward.o: ../../include/cleanup_user.h
 forward.o: ../../include/sent.h
+forward.o: ../../include/deliver_request.h
+forward.o: ../../include/recipient_list.h
 forward.o: ../../include/record.h
 forward.o: ../../include/rec_type.h
 forward.o: ../../include/mark_corrupt.h
@@ -236,8 +240,6 @@ forward.o: local.h
 forward.o: ../../include/been_here.h
 forward.o: ../../include/tok822.h
 forward.o: ../../include/resolve_clnt.h
-forward.o: ../../include/deliver_request.h
-forward.o: ../../include/recipient_list.h
 forward.o: ../../include/mbox_conf.h
 forward.o: ../../include/maps.h
 forward.o: ../../include/dict.h
@@ -253,16 +255,17 @@ include.o: ../../include/stat_as.h
 include.o: ../../include/iostuff.h
 include.o: ../../include/mypwd.h
 include.o: ../../include/bounce.h
+include.o: ../../include/deliver_request.h
+include.o: ../../include/vstring.h
+include.o: ../../include/recipient_list.h
 include.o: ../../include/defer.h
 include.o: ../../include/been_here.h
 include.o: ../../include/mail_params.h
 include.o: ../../include/ext_prop.h
+include.o: ../../include/sent.h
 include.o: local.h
-include.o: ../../include/vstring.h
 include.o: ../../include/tok822.h
 include.o: ../../include/resolve_clnt.h
-include.o: ../../include/deliver_request.h
-include.o: ../../include/recipient_list.h
 include.o: ../../include/mbox_conf.h
 include.o: ../../include/argv.h
 include.o: ../../include/maps.h
@@ -273,16 +276,17 @@ indirect.o: ../../include/msg.h
 indirect.o: ../../include/htable.h
 indirect.o: ../../include/mail_params.h
 indirect.o: ../../include/bounce.h
+indirect.o: ../../include/deliver_request.h
+indirect.o: ../../include/vstring.h
+indirect.o: ../../include/vbuf.h
+indirect.o: ../../include/vstream.h
+indirect.o: ../../include/recipient_list.h
 indirect.o: ../../include/defer.h
 indirect.o: ../../include/been_here.h
+indirect.o: ../../include/sent.h
 indirect.o: local.h
-indirect.o: ../../include/vstream.h
-indirect.o: ../../include/vbuf.h
-indirect.o: ../../include/vstring.h
 indirect.o: ../../include/tok822.h
 indirect.o: ../../include/resolve_clnt.h
-indirect.o: ../../include/deliver_request.h
-indirect.o: ../../include/recipient_list.h
 indirect.o: ../../include/mbox_conf.h
 indirect.o: ../../include/argv.h
 indirect.o: ../../include/maps.h
@@ -346,13 +350,13 @@ mailbox.o: ../../include/set_eugid.h
 mailbox.o: ../../include/mail_copy.h
 mailbox.o: ../../include/defer.h
 mailbox.o: ../../include/bounce.h
+mailbox.o: ../../include/deliver_request.h
+mailbox.o: ../../include/recipient_list.h
 mailbox.o: ../../include/sent.h
 mailbox.o: ../../include/mypwd.h
 mailbox.o: ../../include/been_here.h
 mailbox.o: ../../include/mail_params.h
 mailbox.o: ../../include/deliver_pass.h
-mailbox.o: ../../include/deliver_request.h
-mailbox.o: ../../include/recipient_list.h
 mailbox.o: ../../include/mail_proto.h
 mailbox.o: ../../include/iostuff.h
 mailbox.o: ../../include/attr.h
@@ -380,6 +384,8 @@ maildir.o: ../../include/get_hostname.h
 maildir.o: ../../include/sane_fsops.h
 maildir.o: ../../include/mail_copy.h
 maildir.o: ../../include/bounce.h
+maildir.o: ../../include/deliver_request.h
+maildir.o: ../../include/recipient_list.h
 maildir.o: ../../include/defer.h
 maildir.o: ../../include/sent.h
 maildir.o: ../../include/mail_params.h
@@ -388,8 +394,6 @@ maildir.o: ../../include/htable.h
 maildir.o: ../../include/been_here.h
 maildir.o: ../../include/tok822.h
 maildir.o: ../../include/resolve_clnt.h
-maildir.o: ../../include/deliver_request.h
-maildir.o: ../../include/recipient_list.h
 maildir.o: ../../include/mbox_conf.h
 maildir.o: ../../include/argv.h
 maildir.o: ../../include/maps.h
@@ -408,6 +412,8 @@ recipient.o: ../../include/vstream.h
 recipient.o: ../../include/argv.h
 recipient.o: ../../include/stat_as.h
 recipient.o: ../../include/bounce.h
+recipient.o: ../../include/deliver_request.h
+recipient.o: ../../include/recipient_list.h
 recipient.o: ../../include/defer.h
 recipient.o: ../../include/mail_params.h
 recipient.o: ../../include/split_addr.h
@@ -419,8 +425,6 @@ recipient.o: local.h
 recipient.o: ../../include/been_here.h
 recipient.o: ../../include/tok822.h
 recipient.o: ../../include/resolve_clnt.h
-recipient.o: ../../include/deliver_request.h
-recipient.o: ../../include/recipient_list.h
 recipient.o: ../../include/mbox_conf.h
 recipient.o: ../../include/maps.h
 resolve.o: resolve.c
@@ -439,10 +443,10 @@ resolve.o: ../../include/tok822.h
 resolve.o: ../../include/mail_params.h
 resolve.o: ../../include/defer.h
 resolve.o: ../../include/bounce.h
-resolve.o: local.h
-resolve.o: ../../include/been_here.h
 resolve.o: ../../include/deliver_request.h
 resolve.o: ../../include/recipient_list.h
+resolve.o: local.h
+resolve.o: ../../include/been_here.h
 resolve.o: ../../include/mbox_conf.h
 resolve.o: ../../include/argv.h
 resolve.o: ../../include/maps.h
@@ -462,10 +466,10 @@ token.o: ../../include/tok822.h
 token.o: ../../include/resolve_clnt.h
 token.o: ../../include/mail_params.h
 token.o: ../../include/bounce.h
-token.o: local.h
-token.o: ../../include/been_here.h
 token.o: ../../include/deliver_request.h
 token.o: ../../include/recipient_list.h
+token.o: local.h
+token.o: ../../include/been_here.h
 token.o: ../../include/mbox_conf.h
 token.o: ../../include/argv.h
 token.o: ../../include/maps.h
@@ -484,14 +488,14 @@ unknown.o: ../../include/vstream.h
 unknown.o: ../../include/iostuff.h
 unknown.o: ../../include/attr.h
 unknown.o: ../../include/bounce.h
+unknown.o: ../../include/deliver_request.h
+unknown.o: ../../include/recipient_list.h
 unknown.o: ../../include/mail_addr.h
 unknown.o: ../../include/sent.h
 unknown.o: local.h
 unknown.o: ../../include/htable.h
 unknown.o: ../../include/tok822.h
 unknown.o: ../../include/resolve_clnt.h
-unknown.o: ../../include/deliver_request.h
-unknown.o: ../../include/recipient_list.h
 unknown.o: ../../include/mbox_conf.h
 unknown.o: ../../include/argv.h
 unknown.o: ../../include/maps.h
index 362b26df8e566f5015247ac13349c679488dc102..14b51eac9be93124a014432144e753f1a573b0e4 100644 (file)
@@ -87,6 +87,7 @@
 #include <bounce.h>
 #include <mypwd.h>
 #include <canon_addr.h>
+#include <sent.h>
 
 /* Application-specific. */
 
@@ -162,7 +163,8 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
        return (NO);
     if (state.level > 100) {
        msg_warn("possible alias database loop for %s", name);
-       *statusp = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       *statusp = bounce_append(BOUNCE_FLAGS(state.request),
+                                BOUNCE_ATTR(state.msg_attr),
                               "possible alias database loop for %s", name);
        return (YES);
     }
@@ -191,6 +193,16 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
            if (msg_verbose)
                msg_info("%s: %s: %s = %s", myname, *cpp, name, alias_result);
 
+           /*
+            * Don't expand a verify-only request.
+            */
+           if (state.request->flags & DEL_REQ_FLAG_VERIFY) {
+               *statusp = sent(BOUNCE_FLAGS(state.request),
+                               SENT_ATTR(state.msg_attr),
+                               "aliased to %s", alias_result);
+               return (YES);
+           }
+
            /*
             * DELIVERY POLICY
             * 
@@ -213,7 +225,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
            } else {
                if ((alias_pwd = mypwuid(alias_uid)) == 0) {
                    msg_warn("cannot find alias database owner for %s", *cpp);
-                   *statusp = defer_append(BOUNCE_FLAG_KEEP,
+                   *statusp = defer_append(BOUNCE_FLAGS(state.request),
                                            BOUNCE_ATTR(state.msg_attr),
                                        "cannot find alias database owner");
                    return (YES);
@@ -237,7 +249,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
 
            expansion = mystrdup(alias_result);
            if (OWNER_ASSIGN(owner) != 0
-           && (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_NONE)) != 0) {
+               && (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_NONE)) != 0) {
                canon_owner = canon_addr_internal(vstring_alloc(10),
                                     var_exp_own_alias ? owner_rhs : owner);
                SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
@@ -260,12 +272,13 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
            alias_count = 0;
            *statusp =
                (dict_errno ?
-                defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+                defer_append(BOUNCE_FLAGS(state.request),
+                             BOUNCE_ATTR(state.msg_attr),
                              "alias database unavailable") :
            deliver_token_string(state, usr_attr, expansion, &alias_count));
 #if 0
            if (var_ownreq_special
-               && strncmp("owner-", state.msg_attr.sender, 6) != 0 
+               && strncmp("owner-", state.msg_attr.sender, 6) != 0
                && alias_count > 10)
                msg_warn("mailing list \"%s\" needs an \"owner-%s\" alias",
                         name, name);
@@ -285,7 +298,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
         * further delivery for the current top-level recipient.
         */
        if (dict_errno != 0) {
-           *statusp = defer_append(BOUNCE_FLAG_KEEP,
+           *statusp = defer_append(BOUNCE_FLAGS(state.request),
                                    BOUNCE_ATTR(state.msg_attr),
                                    "alias database unavailable");
            return (YES);
index 9cbd1f706ce271b72a6edf20c517942243aa1f45..50f8f9d85bb8f9af5cb63ec0e6163e117c95731f 100644 (file)
@@ -106,6 +106,13 @@ int     deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *comma
     if (been_here(state.dup_filter, "command %ld %s", (long) usr_attr.uid, command))
        return (0);
 
+    /*
+     * Don't deliver a trace-only request.
+     */
+    if (DEL_REQ_TRACE_ONLY(state.request->flags))
+       return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+                    "delivers to command: %s", command));
+
     /*
      * DELIVERY RIGHTS
      * 
@@ -185,15 +192,17 @@ int     deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *comma
      */
     switch (cmd_status) {
     case PIPE_STAT_OK:
-       deliver_status = sent(SENT_ATTR(state.msg_attr), "\"|%s\"", command);
+       deliver_status = sent(BOUNCE_FLAGS(state.request),
+                             SENT_ATTR(state.msg_attr),
+                             "delivered to command: %s", command);
        break;
     case PIPE_STAT_BOUNCE:
-       deliver_status = bounce_append(BOUNCE_FLAG_KEEP,
+       deliver_status = bounce_append(BOUNCE_FLAGS(state.request),
                                       BOUNCE_ATTR(state.msg_attr),
                                       "%s", vstring_str(why));
        break;
     case PIPE_STAT_DEFER:
-       deliver_status = defer_append(BOUNCE_FLAG_KEEP,
+       deliver_status = defer_append(BOUNCE_FLAGS(state.request),
                                      BOUNCE_ATTR(state.msg_attr),
                                      "%s", vstring_str(why));
        break;
index 6d0890fb2fcff9ce8510d68d60ef0174afa82005..307082169ffa5aac776a64e11f60e043902eeb46 100644 (file)
@@ -78,6 +78,7 @@
 #include <mail_params.h>
 #include <mail_conf.h>
 #include <ext_prop.h>
+#include <sent.h>
 
 /* Application-specific. */
 
@@ -214,7 +215,16 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      * deliver to the user instead.
      */
     if (lookup_status >= 0) {
-       if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
+
+       /*
+        * Don't expand a verify-only request.
+        */
+       if (state.request->flags & DEL_REQ_FLAG_VERIFY) {
+           *statusp = sent(BOUNCE_FLAGS(state.request), 
+                               SENT_ATTR(state.msg_attr),
+                           "forward via file: %s", STR(path));
+           forward_found = YES;
+       } else if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
            state.msg_attr.exp_from = state.msg_attr.local;
            if (S_ISREG(st.st_mode) == 0) {
                msg_warn("file %s is not a regular file", STR(path));
index 96663d3c41e61b2949a507daaddd26af62dcc96c..7e5b73f663f6738e5255b832b347234016dab35e 100644 (file)
@@ -111,9 +111,17 @@ int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
      * Do we allow delivery to files?
      */
     if ((local_file_deliver_mask & state.msg_attr.exp_type) == 0)
-       return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       return (bounce_append(BOUNCE_FLAGS(state.request),
+                             BOUNCE_ATTR(state.msg_attr),
                              "mail to file is restricted"));
 
+    /*
+     * Don't deliver trace-only requests.
+     */
+    if (DEL_REQ_TRACE_ONLY(state.request->flags))
+       return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+                    "delivers to file: %s", path));
+
     /*
      * DELIVERY RIGHTS
      * 
@@ -175,11 +183,13 @@ int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     } else if (mail_copy_status != 0) {
        deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
                          defer_append : bounce_append)
-           (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+           (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
             "cannot append message to destination file %s: %s",
             path, STR(why));
     } else {
-       deliver_status = sent(SENT_ATTR(state.msg_attr), "%s", path);
+       deliver_status = sent(BOUNCE_FLAGS(state.request),
+                             SENT_ATTR(state.msg_attr),
+                             "delivered to file: %s", path);
     }
 
     /*
index 77ebc9282c7d87aa4d8020bc200210b7dac91f40..9a9b148caa1b4f9dc72aa705f404b277a5eeb2ba 100644 (file)
@@ -11,7 +11,8 @@
 /*     int     forward_append(attr)
 /*     DELIVER_ATTR attr;
 /*
-/*     int     forward_finish(attr, cancel)
+/*     int     forward_finish(request, attr, cancel)
+/*     DELIVER_REQUEST *request;
 /*     DELIVER_ATTR attr;
 /*     int     cancel;
 /* DESCRIPTION
@@ -195,7 +196,8 @@ int     forward_append(DELIVER_ATTR attr)
 
 /* forward_send - send forwarded message */
 
-static int forward_send(FORWARD_INFO *info, DELIVER_ATTR attr, char *delivered)
+static int forward_send(FORWARD_INFO *info, DELIVER_REQUEST *request,
+                               DELIVER_ATTR attr, char *delivered)
 {
     char   *myname = "forward_send";
     VSTRING *buffer = vstring_alloc(100);
@@ -251,7 +253,8 @@ static int forward_send(FORWARD_INFO *info, DELIVER_ATTR attr, char *delivered)
      * Log successful forwarding.
      */
     if (status == 0)
-       sent(SENT_ATTR(attr), "forwarded as %s", info->queue_id);
+       status = sent(BOUNCE_FLAGS(request), SENT_ATTR(attr),
+                     "forwarded as %s", info->queue_id);
 
     /*
      * Cleanup.
@@ -262,7 +265,7 @@ static int forward_send(FORWARD_INFO *info, DELIVER_ATTR attr, char *delivered)
 
 /* forward_finish - complete message forwarding requests and clean up */
 
-int     forward_finish(DELIVER_ATTR attr, int cancel)
+int     forward_finish(DELIVER_REQUEST *request, DELIVER_ATTR attr, int cancel)
 {
     HTABLE_INFO **dt_list;
     HTABLE_INFO **dt;
@@ -291,7 +294,7 @@ int     forward_finish(DELIVER_ATTR attr, int cancel)
            sender = sn[0]->key;
            info = (FORWARD_INFO *) sn[0]->value;
            if (status == 0)
-               status |= forward_send(info, attr, delivered);
+               status |= forward_send(info, request, attr, delivered);
            if (msg_verbose)
                msg_info("forward_finish: delivered %s sender %s status %d",
                         delivered, sender, status);
index 0bac66ef95d75d6aefef966d69f6dffc43985a7c..53d31a44739a9c257485e02a362713137962d514 100644 (file)
@@ -68,6 +68,7 @@
 #include <been_here.h>
 #include <mail_params.h>
 #include <ext_prop.h>
+#include <sent.h>
 
 /* Application-specific. */
 
@@ -106,16 +107,20 @@ int     deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
      * enabled.
      */
     if (*path != '/')
-       return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       return (bounce_append(BOUNCE_FLAGS(state.request),
+                             BOUNCE_ATTR(state.msg_attr),
                              ":include:%s uses a relative path", path));
     if (stat_as(path, &st, usr_attr.uid, usr_attr.gid) < 0)
-       return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
-                             "unable to lookup file %s: %m", path));
+       return (bounce_append(BOUNCE_FLAGS(state.request),
+                             BOUNCE_ATTR(state.msg_attr),
+                             "unable to lookup include file %s: %m", path));
     if (S_ISREG(st.st_mode) == 0)
-       return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       return (bounce_append(BOUNCE_FLAGS(state.request),
+                             BOUNCE_ATTR(state.msg_attr),
                              "not a regular include file: %s", path));
     if (st.st_mode & S_IWOTH)
-       return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       return (bounce_append(BOUNCE_FLAGS(state.request),
+                             BOUNCE_ATTR(state.msg_attr),
                              "world writable include file: %s", path));
 
     /*
@@ -141,7 +146,8 @@ int     deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     if (usr_attr.uid == 0) {
        if ((file_pwd = mypwuid(st.st_uid)) == 0) {
            msg_warn("cannot find username for uid %ld", (long) st.st_uid);
-           return (defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+           return (defer_append(BOUNCE_FLAGS(state.request),
+                                BOUNCE_ATTR(state.msg_attr),
                             "%s: cannot find :include: file owner", path));
        }
        if (file_pwd->pw_uid != 0)
@@ -177,7 +183,8 @@ int     deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
                                vstream_fdopen(fd,O_RDONLY) : 0)
 
     if ((fp = FOPEN_AS(path, usr_attr.uid, usr_attr.gid)) == 0) {
-       status = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       status = bounce_append(BOUNCE_FLAGS(state.request),
+                              BOUNCE_ATTR(state.msg_attr),
                               "cannot open include file %s: %m", path);
     } else {
        if ((local_ext_prop_mask & EXT_PROP_INCLUDE) == 0)
index 88e63eb84921503d621cdfbc7bd7f2b95b293948..4b81777f02345f6b500b5b1697b42a6260fcc7db 100644 (file)
@@ -49,6 +49,7 @@
 #include <bounce.h>
 #include <defer.h>
 #include <been_here.h>
+#include <sent.h>
 
 /* Application-specific. */
 
@@ -68,14 +69,23 @@ int     deliver_indirect(LOCAL_STATE state)
     if (msg_verbose)
        msg_info("deliver_indirect: %s", state.msg_attr.recipient);
     if (been_here(state.dup_filter, "indirect %s", state.msg_attr.recipient))
-           return (0);
+       return (0);
+
+    /*
+     * Don't forward a trace-only request.
+     */
+    if (DEL_REQ_TRACE_ONLY(state.request->flags))
+       return (sent(BOUNCE_FLAGS(state.request),
+                    SENT_ATTR(state.msg_attr),
+                    "forwards to %s", state.msg_attr.recipient));
 
     /*
      * Send the address to the forwarding service. Inherit the delivered
      * attribute from the alias or from the .forward file owner.
      */
     if (forward_append(state.msg_attr))
-       return (defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       return (defer_append(BOUNCE_FLAGS(state.request),
+                            BOUNCE_ATTR(state.msg_attr),
                             "unable to forward message"));
     return (0);
 }
index 4465de5d975ae1cff42f7bcee19e80dd5ff450f7..b0615286d33d594dbed4b0ba0b9f08bc4ce96b6b 100644 (file)
@@ -568,7 +568,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
        state.msg_attr.orig_rcpt = rcpt->orig_addr;
        state.msg_attr.recipient = rcpt->address;
        rcpt_stat = deliver_recipient(state, usr_attr);
-       rcpt_stat |= forward_finish(state.msg_attr, rcpt_stat);
+       rcpt_stat |= forward_finish(rqst, state.msg_attr, rcpt_stat);
        if (rcpt_stat == 0 && (rqst->flags & DEL_REQ_FLAG_SUCCESS))
            deliver_completed(state.msg_attr.fp, rcpt->offset);
        been_here_free(state.dup_filter);
index ef1e256fbd53bdd94e755681fd4681d405987758..32ad86d0249dad57e6d40c3142363ed2c2687ef0 100644 (file)
@@ -121,6 +121,8 @@ typedef struct LOCAL_STATE {
  /*
   * Bundle up some often-user attributes.
   */
+#define BOUNCE_FLAGS(request)  DEL_REQ_TRACE_FLAGS((request)->flags)
+
 #define BOUNCE_ATTR(attr)      attr.queue_id, attr.orig_rcpt, attr.recipient, \
                                        attr.relay, attr.arrival_time
 #define BOUNCE_ONE_ATTR(attr)  attr.queue_name, attr.queue_id, attr.encoding, \
@@ -204,7 +206,7 @@ extern int delivered_find(HTABLE *, char *);
   */
 extern int forward_init(void);
 extern int forward_append(DELIVER_ATTR);
-extern int forward_finish(DELIVER_ATTR, int);
+extern int forward_finish(DELIVER_REQUEST *, DELIVER_ATTR, int);
 
  /*
   * feature.c
index e867988fa9d2f3894aaf10a03ca7c70b645e4b23..7cbd8d7f05f6d775d10914d93cedaaf1797122d6 100644 (file)
@@ -113,6 +113,13 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     if (msg_verbose)
        MSG_LOG_STATE(myname, state);
 
+    /*
+     * Don't deliver trace-only requests.
+     */
+    if (DEL_REQ_TRACE_ONLY(state.request->flags))
+       return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+                    "delivers to mailbox"));
+
     /*
      * Initialize. Assume the operation will fail. Set the delivered
      * attribute to reflect the final recipient.
@@ -208,11 +215,13 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     } else if (mail_copy_status != 0) {
        deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
                          defer_append : bounce_append)
-           (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+           (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
             "cannot access mailbox %s for user %s. %s",
             mailbox, state.msg_attr.user, vstring_str(why));
     } else {
-       deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox");
+       deliver_status = sent(BOUNCE_FLAGS(state.request),
+                             SENT_ATTR(state.msg_attr),
+                             "delivered to mailbox");
        if (var_biff) {
            biff = vstring_alloc(100);
            vstring_sprintf(biff, "%s@%ld", usr_attr.logname, (long) end);
index 02899263f67e4a4373268d378c919ab9a66af456..6ff172d4cfa5ece9a37faa83d261cf6dfe5c6933 100644 (file)
@@ -92,6 +92,13 @@ int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     if (msg_verbose)
        MSG_LOG_STATE(myname, state);
 
+    /*
+     * Don't deliver trace-only requests.
+     */
+    if (DEL_REQ_TRACE_ONLY(state.request->flags))
+       return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+                    "delivers to maildir"));
+
     /*
      * Initialize. Assume the operation will fail. Set the delivered
      * attribute to reflect the final recipient.
@@ -161,10 +168,12 @@ int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     } else if (mail_copy_status != 0) {
        deliver_status = (errno == ENOSPC || errno == ESTALE ?
                          defer_append : bounce_append)
-           (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+           (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
             "maildir delivery failed: %s", vstring_str(why));
     } else {
-       deliver_status = sent(SENT_ATTR(state.msg_attr), "maildir");
+       deliver_status = sent(BOUNCE_FLAGS(state.request),
+                             SENT_ATTR(state.msg_attr),
+                             "delivered to maildir");
     }
     vstring_free(buf);
     vstring_free(why);
index e0b6443f4122ca3f85d9ca0f66849cb5d2bb791c..761d58420f03c097e0d4159d2640daf6944b3f23 100644 (file)
@@ -184,7 +184,7 @@ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
     if (var_stat_home_dir
        && (mypwd = mypwnam(state.msg_attr.user)) != 0
        && stat_as(mypwd->pw_dir, &st, mypwd->pw_uid, mypwd->pw_gid) < 0)
-       return (defer_append(BOUNCE_FLAG_KEEP,
+       return (defer_append(BOUNCE_FLAGS(state.request),
                             BOUNCE_ATTR(state.msg_attr),
                             "cannot access home directory %s: %m",
                             mypwd->pw_dir));
@@ -262,13 +262,13 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
            myfree(owner_alias);
        }
        if (canon_owner) {
-           rcpt_stat = bounce_one(BOUNCE_FLAG_KEEP,
+           rcpt_stat = bounce_one(BOUNCE_FLAGS(state.request),
                                   BOUNCE_ONE_ATTR(state.msg_attr),
                                   "mail forwarding loop for %s",
                                   state.msg_attr.recipient);
            vstring_free(canon_owner);
        } else {
-           rcpt_stat = bounce_append(BOUNCE_FLAG_KEEP,
+           rcpt_stat = bounce_append(BOUNCE_FLAGS(state.request),
                                      BOUNCE_ATTR(state.msg_attr),
                                      "mail forwarding loop for %s",
                                      state.msg_attr.recipient);
@@ -308,7 +308,8 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
      * Do not allow null usernames.
      */
     if (state.msg_attr.user[0] == 0)
-       return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       return (bounce_append(BOUNCE_FLAGS(state.request),
+                             BOUNCE_ATTR(state.msg_attr),
                          "null username in %s", state.msg_attr.recipient));
 
     /*
index e718ddb267aced2400a1e896fa151742310d924e..f495b6d81865f43532ee87bd453f0c3bf37be485 100644 (file)
@@ -118,11 +118,11 @@ int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
      * First, a healthy portion of error handling.
      */
     if (reply.flags & RESOLVE_FLAG_FAIL) {
-       status = defer_append(BOUNCE_FLAG_KEEP, /* XXX */
+       status = defer_append(BOUNCE_FLAGS(state.request),
                              BOUNCE_ATTR(state.msg_attr),
                              "address resolver failure");
     } else if (reply.flags & RESOLVE_FLAG_ERROR) {
-       status = bounce_append(BOUNCE_FLAG_KEEP,/* XXX */
+       status = bounce_append(BOUNCE_FLAGS(state.request),
                               BOUNCE_ATTR(state.msg_attr),
                               "bad recipient address syntax: %s",
                               STR(reply.recipient));
index c427eb7042c4b24e1985822fe12722cda427804e..1da680c0118717fdb6941c0eba62ec53f1eb75b0 100644 (file)
@@ -111,11 +111,11 @@ static int deliver_token_home(LOCAL_STATE state, USER_ATTR usr_attr, char *addr)
     int     status;
 
     if (addr[1] != '/') {                      /* disallow ~user */
-       status = bounce_append(BOUNCE_FLAG_KEEP,
+       status = bounce_append(BOUNCE_FLAGS(state.request),
                               BOUNCE_ATTR(state.msg_attr),
                               "bad home directory syntax for: %s", addr);
     } else if (usr_attr.home == 0) {           /* require user context */
-       status = bounce_append(BOUNCE_FLAG_KEEP,
+       status = bounce_append(BOUNCE_FLAGS(state.request),
                               BOUNCE_ATTR(state.msg_attr),
                               "unknown home directory for: %s", addr);
     } else if (usr_attr.home[0] == '/' && usr_attr.home[1] == 0) {
@@ -149,7 +149,7 @@ int     deliver_token(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr)
        status = deliver_token_home(state, usr_attr, STR(addr_buf));
     } else if (*STR(addr_buf) == '|') {
        if ((local_cmd_deliver_mask & state.msg_attr.exp_type) == 0)
-           status = bounce_append(BOUNCE_FLAG_KEEP,
+           status = bounce_append(BOUNCE_FLAGS(state.request),
                                   BOUNCE_ATTR(state.msg_attr),
                                   "mail to command is restricted");
        else
index 18774e44f19c66c7590cd0e7fdc5870596f2318c..062a32888aa7bf1452df5a393ff86e232795204c 100644 (file)
@@ -132,12 +132,15 @@ int     deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
     if (STREQ(state.msg_attr.local, MAIL_ADDR_MAIL_DAEMON)
        || STREQ(state.msg_attr.local, MAIL_ADDR_POSTMASTER)) {
        msg_warn("required alias not found: %s", state.msg_attr.local);
-       return (sent(SENT_ATTR(state.msg_attr), "discarded"));
+       return (sent(BOUNCE_FLAGS(state.request),
+                    SENT_ATTR(state.msg_attr),
+                    "discarded"));
     }
 
     /*
      * Bounce the message when no luser relay is specified.
      */
-    return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+    return (bounce_append(BOUNCE_FLAGS(state.request),
+                         BOUNCE_ATTR(state.msg_attr),
                          "unknown user: \"%s\"", state.msg_attr.local));
 }
index 771cac5079b338905444a7656ab9f5ab082956b4..1b1b139b83a9261cad47adc9b016083b9b1d277d 100644 (file)
@@ -96,7 +96,9 @@ qmgr_active.o: ../../include/mail_queue.h
 qmgr_active.o: ../../include/vstring.h
 qmgr_active.o: ../../include/recipient_list.h
 qmgr_active.o: ../../include/bounce.h
+qmgr_active.o: ../../include/deliver_request.h
 qmgr_active.o: ../../include/defer.h
+qmgr_active.o: ../../include/trace.h
 qmgr_active.o: ../../include/abounce.h
 qmgr_active.o: ../../include/rec_type.h
 qmgr_active.o: qmgr.h
@@ -104,9 +106,12 @@ qmgr_active.o: ../../include/scan_dir.h
 qmgr_bounce.o: qmgr_bounce.c
 qmgr_bounce.o: ../../include/sys_defs.h
 qmgr_bounce.o: ../../include/bounce.h
-qmgr_bounce.o: ../../include/deliver_completed.h
-qmgr_bounce.o: ../../include/vstream.h
+qmgr_bounce.o: ../../include/deliver_request.h
+qmgr_bounce.o: ../../include/vstring.h
 qmgr_bounce.o: ../../include/vbuf.h
+qmgr_bounce.o: ../../include/vstream.h
+qmgr_bounce.o: ../../include/recipient_list.h
+qmgr_bounce.o: ../../include/deliver_completed.h
 qmgr_bounce.o: qmgr.h
 qmgr_bounce.o: ../../include/scan_dir.h
 qmgr_defer.o: qmgr_defer.c
@@ -116,6 +121,9 @@ qmgr_defer.o: ../../include/vstream.h
 qmgr_defer.o: ../../include/vbuf.h
 qmgr_defer.o: ../../include/defer.h
 qmgr_defer.o: ../../include/bounce.h
+qmgr_defer.o: ../../include/deliver_request.h
+qmgr_defer.o: ../../include/vstring.h
+qmgr_defer.o: ../../include/recipient_list.h
 qmgr_defer.o: qmgr.h
 qmgr_defer.o: ../../include/scan_dir.h
 qmgr_deliver.o: qmgr_deliver.c
@@ -183,6 +191,8 @@ qmgr_message.o: ../../include/canon_addr.h
 qmgr_message.o: ../../include/record.h
 qmgr_message.o: ../../include/rec_type.h
 qmgr_message.o: ../../include/sent.h
+qmgr_message.o: ../../include/deliver_request.h
+qmgr_message.o: ../../include/recipient_list.h
 qmgr_message.o: ../../include/deliver_completed.h
 qmgr_message.o: ../../include/opened.h
 qmgr_message.o: ../../include/verp_sender.h
index 76bd52b3ed2c06e126a53025225bdc41b92d3efd..54d91e588948b0ef90278f6d41516968f960f7e9 100644 (file)
@@ -252,6 +252,7 @@ extern QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *, QMGR_MESSAGE *);
 struct QMGR_MESSAGE {
     int     flags;                     /* delivery problems */
     int     qflags;                    /* queuing flags */
+    int     tflags;                    /* tracing flags */
     VSTREAM *fp;                       /* open queue file or null */
     int     refcount;                  /* queue entries */
     int     single_rcpt;               /* send one rcpt at a time */
index dd0044b4c7b90bbf59eaee3ff002f3571f600b9d..67f574253dd35015aca98a064946d19d0fec0451 100644 (file)
 #include <recipient_list.h>
 #include <bounce.h>
 #include <defer.h>
+#include <trace.h>
 #include <abounce.h>
 #include <rec_type.h>
 
@@ -357,6 +358,18 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
        return;
     }
 
+    /*
+     * As a temporary implementation, synchronously inform the sender of
+     * trace information. This will block for 10 seconds when the qmgr FIFO
+     * is full.
+     */
+    if (message->tflags & (DEL_REQ_FLAG_EXPAND | DEL_REQ_FLAG_RECORD))
+        message->flags |= trace_flush(message->tflags,
+                                      message->queue_name,
+                                      message->queue_id,
+                                      message->encoding,
+                                      message->sender);
+
     /*
      * If we get to this point we have tried all recipients for this message.
      * If the message is too old, try to bounce it.
index 759ab9fef8fb2c568424948a115eaa164fd0448c..3405c5b76fe234d1d61815a6cbef90b438b70b5a 100644 (file)
@@ -155,8 +155,8 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
      * concurrency limits. However, the delivery agent protocol expects
      * nexthop only, so we must strip off the recipient local part.
      */
-    flags = message->inspect_xport ?
-       DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT;
+    flags = message->tflags
+       | (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
     nexthop = (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ?
        cp + 1 : entry->queue->name;
     attr_print(stream, ATTR_FLAG_MORE,
index 83b7d5c9e7b23a2e87bb8cc7203e5f888fc6dcbd..7d77c849ca5d9a399923a279e2b59a53f3284d36 100644 (file)
@@ -144,6 +144,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
     qmgr_message_count++;
     message->flags = 0;
     message->qflags = qflags;
+    message->tflags = 0;
     message->fp = 0;
     message->refcount = 0;
     message->single_rcpt = 0;
@@ -427,6 +428,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                    myfree(message->encoding);
                message->encoding = mystrdup(value);
            }
+           /* Optional tracing flags. */
+           else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
+               message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
+           }
        } else if (rec_type == REC_TYPE_ERTO) {
            if (message->errors_to == 0) {
                message->errors_to = mystrdup(start);
@@ -628,6 +633,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
     char  **cpp;
     char   *nexthop;
     int     len;
+    int     status;
 
 #define STREQ(x,y)     (strcmp(x,y) == 0)
 #define STR            vstring_str
@@ -775,12 +781,15 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
            if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
                            len) == 0
                && !var_double_bounce_sender[len]) {
-               sent(message->queue_id, recipient->orig_rcpt,
-                    recipient->address, "none", message->arrival_time,
-                    "discarded");
-               deliver_completed(message->fp, recipient->offset);
-               msg_warn("%s: undeliverable postmaster notification discarded",
-                        message->queue_id);
+               status = sent(message->tflags, message->queue_id, recipient->orig_rcpt,
+                         recipient->address, "none", message->arrival_time,
+                        "undeliverable postmaster notification discarded");
+               if (status == 0) {
+                   deliver_completed(message->fp, recipient->offset);
+                   msg_warn("%s: undeliverable postmaster notification discarded",
+                            message->queue_id);
+               } else
+                   message->flags |= status;
                continue;
            }
        }
index b8f697b281a33502ca8da7cd25dc098e37c21122..281ee54ac510149c3e9d775aada47be8937ef3fd 100644 (file)
@@ -203,10 +203,11 @@ static int copy_segment(VSTREAM *qfile, VSTREAM *cleanup, PICKUP_INFO *info,
            }
 #define STREQ(x,y) (strcmp(x,y) == 0)
 
-           if (STREQ(attr_name, MAIL_ATTR_ENCODING)
-               && (STREQ(attr_value, MAIL_ATTR_ENC_7BIT)
-                   || STREQ(attr_value, MAIL_ATTR_ENC_8BIT)
-                   || STREQ(attr_value, MAIL_ATTR_ENC_NONE))) {
+           if ((STREQ(attr_name, MAIL_ATTR_ENCODING)
+                && (STREQ(attr_value, MAIL_ATTR_ENC_7BIT)
+                    || STREQ(attr_value, MAIL_ATTR_ENC_8BIT)
+                    || STREQ(attr_value, MAIL_ATTR_ENC_NONE)))
+               || STREQ(attr_name, MAIL_ATTR_TRACE_FLAGS)) {   /* XXX */
                rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%s",
                            attr_name, attr_value);
            } else if (info->st.st_uid != var_owner_uid) {
index 9cec20901f8a444f3b210c20b605bda0d4104899..8dc0fe7f04950cde78dbd2aeaf6ec6406fd7abdc 100644 (file)
@@ -706,16 +706,19 @@ static int eval_command_status(int command_status, char *service,
     case PIPE_STAT_OK:
        for (n = 0; n < request->rcpt_list.len; n++) {
            rcpt = request->rcpt_list.info + n;
-           sent(request->queue_id, rcpt->orig_addr, rcpt->address, service,
-                request->arrival_time, "%s", request->nexthop);
-           if (request->flags & DEL_REQ_FLAG_SUCCESS)
+           status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
+                         request->queue_id, rcpt->orig_addr,
+                         rcpt->address, service,
+                         request->arrival_time, "%s", request->nexthop);
+           if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
                deliver_completed(src, rcpt->offset);
+           result |= status;
        }
        break;
     case PIPE_STAT_BOUNCE:
        for (n = 0; n < request->rcpt_list.len; n++) {
            rcpt = request->rcpt_list.info + n;
-           status = bounce_append(BOUNCE_FLAG_KEEP,
+           status = bounce_append(DEL_REQ_TRACE_FLAGS(request->flags),
                                   request->queue_id, rcpt->orig_addr,
                                   rcpt->address, service,
                                   request->arrival_time, "%s", why);
@@ -727,7 +730,7 @@ static int eval_command_status(int command_status, char *service,
     case PIPE_STAT_DEFER:
        for (n = 0; n < request->rcpt_list.len; n++) {
            rcpt = request->rcpt_list.info + n;
-           result |= defer_append(BOUNCE_FLAG_KEEP,
+           result |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
                                   request->queue_id, rcpt->orig_addr,
                                   rcpt->address, service,
                                   request->arrival_time, "%s", why);
@@ -837,6 +840,30 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
        return (deliver_status);
     }
 
+    /*
+     * Don't deliver a trace-only request.
+     */
+    if (DEL_REQ_TRACE_ONLY(request->flags)) {
+       RECIPIENT *rcpt;
+       int     status;
+       int     n;
+
+       deliver_status = 0;
+       for (n = 0; n < request->rcpt_list.len; n++) {
+           rcpt = request->rcpt_list.info + n;
+           status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
+                         request->queue_id, rcpt->orig_addr,
+                         rcpt->address, service,
+                         request->arrival_time,
+                         "delivers to command: %s", attr.command[0]);
+           if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
+               deliver_completed(request->fp, rcpt->offset);
+           deliver_status |= status;
+       }
+       DELIVER_MSG_CLEANUP();
+       return (deliver_status);
+    }
+
     /*
      * Deliver. Set the nexthop and sender variables, and expand the command
      * argument vector. Recipients will be expanded on the fly. XXX Rewrite
index 46876ee9d2840b46dcc8b7afc6aa40e1ab597714..1565d2a171e1dde02fb71a727ceba2b6baa76e38 100644 (file)
@@ -17,7 +17,7 @@
 /*     \fB-s\fR and \fB-p\fR command-line options on all Postfix queue
 /*     directories - this includes the \fBincoming\fR, \fBactive\fR and
 /*     \fBdeferred\fR directories with mail files and the \fBbounce\fR,
-/*     \fBdefer\fR and \fBflush\fR directories with log files.
+/*     \fBdefer\fR, \fBtrace\fR and \fBflush\fR directories with log files.
 /*
 /*     Options:
 /* .IP "\fB-c \fIconfig_dir\fR"
@@ -261,6 +261,7 @@ static struct queue_info queue_info[] = {
     MAIL_QUEUE_ACTIVE, MAIL_QUEUE_STAT_READY, RECURSE,
     MAIL_QUEUE_DEFERRED, MAIL_QUEUE_STAT_READY, RECURSE,
     MAIL_QUEUE_HOLD, MAIL_QUEUE_STAT_READY, RECURSE,
+    MAIL_QUEUE_TRACE, 0600, RECURSE,
     MAIL_QUEUE_DEFER, 0600, RECURSE,
     MAIL_QUEUE_BOUNCE, 0600, RECURSE,
     MAIL_QUEUE_FLUSH, 0600, RECURSE,
@@ -273,6 +274,7 @@ static struct queue_info queue_info[] = {
 const char *log_queue_names[] = {
     MAIL_QUEUE_BOUNCE,
     MAIL_QUEUE_DEFER,
+    MAIL_QUEUE_TRACE,
     0,
 };
 
@@ -389,7 +391,7 @@ static int delete_one(const char **queue_names, const char *queue_id)
     log_path_buf = vstring_alloc(100);
 
     /*
-     * Skip meta file directories. Delete defer or bounce logfiles before
+     * Skip meta file directories. Delete trace/defer/bounce logfiles before
      * deleting the corresponding message file, and only if the message file
      * exists. This minimizes but does not eliminate a race condition with
      * queue ID reuse which results in deleting the wrong files.
index 35212640b4d0c1b6a8f4898a8fbe43b171a99945..e128810a77f0dccc87d283b01a0d8e2630310f09 100644 (file)
@@ -94,7 +94,9 @@ qmgr_active.o: ../../include/mail_queue.h
 qmgr_active.o: ../../include/vstring.h
 qmgr_active.o: ../../include/recipient_list.h
 qmgr_active.o: ../../include/bounce.h
+qmgr_active.o: ../../include/deliver_request.h
 qmgr_active.o: ../../include/defer.h
+qmgr_active.o: ../../include/trace.h
 qmgr_active.o: ../../include/abounce.h
 qmgr_active.o: ../../include/rec_type.h
 qmgr_active.o: qmgr.h
@@ -102,9 +104,12 @@ qmgr_active.o: ../../include/scan_dir.h
 qmgr_bounce.o: qmgr_bounce.c
 qmgr_bounce.o: ../../include/sys_defs.h
 qmgr_bounce.o: ../../include/bounce.h
-qmgr_bounce.o: ../../include/deliver_completed.h
-qmgr_bounce.o: ../../include/vstream.h
+qmgr_bounce.o: ../../include/deliver_request.h
+qmgr_bounce.o: ../../include/vstring.h
 qmgr_bounce.o: ../../include/vbuf.h
+qmgr_bounce.o: ../../include/vstream.h
+qmgr_bounce.o: ../../include/recipient_list.h
+qmgr_bounce.o: ../../include/deliver_completed.h
 qmgr_bounce.o: qmgr.h
 qmgr_bounce.o: ../../include/scan_dir.h
 qmgr_defer.o: qmgr_defer.c
@@ -114,6 +119,9 @@ qmgr_defer.o: ../../include/vstream.h
 qmgr_defer.o: ../../include/vbuf.h
 qmgr_defer.o: ../../include/defer.h
 qmgr_defer.o: ../../include/bounce.h
+qmgr_defer.o: ../../include/deliver_request.h
+qmgr_defer.o: ../../include/vstring.h
+qmgr_defer.o: ../../include/recipient_list.h
 qmgr_defer.o: qmgr.h
 qmgr_defer.o: ../../include/scan_dir.h
 qmgr_deliver.o: qmgr_deliver.c
@@ -170,6 +178,8 @@ qmgr_message.o: ../../include/canon_addr.h
 qmgr_message.o: ../../include/record.h
 qmgr_message.o: ../../include/rec_type.h
 qmgr_message.o: ../../include/sent.h
+qmgr_message.o: ../../include/deliver_request.h
+qmgr_message.o: ../../include/recipient_list.h
 qmgr_message.o: ../../include/deliver_completed.h
 qmgr_message.o: ../../include/opened.h
 qmgr_message.o: ../../include/verp_sender.h
index f8beea11682323976bbca6c0c2613cb54eb1c731..e553e1793e0bc3d307b92d56fef41b85771cceac 100644 (file)
@@ -214,6 +214,7 @@ extern QMGR_ENTRY *qmgr_entry_create(QMGR_QUEUE *, QMGR_MESSAGE *);
 struct QMGR_MESSAGE {
     int     flags;                     /* delivery problems */
     int     qflags;                    /* queuing flags */
+    int     tflags;                    /* tracing flags */
     VSTREAM *fp;                       /* open queue file or null */
     int     refcount;                  /* queue entries */
     int     single_rcpt;               /* send one rcpt at a time */
index dd0044b4c7b90bbf59eaee3ff002f3571f600b9d..3e25b6323e810dba20fa6b3b60a5641b51ec4f0b 100644 (file)
 #include <recipient_list.h>
 #include <bounce.h>
 #include <defer.h>
+#include <trace.h>
 #include <abounce.h>
 #include <rec_type.h>
 
@@ -357,6 +358,18 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
        return;
     }
 
+    /*
+     * As a temporary implementation, synchronously inform the sender of
+     * trace information. This will block for 10 seconds when the qmgr FIFO
+     * is full.
+     */
+    if (message->tflags & (DEL_REQ_FLAG_EXPAND | DEL_REQ_FLAG_RECORD))
+       message->flags |= trace_flush(message->tflags,
+                                     message->queue_name,
+                                     message->queue_id,
+                                     message->encoding,
+                                     message->sender);
+
     /*
      * If we get to this point we have tried all recipients for this message.
      * If the message is too old, try to bounce it.
index 1986a074811c77ec13bd3cfd101707ea1100a9be..189baa5be95dd2fa2fceae0bbc2b83fa8c11d2ae 100644 (file)
@@ -150,8 +150,8 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
      * concurrency limits. However, the delivery agent protocol expects
      * nexthop only, so we must strip off the recipient local part.
      */
-    flags = message->inspect_xport ?
-       DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT;
+    flags = message->tflags
+       | (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
     nexthop = (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ?
        cp + 1 : entry->queue->name;
     attr_print(stream, ATTR_FLAG_MORE,
index 011f6020a51bba90ccfc5be1b959786a27b2a385..16a0c2245e69a3708a1f40c0deb425753aecec7d 100644 (file)
@@ -135,6 +135,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
     qmgr_message_count++;
     message->flags = 0;
     message->qflags = qflags;
+    message->tflags = 0;
     message->fp = 0;
     message->refcount = 0;
     message->single_rcpt = 0;
@@ -317,6 +318,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
                    myfree(message->encoding);
                message->encoding = mystrdup(value);
            }
+           /* Optional tracing flags. */
+           else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
+               message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
+           }
        } else if (rec_type == REC_TYPE_ERTO) {
            if (message->errors_to == 0)
                message->errors_to = mystrdup(start);
@@ -508,6 +513,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
     char  **cpp;
     char   *nexthop;
     int     len;
+    int     status;
 
 #define STREQ(x,y)     (strcasecmp(x,y) == 0)
 #define STR            vstring_str
@@ -655,12 +661,15 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
            if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
                            len) == 0
                && !var_double_bounce_sender[len]) {
-               sent(message->queue_id, recipient->orig_rcpt,
-                    recipient->address, "none", message->arrival_time,
-                    "discarded");
-               deliver_completed(message->fp, recipient->offset);
-               msg_warn("%s: undeliverable postmaster notification discarded",
-                        message->queue_id);
+               status = sent(message->tflags, message->queue_id, recipient->orig_rcpt,
+                         recipient->address, "none", message->arrival_time,
+                        "undeliverable postmaster notification discarded");
+               if (status == 0) {
+                   deliver_completed(message->fp, recipient->offset);
+                   msg_warn("%s: undeliverable postmaster notification discarded",
+                            message->queue_id);
+               } else
+                   message->flags |= status;
                continue;
            }
        }
index e6e96aa0f16dcb83681e89918bfa38e3f9096eb0..50d16cca453fbe0d39de854ead8d4cf0ccb0c127 100644 (file)
@@ -90,3 +90,5 @@ sendmail.o: ../../include/resolve_clnt.h
 sendmail.o: ../../include/mail_flush.h
 sendmail.o: ../../include/mail_stream.h
 sendmail.o: ../../include/verp_sender.h
+sendmail.o: ../../include/deliver_request.h
+sendmail.o: ../../include/recipient_list.h
index 954bd07173bbb30871bd61ca90b1bced995040a1..00785b831fc81f3c48bbe338484b3d3fdedff1cd 100644 (file)
 /* .sp
 /*     This mode of operation is implemented by running the
 /*     \fBsmtpd\fR(8) daemon.
+/* .IP \fB-bv\fR
+/*     Send an email report after verifying each recipient address.
+/*     Verification always happens in the background. This is useful
+/*     for testing address rewriting and routing configurations.
 /* .IP "\fB-f \fIsender\fR"
 /*     Set the envelope sender address. This is the address where
 /*     delivery problems are sent to, unless the message contains an
 /*     Extract recipients from message headers. This requires that no
 /*     recipients be specified on the command line.
 /* .IP \fB-v\fR
-/*     Enable verbose logging for debugging purposes. Multiple \fB-v\fR
-/*     options make the software increasingly verbose. For compatibility
-/*     with mailx and other mail submission software, a single \fB-v\fR
-/*     option produces no output.
+/*     Send an email report of all delivery attempts (mail delivery
+/*     always happens in the background). When multiple \fB-v\fR
+/*     options are given, enable verbose logging for debugging purposes.
 /* SECURITY
 /* .ad
 /* .fi
 #include <mail_flush.h>
 #include <mail_stream.h>
 #include <verp_sender.h>
+#include <deliver_request.h>
 
 /* Application-specific. */
 
 #define SM_MODE_FLUSHQ         6       /* user (stand-alone) mode */
 
  /*
-  * Flag parade.
+  * Flag parade. Flags 8-15 are reserved for delivery request trace flags.
   */
 #define SM_FLAG_AEOF   (1<<0)          /* archaic EOF */
 
@@ -437,6 +441,9 @@ static void enqueue(const int flags, const char *encoding, const char *sender,
                         "-V option requires non-null sender address");
     if (encoding)
        rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ENCODING, encoding);
+    if (DEL_REQ_TRACE_FLAGS(flags))
+       rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_TRACE_FLAGS,
+                   DEL_REQ_TRACE_FLAGS(flags));
     if (verp_delims)
        rec_fputs(dst, REC_TYPE_VERP, verp_delims);
     if (recipients) {
@@ -465,34 +472,45 @@ static void enqueue(const int flags, const char *encoding, const char *sender,
      * of UUCP environments, also get rid of leading >>>From_ lines.
      */
     rec_fprintf(dst, REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0L);
-    skip_from_ = 1;
-    strip_cr = STRIP_CR_DUNNO;
-    for (prev_type = 0; (type = rec_streamlf_get(VSTREAM_IN, buf, var_line_limit))
-        != REC_TYPE_EOF; prev_type = type) {
-       if (strip_cr == STRIP_CR_DUNNO && type == REC_TYPE_NORM) {
-           if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
-               strip_cr = STRIP_CR_DO;
-           else
-               strip_cr = STRIP_CR_DONT;
+    if (DEL_REQ_TRACE_ONLY(flags) != 0) {
+       rec_fprintf(dst, REC_TYPE_NORM, "Subject: probe");
+       if (recipients) {
+           rec_fprintf(dst, REC_TYPE_NORM, "To:");
+           for (cpp = recipients; *cpp != 0; cpp++) {
+               rec_fprintf(dst, REC_TYPE_NORM, "       %s%s",
+                           *cpp, cpp[1] ? "," : "");
+           }
        }
-       if (skip_from_) {
-           if (type == REC_TYPE_NORM) {
-               start = vstring_str(buf);
-               if (strncmp(start + strspn(start, ">"), "From ", 5) == 0)
-                   continue;
+    } else {
+       skip_from_ = 1;
+       strip_cr = STRIP_CR_DUNNO;
+       for (prev_type = 0; (type = rec_streamlf_get(VSTREAM_IN, buf, var_line_limit))
+            != REC_TYPE_EOF; prev_type = type) {
+           if (strip_cr == STRIP_CR_DUNNO && type == REC_TYPE_NORM) {
+               if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
+                   strip_cr = STRIP_CR_DO;
+               else
+                   strip_cr = STRIP_CR_DONT;
+           }
+           if (skip_from_) {
+               if (type == REC_TYPE_NORM) {
+                   start = vstring_str(buf);
+                   if (strncmp(start + strspn(start, ">"), "From ", 5) == 0)
+                       continue;
+               }
+               skip_from_ = 0;
            }
-           skip_from_ = 0;
+           if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM)
+               if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
+                   vstring_truncate(buf, VSTRING_LEN(buf) - 1);
+           if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT
+               && VSTRING_LEN(buf) == 1 && *STR(buf) == '.')
+               break;
+           if (REC_PUT_BUF(dst, type, buf) < 0)
+               msg_fatal_status(EX_TEMPFAIL,
+                                "%s(%ld): error writing queue file: %m",
+                                saved_sender, (long) uid);
        }
-       if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM)
-           if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
-               vstring_truncate(buf, VSTRING_LEN(buf) - 1);
-       if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT
-           && VSTRING_LEN(buf) == 1 && *STR(buf) == '.')
-           break;
-       if (REC_PUT_BUF(dst, type, buf) < 0)
-           msg_fatal_status(EX_TEMPFAIL,
-                            "%s(%ld): error writing queue file: %m",
-                            saved_sender, (long) uid);
     }
 
     /*
@@ -521,6 +539,15 @@ static void enqueue(const int flags, const char *encoding, const char *sender,
                         EX_UNAVAILABLE, "%s(%ld): %s", saved_sender,
                         (long) uid, cleanup_strerror(status));
 
+    /*
+     * Don't leave them in the dark.
+     */
+    if (DEL_REQ_TRACE_FLAGS(flags)) {
+       vstream_printf("Mail Delivery Status Report will be mailed to <%s>.\n",
+                      saved_sender);
+       vstream_fflush(VSTREAM_OUT);
+    }
+
     /*
      * Cleanup. Not really necessary as we're about to exit, but good for
      * debugging purposes.
@@ -609,6 +636,7 @@ int     main(int argc, char **argv)
      * Further initialization...
      */
     mail_conf_read();
+
     if (chdir(var_queue_dir))
        msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir);
 
@@ -715,6 +743,9 @@ int     main(int argc, char **argv)
            case 's':                           /* stand-alone mode */
                mode = SM_MODE_USER;
                break;
+           case 'v':                           /* expand recipients */
+               flags |= DEL_REQ_FLAG_EXPAND;
+               break;
            }
            break;
        case 'f':
@@ -776,13 +807,6 @@ int     main(int argc, char **argv)
        }
     }
 
-    /*
-     * Workaround: produce no output when verbose delivery is requested in
-     * mail.rc.
-     */
-    if (msg_verbose > 0)
-       msg_verbose--;
-
     /*
      * Look for conflicting options and arguments.
      */
@@ -796,6 +820,15 @@ int     main(int argc, char **argv)
        msg_fatal_status(EX_USAGE,
                         "cannot handle command-line recipients with -t");
 
+    /*
+     * The -v option plays double duty. One requests verbose delivery, more
+     * than one requests verbose logging.
+     */
+    if (msg_verbose == 1 && mode == SM_MODE_ENQUEUE) {
+       msg_verbose = 0;
+       flags |= DEL_REQ_FLAG_RECORD;
+    }
+
     /*
      * Start processing. Everything is delegated to external commands.
      */
index 86b825ebe0fb27c4b58fabea6410db2e4156ae43..420006b02d2051e3ef4dfcca46ec1e1b3fe87b46 100644 (file)
 /*     Timeout for sending the "\fB.\fR" command, and for
 /*     receiving the server response. When no response is received, a
 /*     warning is logged that the mail may be delivered multiple times.
+/* .IP \fBsmtp_rset_timeout\fR
+/*     Timeout for sending the \fBRSET\fR command.
 /* .IP \fBsmtp_quit_timeout\fR
 /*     Timeout for sending the \fBQUIT\fR command, and for
 /*     receiving the server response.
@@ -268,6 +270,7 @@ int     var_smtp_rcpt_tmout;
 int     var_smtp_data0_tmout;
 int     var_smtp_data1_tmout;
 int     var_smtp_data2_tmout;
+int     var_smtp_rset_tmout;
 int     var_smtp_quit_tmout;
 char   *var_inet_interfaces;
 char   *var_notify_classes;
@@ -452,6 +455,7 @@ int     main(int argc, char **argv)
        VAR_SMTP_DATA0_TMOUT, DEF_SMTP_DATA0_TMOUT, &var_smtp_data0_tmout, 1, 0,
        VAR_SMTP_DATA1_TMOUT, DEF_SMTP_DATA1_TMOUT, &var_smtp_data1_tmout, 1, 0,
        VAR_SMTP_DATA2_TMOUT, DEF_SMTP_DATA2_TMOUT, &var_smtp_data2_tmout, 1, 0,
+       VAR_SMTP_RSET_TMOUT, DEF_SMTP_RSET_TMOUT, &var_smtp_rset_tmout, 1, 0,
        VAR_SMTP_QUIT_TMOUT, DEF_SMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0,
        VAR_SMTP_PIX_THRESH, DEF_SMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0,
        VAR_SMTP_PIX_DELAY, DEF_SMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0,
index 092a5d19772c62cecf49d10a685928616023080c..566af74d6c7f569681f3a626bd17302f118df192 100644 (file)
@@ -160,7 +160,7 @@ void    smtp_chat_cmd(SMTP_STATE *state, char *fmt,...)
      * Abort immediately if the connection is broken.
      */
     if (vstream_ftimeout(session->stream))
-        vstream_longjmp(session->stream, SMTP_ERR_TIME);
+       vstream_longjmp(session->stream, SMTP_ERR_TIME);
     if (vstream_ferror(session->stream))
        vstream_longjmp(session->stream, SMTP_ERR_EOF);
 }
@@ -261,12 +261,14 @@ void    smtp_chat_notify(SMTP_STATE *state)
      * generate from untrusted data.
      */
 #define NULL_CLEANUP_FLAGS     0
+#define NULL_TRACE_FLAGS       0
 #define LENGTH 78
 #define INDENT 4
 
     notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                    var_error_rcpt,
-                                   NULL_CLEANUP_FLAGS);
+                                   NULL_CLEANUP_FLAGS,
+                                   NULL_TRACE_FLAGS);
     if (notice == 0) {
        msg_warn("postmaster notify: %m");
        return;
index b5c3007a5bec36ff0c6725bcb41fc71e8a26c862..0ad53abeb9351a9e1a0ed1e284025ebba1322191 100644 (file)
@@ -136,7 +136,7 @@ int    *xfer_timeouts[SMTP_STATE_LAST] = {
     &var_smtp_rcpt_tmout,
     &var_smtp_data0_tmout,
     &var_smtp_data2_tmout,
-    &var_smtp_quit_tmout,
+    &var_smtp_rset_tmout,
     &var_smtp_quit_tmout,
 };
 
@@ -517,7 +517,8 @@ int     smtp_xfer(SMTP_STATE *state)
            vstring_sprintf(next_command, "RCPT TO:<%s>",
                            vstring_str(state->scratch));
            if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
-               next_state = SMTP_STATE_DATA;
+               next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
+                   SMTP_STATE_ABORT : SMTP_STATE_DATA;
            break;
 
            /*
@@ -538,11 +539,15 @@ int     smtp_xfer(SMTP_STATE *state)
            break;
 
            /*
-            * Can't happen. The SMTP_STATE_ABORT sender state is entered by
-            * the receiver and is left before the bottom of the main loop.
+            * The SMTP_STATE_ABORT sender state is entered by sender when it
+            * has verified all recipients; or it is entered the receiver
+            * when all recipients are rejected and is then left before the
+            * bottom of the main loop.
             */
        case SMTP_STATE_ABORT:
-           msg_panic("%s: sender abort state", myname);
+           vstring_strcpy(next_command, "RSET");
+           next_state = SMTP_STATE_QUIT;
+           break;
 
            /*
             * Build the QUIT command before we have seen the "." or RSET
@@ -637,6 +642,17 @@ int     smtp_xfer(SMTP_STATE *state)
 #endif
                        if (resp->code / 100 == 2) {
                            ++nrcpt;
+                           /* If trace-only, mark the recipient done. */
+                           if (DEL_REQ_TRACE_ONLY(request->flags)
+                               && sent(DEL_REQ_TRACE_FLAGS(request->flags),
+                                       request->queue_id, rcpt->orig_addr,
+                                       rcpt->address, session->namaddr,
+                                       request->arrival_time, "%s",
+                                       translit(resp->str, "\n", " ")) == 0) {
+                               if (request->flags & DEL_REQ_FLAG_SUCCESS)
+                                   deliver_completed(state->src, rcpt->offset);
+                               rcpt->offset = 0;       /* in case deferred */
+                           }
                        } else {
                            rcpt = request->rcpt_list.info + recv_rcpt;
                            smtp_rcpt_fail(state, resp->code, rcpt,
@@ -647,8 +663,10 @@ int     smtp_xfer(SMTP_STATE *state)
                            rcpt->offset = 0;   /* in case deferred */
                        }
                    }
+                   /* If trace-only, send RSET instead of DATA. */
                    if (++recv_rcpt == request->rcpt_list.len)
-                       recv_state = SMTP_STATE_DATA;
+                       recv_state = DEL_REQ_TRACE_ONLY(request->flags) ?
+                           SMTP_STATE_ABORT : SMTP_STATE_DATA;
                    break;
 
                    /*
@@ -690,14 +708,16 @@ int     smtp_xfer(SMTP_STATE *state)
                            for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
                                rcpt = request->rcpt_list.info + nrcpt;
                                if (rcpt->offset) {
-                                   sent(request->queue_id, rcpt->orig_addr,
-                                        rcpt->address,
-                                        session->namaddr,
-                                        request->arrival_time, "%s",
-                                        resp->str);
-                                   if (request->flags & DEL_REQ_FLAG_SUCCESS)
-                                       deliver_completed(state->src, rcpt->offset);
-                                   rcpt->offset = 0;
+                                   if (sent(DEL_REQ_TRACE_FLAGS(request->flags),
+                                        request->queue_id, rcpt->orig_addr,
+                                            rcpt->address,
+                                            session->namaddr,
+                                            request->arrival_time,
+                                            "%s", resp->str) == 0) {
+                                       if (request->flags & DEL_REQ_FLAG_SUCCESS)
+                                           deliver_completed(state->src, rcpt->offset);
+                                       rcpt->offset = 0;
+                                   }
                                }
                            }
                        }
index ef78e51f302e1781b85140e25d549535c32ee3b8..6269c7c4fd37d6f9c306f7011e7910dd13953f2f 100644 (file)
 
 #define SMTP_SOFT(code) (((code) / 100) == 4)
 #define SMTP_HARD(code) (((code) / 100) == 5)
-#define KEEP           BOUNCE_FLAG_KEEP
 
 /* smtp_check_code - check response code */
 
@@ -167,7 +166,8 @@ int     smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
        if (rcpt->offset == 0)
            continue;
        status = (soft_error ? defer_append : bounce_append)
-           (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+           (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+            rcpt->orig_addr, rcpt->address,
             session ? session->namaddr : "none",
             request->arrival_time, "%s", vstring_str(why));
        if (status == 0) {
@@ -214,7 +214,8 @@ int     smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
        if (rcpt->offset == 0)
            continue;
        status = (SMTP_SOFT(code) ? defer_append : bounce_append)
-           (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+           (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+            rcpt->orig_addr, rcpt->address,
             session->namaddr, request->arrival_time,
             "%s", vstring_str(why));
        if (status == 0) {
@@ -248,7 +249,8 @@ void    smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
      */
     va_start(ap, format);
     status = (SMTP_SOFT(code) ? vdefer_append : vbounce_append)
-       (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+       (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+        rcpt->orig_addr, rcpt->address,
         session->namaddr, request->arrival_time, format, ap);
     va_end(ap);
     if (status == 0) {
@@ -293,7 +295,8 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
        rcpt = request->rcpt_list.info + nrcpt;
        if (rcpt->offset == 0)
            continue;
-       state->status |= defer_append(KEEP, request->queue_id,
+       state->status |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
+                                     request->queue_id,
                                      rcpt->orig_addr, rcpt->address,
                                      session->namaddr,
                                      request->arrival_time,
index 2f923e29a0317dfad0c88b124a74b4dfa2c9dbb4..7550d3d73df2d43f441820f59830b7f7b2c40fbc 100644 (file)
@@ -221,6 +221,9 @@ smtpd_check.o: ../../include/rec_type.h
 smtpd_check.o: ../../include/mail_proto.h
 smtpd_check.o: ../../include/iostuff.h
 smtpd_check.o: ../../include/attr.h
+smtpd_check.o: ../../include/verify_clnt.h
+smtpd_check.o: ../../include/deliver_request.h
+smtpd_check.o: ../../include/recipient_list.h
 smtpd_check.o: smtpd.h
 smtpd_check.o: ../../include/mail_stream.h
 smtpd_check.o: smtpd_sasl_glue.h
index 3d4d294dbc52425918d8076199e1cce68549890a..7db37ba26494dbc78d8092332820399e2fad964e 100644 (file)
 /*     restriction.
 /* .IP \fBmaps_rbl_reject_code\fR
 /*     Response code when a request is RBL blacklisted.
+/* .IP \fBmulti_recipient_bounce_reject_code\fR
+/*     Response code when a multi-recipient bounce is blocked.
 /* .IP \fBrbl_reply_maps\fR
 /*     Table with template responses for RBL blacklisted requests, indexed by
 /*     RBL domain name. These templates are used by the \fBreject_rbl_*\fR
 /* .IP \fBunknown_hostname_reject_code\fR
 /*     Response code when a client violates the \fBreject_unknown_hostname\fR
 /*     restriction.
+/* .IP \fBunverified_sender_reject_code\fR
+/*     Response code when a sender address is known to be undeliverable.
+/* .IP \fBunverified_recipient_reject_code\fR
+/*     Response code when a recipient address is known to be undeliverable.
 /* SEE ALSO
 /*     trivial-rewrite(8) address resolver
 /*     cleanup(8) message canonicalization
@@ -431,7 +437,11 @@ char   *var_smtpd_null_key;
 int     var_smtpd_hist_thrsh;
 char   *var_smtpd_exp_filter;
 char   *var_def_rbl_reply;
+int     var_unv_from_code;
+int     var_unv_rcpt_code;
+int     var_mul_rcpt_code;
 char   *var_relay_rcpt_maps;
+char   *var_verify_sender;
 int     var_local_rcpt_code;
 int     var_virt_alias_code;
 int     var_virt_mailbox_code;
@@ -1644,6 +1654,9 @@ int     main(int argc, char **argv)
        VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0,
        VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0,
        VAR_SMTPD_HIST_THRSH, DEF_SMTPD_HIST_THRSH, &var_smtpd_hist_thrsh, 1, 0,
+       VAR_UNV_FROM_CODE, DEF_UNV_FROM_CODE, &var_unv_from_code, 0, 0,
+       VAR_UNV_RCPT_CODE, DEF_UNV_RCPT_CODE, &var_unv_rcpt_code, 0, 0,
+       VAR_MUL_RCPT_CODE, DEF_MUL_RCPT_CODE, &var_mul_rcpt_code, 0, 0,
        VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code, 0, 0,
        VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code, 0, 0,
        VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code, 0, 0,
@@ -1694,6 +1707,7 @@ int     main(int argc, char **argv)
        VAR_SMTPD_NOOP_CMDS, DEF_SMTPD_NOOP_CMDS, &var_smtpd_noop_cmds, 0, 0,
        VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key, 0, 0,
        VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
+       VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
        VAR_VERP_CLIENTS, DEF_VERP_CLIENTS, &var_verp_clients, 0, 0,
        0,
     };
index 692a52c6ebee7db9b1666ac5392fded8d967b24e..1769336691598ed26a002cbf29a730ce2378feab 100644 (file)
@@ -215,12 +215,14 @@ void    smtpd_chat_notify(SMTPD_STATE *state)
      * generate from untrusted data.
      */
 #define NULL_CLEANUP_FLAGS     0
+#define NULL_TRACE_FLAGS       0
 #define LENGTH 78
 #define INDENT 4
 
     notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
                                    var_error_rcpt,
-                                   NULL_CLEANUP_FLAGS);
+                                   NULL_CLEANUP_FLAGS,
+                                   NULL_TRACE_FLAGS);
     if (notice == 0) {
        msg_warn("postmaster notify: %m");
        return;
index 450c3208e1ec312dccb7f8c6d89c84ae07ef2f4d..7e3e5ca8e8826ad5194674e703d3e4c8a2d62bdd 100644 (file)
@@ -93,6 +93,8 @@
 /* .IP "check_recipient_maps"
 /*     Reject recipients not listed as valid local, virtual or relay
 /*     recipients.
+/* .IP reject_multi_recipient_bounce
+/*     Reject mail from <> with multiple envelope recipients.
 /* .IP reject_rbl_client rbl.domain.tld
 /*     Look up the reversed client network address in the specified
 /*     real-time blackhole DNS zone.  The \fIrbl_reply_maps\fR configuration
 /*     DNS A or MX record.
 /*     The \fIunknown_address_reject_code\fR configuration parameter
 /*     specifies the reject status code (default: 450).
+/* .IP reject_unverified_sender
+/*     Reject the request when mail to the sender address is known to
+/*     bounce, or when the sender's address destination is not reachable.
+/*     Address verification information is managed by the verify(8) daemon.
+/* .IP reject_unverified_recipient
+/*     Reject the request when mail to the recipient address is known to
+/*     bounce, or when the recipient's address destination is not reachable.
+/*     Address verification information is managed by the verify(8) daemon.
 /* .IP reject_unknown_recipient_domain
 /*     Reject the request when the resolved recipient address has no
 /*     DNS A or MX record.
 #include <record.h>
 #include <rec_type.h>
 #include <mail_proto.h>
+#include <verify_clnt.h>
 
 /* Application-specific. */
 
@@ -463,6 +474,12 @@ static void PRINTFLIKE(3, 4) defer_if(SMTPD_DEFER *, int, const char *,...);
     else \
        (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2)); \
     } while (0)
+#define DEFER_IF_PERMIT3(state, class, fmt, a1, a2, a3) do { \
+    if ((state)->warn_if_reject == 0) \
+       defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3)); \
+    else \
+       (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2), (a3)); \
+    } while (0)
 
  /*
   * Cached RBL lookup state.
@@ -1625,6 +1642,67 @@ static int reject_unknown_address(SMTPD_STATE *state, const char *addr,
     return (reject_unknown_mailhost(state, domain, reply_name, reply_class));
 }
 
+/* reject_unverified_address - fail if address bounces */
+
+static int reject_unverified_address(SMTPD_STATE *state, const char *addr,
+                           const char *reply_name, const char *reply_class,
+                                            int unv_addr_code)
+{
+    char   *myname = "reject_unverified_address";
+    VSTRING *why = vstring_alloc(10);
+    int     rqst_status;
+    int     rcpt_status;
+    int     verify_status;
+    int     count;
+
+    if (msg_verbose)
+       msg_info("%s: %s", myname, addr);
+
+    /*
+     * Verify the address. Don't waste too much of their or our time.
+     */
+    for (count = 0; count < 3; count++) {
+       verify_status = verify_clnt_query(addr, &rcpt_status, why);
+       if (verify_status != VRFY_STAT_OK || rcpt_status != DEL_RCPT_STAT_TODO)
+           break;
+       sleep(3);
+    }
+    if (verify_status != VRFY_STAT_OK) {
+       msg_warn("%s service failure", var_verify_service);
+       DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
+                     "450 <%s>: %s rejected: address verification problem",
+                        reply_name, reply_class);
+       rqst_status = SMTPD_CHECK_DUNNO;
+    } else {
+       switch (rcpt_status) {
+       default:
+           msg_warn("unknown address verification status %d", rcpt_status);
+           rqst_status = SMTPD_CHECK_DUNNO;
+           break;
+       case DEL_RCPT_STAT_TODO:
+       case DEL_RCPT_STAT_DEFER:
+           DEFER_IF_PERMIT3(state, MAIL_ERROR_POLICY,
+                            "450 <%s>: %s rejected: unverified address: %s",
+                            reply_name, reply_class, STR(why));
+           rqst_status = SMTPD_CHECK_DUNNO;
+           break;
+       case DEL_RCPT_STAT_OK:
+           rqst_status = SMTPD_CHECK_DUNNO;
+           break;
+       case DEL_RCPT_STAT_BOUNCE:
+           if (unv_addr_code / 100 == 2)
+               rqst_status = SMTPD_CHECK_DUNNO;
+           else
+               rqst_status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+                         "%d <%s>: %s rejected: undeliverable address: %s",
+                         unv_addr_code, reply_name, reply_class, STR(why));
+           break;
+       }
+    }
+    vstring_free(why);
+    return (rqst_status);
+}
+
 /* check_table_result - translate table lookup result into pass/reject */
 
 static int check_table_result(SMTPD_STATE *state, const char *table,
@@ -2709,6 +2787,11 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
            if (state->sender && *state->sender)
                status = reject_unknown_address(state, state->sender,
                                          state->sender, SMTPD_NAME_SENDER);
+       } else if (strcasecmp(name, REJECT_UNVERIFIED_SENDER) == 0) {
+           if (state->sender && *state->sender)
+               status = reject_unverified_address(state, state->sender,
+                                          state->sender, SMTPD_NAME_SENDER,
+                                                  var_unv_from_code);
        } else if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
            if (state->sender && *state->sender)
                status = reject_non_fqdn_address(state, state->sender,
@@ -2780,6 +2863,17 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
        } else if (strcasecmp(name, CHECK_RCPT_MAPS) == 0) {
            if (state->recipient && *state->recipient)
                status = check_rcpt_maps(state, state->recipient);
+       } else if (strcasecmp(name, REJECT_MUL_RCPT_BOUNCE) == 0) {
+           if (state->sender && *state->sender == 0 && state->rcpt_count
+               > (strcmp(state->where, "DATA") ? 0 : 1))
+               status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+                            "%d <%s>: %s rejected: Multi-recipient bounce",
+                               var_mul_rcpt_code, reply_name, reply_class);
+       } else if (strcasecmp(name, REJECT_UNVERIFIED_RECIP) == 0) {
+           if (state->recipient && *state->recipient)
+               status = reject_unverified_address(state, state->recipient,
+                                    state->recipient, SMTPD_NAME_RECIPIENT,
+                                                  var_unv_rcpt_code);
        }
 
        /*
@@ -2970,6 +3064,7 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
     int     status;
     char   *saved_recipient;
     char   *err;
+    static VSTRING *canon_verify_sender;
 
     /*
      * Initialize.
@@ -2984,6 +3079,22 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
     if (strcasecmp(recipient, "postmaster") == 0)
        return (0);
 
+    /*
+     * XXX Always say OK when we're probed with our own address verification
+     * sender address. Otherwise, some timeout or some UCE block may result
+     * in mutual negative caching, making it painful to get the mail through.
+     */
+#ifndef TEST
+    if (*recipient) {
+       if (canon_verify_sender == 0) {
+           canon_verify_sender = vstring_alloc(10);
+           canon_addr_internal(canon_verify_sender, var_verify_sender);
+       }
+       if (strcasecmp(STR(canon_verify_sender), recipient) == 0)
+           return (0);
+    }
+#endif
+
     /*
      * Minor kluge so that we can delegate work to the generic routine and so
      * that we can syslog the recipient with the reject messages.
@@ -3026,7 +3137,7 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
     SMTPD_CHECK_RESET();
     status = setjmp(smtpd_check_buf);
     if (status == 0 && rcpt_restrctions->argc)
-           status = generic_checks(state, rcpt_restrctions,
+       status = generic_checks(state, rcpt_restrctions,
                          recipient, SMTPD_NAME_RECIPIENT, CHECK_RECIP_ACL);
 
     /*
@@ -3382,6 +3493,7 @@ char   *var_rbl_reply_maps;
 char   *var_smtpd_exp_filter;
 char   *var_def_rbl_reply;
 char   *var_relay_rcpt_maps;
+char   *var_verify_sender;
 
 typedef struct {
     char   *name;
@@ -3389,12 +3501,12 @@ typedef struct {
     char  **target;
 } STRING_TABLE;
 
-#undef DEF_LOCAL_RCPT_MAPS
-#define DEF_LOCAL_RCPT_MAPS            ""
-
 #undef DEF_VIRT_ALIAS_MAPS
 #define DEF_VIRT_ALIAS_MAPS    ""
 
+#undef DEF_LOCAL_RCPT_MAPS
+#define DEF_LOCAL_RCPT_MAPS    ""
+
 static STRING_TABLE string_table[] = {
     VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains,
     VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin,
@@ -3420,6 +3532,7 @@ static STRING_TABLE string_table[] = {
     VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter,
     VAR_DEF_RBL_REPLY, DEF_DEF_RBL_REPLY, &var_def_rbl_reply,
     VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps,
+    VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender,
     0,
 };
 
@@ -3471,6 +3584,9 @@ int     var_defer_code;
 int     var_non_fqdn_code;
 int     var_smtpd_delay_reject;
 int     var_allow_untrust_route;
+int     var_mul_rcpt_code;
+int     var_unv_from_code;
+int     var_unv_rcpt_code;
 int     var_local_rcpt_code;
 int     var_relay_rcpt_code;
 int     var_virt_mailbox_code;
@@ -3490,6 +3606,9 @@ static INT_TABLE int_table[] = {
     VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code,
     VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject,
     VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route,
+    VAR_MUL_RCPT_CODE, DEF_MUL_RCPT_CODE, &var_mul_rcpt_code,
+    VAR_UNV_FROM_CODE, DEF_UNV_FROM_CODE, &var_unv_from_code,
+    VAR_UNV_RCPT_CODE, DEF_UNV_RCPT_CODE, &var_unv_rcpt_code,
     VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code,
     VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code,
     VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code,
index 7a579df886b37a1dccbd009eb39d5a1e27dba881..0be7fb623576e94c8684876803963dbdb92b4fb7 100644 (file)
@@ -537,8 +537,10 @@ void    resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
      * Subtle note: reset nexthop even when the transport table does not change
      * the transport. Otherwise it is hard to get rid of main.cf specified
      * nexthop information.
+     * 
+     * XXX Don't override the virtual alias class (error:User unknown) result.
      */
-    if (*var_transport_maps) {
+    if (*var_transport_maps && !(*flags & RESOLVE_CLASS_ALIAS)) {
        if (transport_lookup(STR(nextrcpt), rcpt_domain, channel, nexthop) == 0
            && dict_errno != 0) {
            msg_warn("%s lookup failure", VAR_TRANSPORT_MAPS);
index fa608025835cf1fc2c6500e09688f4928b365764..504a777d07c25c29da1b1e7d4c5de367ca5a37ab 100644 (file)
@@ -76,6 +76,7 @@ static MAPS *transport_path;
 static int transport_match_parent_style;
 static VSTRING *wildcard_channel;
 static VSTRING *wildcard_nexthop;
+static int transport_errno;
 
 #define STR(x) vstring_str(x)
 
@@ -195,8 +196,7 @@ void    transport_wildcard_init(void)
            msg_info("wildcard_{chan:hop}={%s:%s}",
              vstring_str(wildcard_channel), vstring_str(wildcard_nexthop));
     } else {
-       if (dict_errno != 0)
-           msg_fatal("transport table initialization problem.");
+       transport_errno = dict_errno;
        vstring_free(channel);
        vstring_free(nexthop);
     }
@@ -294,7 +294,10 @@ int     transport_lookup(const char *addr, const char *rcpt_domain,
     /*
      * Fall back to the wild-card entry.
      */
-    if (wildcard_channel) {
+    if (transport_errno) {
+       dict_errno = transport_errno;
+       RETURN_FREE(NOTFOUND);
+    } else if (wildcard_channel) {
        update_entry(STR(wildcard_channel), STR(wildcard_nexthop),
                     rcpt_domain, channel, nexthop);
        RETURN_FREE(FOUND);
diff --git a/postfix/src/verify/.indent.pro b/postfix/src/verify/.indent.pro
new file mode 120000 (symlink)
index 0000000..5c837ec
--- /dev/null
@@ -0,0 +1 @@
+../../.indent.pro
\ No newline at end of file
diff --git a/postfix/src/verify/Makefile.in b/postfix/src/verify/Makefile.in
new file mode 100644 (file)
index 0000000..169affb
--- /dev/null
@@ -0,0 +1,80 @@
+SHELL  = /bin/sh
+SRCS   = verify.c
+OBJS   = verify.o
+HDRS   = 
+TESTSRC        =
+WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
+       -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
+       -Wunused
+DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+TESTPROG= 
+PROG   = verify
+INC_DIR = ../../include
+LIBS   = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
+
+.c.o:; $(CC) $(CFLAGS) -c $*.c
+
+$(PROG): $(OBJS) $(LIBS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
+
+Makefile: Makefile.in
+       (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+
+test:  $(TESTPROG)
+
+tests: test
+
+update: ../../libexec/$(PROG)
+
+../../libexec/$(PROG): $(PROG)
+       cp $(PROG) ../../libexec
+
+printfck: $(OBJS) $(PROG)
+       rm -rf printfck
+       mkdir printfck
+       sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
+       set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
+       cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
+
+lint:
+       lint $(DEFS) $(SRCS) $(LINTFIX)
+
+clean:
+       rm -f *.o *core $(PROG) $(TESTPROG) junk 
+       rm -rf printfck
+
+tidy:  clean
+
+depend: $(MAKES)
+       (sed '1,/^# do not edit/!d' Makefile.in; \
+       set -e; for i in [a-z][a-z0-9]*.c; do \
+           $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+           -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
+       done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+       @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+verify.o: verify.c
+verify.o: ../../include/sys_defs.h
+verify.o: ../../include/msg.h
+verify.o: ../../include/mymalloc.h
+verify.o: ../../include/htable.h
+verify.o: ../../include/dict_ht.h
+verify.o: ../../include/dict.h
+verify.o: ../../include/vstream.h
+verify.o: ../../include/vbuf.h
+verify.o: ../../include/argv.h
+verify.o: ../../include/split_at.h
+verify.o: ../../include/mail_conf.h
+verify.o: ../../include/mail_params.h
+verify.o: ../../include/mail_proto.h
+verify.o: ../../include/iostuff.h
+verify.o: ../../include/attr.h
+verify.o: ../../include/post_mail.h
+verify.o: ../../include/cleanup_user.h
+verify.o: ../../include/verify_clnt.h
+verify.o: ../../include/deliver_request.h
+verify.o: ../../include/vstring.h
+verify.o: ../../include/recipient_list.h
+verify.o: ../../include/mail_server.h
diff --git a/postfix/src/verify/verify.c b/postfix/src/verify/verify.c
new file mode 100644 (file)
index 0000000..cc8e595
--- /dev/null
@@ -0,0 +1,517 @@
+/*++
+/* NAME
+/*     verify 8
+/* SUMMARY
+/*     Postfix address verification server
+/* SYNOPSIS
+/*     \fBverify\fR [generic Postfix daemon options]
+/* DESCRIPTION
+/*     The Postfix address verification server maintains a record
+/*     of what recipient addresses are known to be deliverable or
+/*     undeliverable.
+/*
+/*     Addresses are verified by submitting probe messages to the
+/*     Postfix queue. Probe messages are run through all the routing
+/*     and rewriting machinery except for final delivery, and are
+/*     discarded rather than being deferred or bounced.
+/*
+/*     Address verification relies on the answer from the nearest
+/*     MTA for the specified address, and will therefore not detect
+/*     all undeliverable addresses.
+/*
+/*     This server is designed to run under control by the Postfix
+/*     master server. It maintains an optional persistent database.
+/*     To avoid being interrupted by "postfix stop" in the middle
+/*     of a database update, the process runs in a separate process
+/*     group.
+/*
+/*     This server implements the following requests:
+/* .IP "\fBVRFY_ADDR_UPDATE\fI address status text\fR"
+/*     Update the status of the specified address.
+/* .IP "\fBVRFY_ADDR_QUERY\fI address\fR"
+/*     Look up the \fIstatus\fR and \fItext\fR of the specified address.
+/*     If the status is unknown, a probe is sent and a default status is
+/*     returned.
+/* .PP
+/*     The server reply status is one of:
+/* .IP \fBVRFYSTAT_OK\fR
+/*     The request completed normally.
+/* .IP \fBVRFYSTAT_BAD\fR
+/*     The server rejected the request (bad request name, bad
+/*     request parameter value).
+/* .IP \fBVRFYSTAT_FAIL\fR
+/*     The request failed.
+/* .PP
+/*     The recipient status is one of:
+/* .IP \fBDEL_RCPT_STAT_OK\fR
+/*     The address is deliverable.
+/* .IP \fBDEL_RCPT_STAT_DEFER\fR
+/*     The address is undeliverable due to a temporary problem.
+/* .IP \fBDEL_RCPT_STAT_BOUNCE\fR
+/*     The address is undeliverable due to a permanent problem.
+/* .IP \fBDEL_RCPT_STAT_TODO\fR
+/*     The address status is being determined.
+/* SECURITY
+/* .ad
+/* .fi
+/*     The address verification server is not security-sensitive. It does
+/*     not talk to the network, and it does not talk to local users.
+/*     The verify server can run chrooted at fixed low privilege.
+/*
+/*     The address verification server can be coerced to store
+/*     unlimited amounts of garbage. Limiting the cache size
+/*     trades one problem (disk space exhaustion) for another
+/*     one (poor response time to client requests).
+/* DIAGNOSTICS
+/*     Problems and transactions are logged to \fBsyslogd\fR(8).
+/* BUGS
+/*     This prototype server uses synchronous submission for sending
+/*     a probe message, which can be slow on a busy machine.
+/*
+/*     If the persistent database ever gets corrupted then the world
+/*     comes to an end and human intervention is needed. This violates
+/*     a basic Postfix principle.
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/*     See the Postfix \fBmain.cf\fR file for syntax details and for
+/*     default values. Use the \fBpostfix reload\fR command after a
+/*     configuration change.
+/* .IP \fBaddress_verify_map\fR
+/*     Optional table for persistent recipient status storage. The file
+/*     is opened before the process enters a chroot jail and before
+/*     it drops root privileges.
+/*     By default, the information is kept in volatile memory,
+/*     and is lost after \fBpostfix reload\fR or \fBpostfix stop\fR.
+/* .sp
+/*     To recover from a corrupted address verification database,
+/*     delete the file and do \fBpostfix reload\fR.
+/* .IP \fBaddress_verify_sender\fR
+/*     The sender address to use for probe messages. Specify an empty
+/*     value (\fBaddress_verify_sender =\fR) or \fB<>\fR if you want
+/*     to use the null sender address.
+/* .IP \fBaddress_verify_positive_expire_time\fR
+/*     The amount of time after which a known to be good address expires.
+/* .IP \fBaddress_verify_positive_refresh_time\fR
+/*     The minimal amount of time after which a proactive probe is sent to
+/*     verify that a known to be good address is still good. The address
+/*     status is not updated when the probe fails (optimistic caching).
+/* .IP \fBaddress_verify_negative_cache\fR
+/*     A boolean parameter that controls whether negative probe results
+/*     are stored in the address verification cache. When enabled, the
+/*     cache may pollute quickly with garbage. When disabled, Postfix
+/*     will generate an address probe for every lookup.
+/* .IP \fBaddress_verify_negative_expire_time\fR
+/*     The amount of time after which a rejected address expires.
+/* .IP \fBaddress_verify_negative_refresh_time\fR
+/*     The minimal amount of time after which a proactive probe is sent to
+/*     verify that a known to be bad address is still bad.
+/* SEE ALSO
+/*     verify_clnt(3) address verification client
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <htable.h>
+#include <dict_ht.h>
+#include <dict.h>
+#include <split_at.h>
+
+/* Global library. */
+
+#include <mail_conf.h>
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <post_mail.h>
+#include <verify_clnt.h>
+
+/* Single server skeleton. */
+
+#include <mail_server.h>
+
+/* Application-specific. */
+
+ /*
+  * Tunable parameters.
+  */
+char   *var_verify_map;
+int     var_verify_pos_exp;
+int     var_verify_pos_try;
+int     var_verify_neg_exp;
+int     var_verify_neg_try;
+char   *var_verify_sender;
+
+ /*
+  * State.
+  */
+static DICT *verify_map;
+
+ /*
+  * Silly little macros.
+  */
+#define STR(x)                 vstring_str(x)
+#define STREQ(x,y)             (strcmp(x,y) == 0)
+
+ /*
+  * The address verification database consists of (address, data) tuples. The
+  * format of the data field is "status:probed:updated:text". The meaning of
+  * each field is:
+  * 
+  * status: one of the four recipient status codes (OK, DEFER, BOUNCE or TODO).
+  * In the case of TODO, we have no information about the address, and the
+  * address is being probed.
+  * 
+  * probed: if non-zero, the time of the last outstanding address probe. If
+  * zero, there is no outstanding address probe.
+  * 
+  * updated: if non-zero, the time of the last processed address probe. If zero,
+  * we have no information about the address, and the address is being
+  * probed.
+  * 
+  * text: descriptive text from delivery agents etc.
+  */
+
+ /*
+  * Quick test to see status without parsing the whole entry.
+  */
+#define STATUS_FROM_RAW_ENTRY(e) atoi(e)
+
+/* verify_make_entry - construct table entry */
+
+static void verify_make_entry(VSTRING *buf, int status, long probed,
+                                     long updated, const char *text)
+{
+    vstring_sprintf(buf, "%d:%ld:%ld:%s", status, probed, updated, text);
+}
+
+/* verify_parse_entry - parse table entry */
+
+static int verify_parse_entry(char *buf, int *status, long *probed,
+                                     long *updated, char **text)
+{
+    char   *probed_text;
+    char   *updated_text;
+
+    if ((probed_text = split_at(buf, ':')) != 0
+       && (updated_text = split_at(probed_text, ':')) != 0
+       && (*text = split_at(updated_text, ':')) != 0) {
+       *probed = atol(probed_text);
+       *updated = atol(updated_text);
+       *status = atoi(buf);
+       if ((*status == DEL_RCPT_STAT_OK
+            || *status == DEL_RCPT_STAT_DEFER
+            || *status == DEL_RCPT_STAT_BOUNCE
+            || *status == DEL_RCPT_STAT_TODO)
+           && (probed || updated))
+           return (0);
+    }
+    msg_warn("bad address verify table entry: %.100s", buf);
+    return (-1);
+}
+
+/* verify_stat2name - status to name */
+
+static const char *verify_stat2name(int addr_status)
+{
+    if (addr_status == DEL_RCPT_STAT_OK)
+       return ("deliverable");
+    if (addr_status == DEL_RCPT_STAT_DEFER)
+       return ("undeliverable");
+    if (addr_status == DEL_RCPT_STAT_BOUNCE)
+       return ("undeliverable");
+    return (0);
+}
+
+/* verify_update_service - update address service */
+
+static void verify_update_service(VSTREAM *client_stream)
+{
+    VSTRING *buf = vstring_alloc(10);
+    VSTRING *addr = vstring_alloc(10);
+    int     addr_status;
+    VSTRING *text = vstring_alloc(10);
+    const char *status_name;
+    const char *raw_data;
+    long    probed;
+    long    updated;
+
+    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
+                 ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+                 ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, &addr_status,
+                 ATTR_TYPE_STR, MAIL_ATTR_WHY, text,
+                 ATTR_TYPE_END) == 3) {
+       if ((status_name = verify_stat2name(addr_status)) == 0) {
+           msg_warn("bad recipient status %d for recipient %s",
+                    addr_status, STR(addr));
+           attr_print(client_stream, ATTR_FLAG_NONE,
+                      ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_BAD,
+                      ATTR_TYPE_END);
+       } else {
+
+           /*
+            * Robustness: don't allow a failed probe to clobber an OK
+            * address before it expires. The failed probe is ignored so that
+            * the address will be re-probed upon the next query. As long as
+            * some probes succeed the address will remain cached as OK.
+            */
+           if (addr_status == DEL_RCPT_STAT_OK
+               || (raw_data = dict_get(verify_map, STR(addr))) == 0
+               || STATUS_FROM_RAW_ENTRY(raw_data) != DEL_RCPT_STAT_OK) {
+               probed = 0;
+               updated = (long) time((time_t *) 0);
+               verify_make_entry(buf, addr_status, probed, updated, STR(text));
+               if (msg_verbose)
+                   msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
+                       STR(addr), addr_status, probed, updated, STR(text));
+               dict_put(verify_map, STR(addr), STR(buf));
+           }
+           attr_print(client_stream, ATTR_FLAG_NONE,
+                      ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_OK,
+                      ATTR_TYPE_END);
+       }
+    }
+    vstring_free(buf);
+    vstring_free(addr);
+    vstring_free(text);
+}
+
+/* verify_query_service - query address status */
+
+static void verify_query_service(VSTREAM *client_stream)
+{
+    VSTRING *addr = vstring_alloc(10);
+    VSTRING *get_buf = 0;
+    VSTRING *put_buf = 0;
+    const char *raw_data;
+    int     addr_status;
+    long    probed;
+    long    updated;
+    char   *text;
+    VSTREAM *post;
+
+    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
+                 ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+                 ATTR_TYPE_END) == 1) {
+       long    now = (long) time((time_t *) 0);
+
+       /*
+        * Produce a default record when no usable record exists.
+        * 
+        * If negative caching is disabled, purge an expired record from the
+        * database.
+        * 
+        * XXX Assume that a probe is lost if no response is received in 1000
+        * seconds. If this number is too small the queue will slowly fill up
+        * with delayed probes.
+        * 
+        * XXX Maintain a moving average for the probe turnaround time, and
+        * allow probe "retransmission" when a probe is outstanding for, say
+        * some minimal amount of time (1000 sec) plus several times the
+        * observed probe turnaround time. This causes probing to back off
+        * when the mail system becomes congested.
+        */
+#define POSITIVE_ENTRY_EXPIRED(addr_status, updated) \
+    (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_exp < now)
+#define NEGATIVE_ENTRY_EXPIRED(addr_status, updated) \
+    (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_exp < now)
+#define PROBE_TTL      1000
+
+       if ((raw_data = dict_get(verify_map, STR(addr))) == 0   /* not found */
+           || ((get_buf = vstring_alloc(10)),
+               vstring_strcpy(get_buf, raw_data),      /* malformed */
+               verify_parse_entry(STR(get_buf), &addr_status, &probed,
+                                  &updated, &text) < 0)
+           || (now - probed > PROBE_TTL        /* safe to probe */
+               && (POSITIVE_ENTRY_EXPIRED(addr_status, updated)
+                   || NEGATIVE_ENTRY_EXPIRED(addr_status, updated)))) {
+           addr_status = DEL_RCPT_STAT_TODO;
+           probed = 0;
+           updated = 0;
+           text = "Address verification in progress";
+           if (raw_data != 0 && var_verify_neg_cache == 0)
+               dict_del(verify_map, STR(addr));
+       }
+       if (msg_verbose)
+           msg_info("GOT %s status=%d probed=%ld updated=%ld text=%s",
+                    STR(addr), addr_status, probed, updated, text);
+
+       /*
+        * Respond to the client.
+        */
+       attr_print(client_stream, ATTR_FLAG_NONE,
+                  ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_OK,
+                  ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+                  ATTR_TYPE_STR, MAIL_ATTR_WHY, text,
+                  ATTR_TYPE_END);
+
+       /*
+        * Send a new probe when the information needs to be refreshed.
+        * 
+        * XXX For an initial proof of concept implementation, use synchronous
+        * mail submission. This needs to be made async for high-volume
+        * sites, which makes it even more interesting to eliminate duplicate
+        * queries while a probe is being built.
+        * 
+        * If negative caching is turned off, update the database only when
+        * refreshing an existing entry.
+        */
+#define POSITIVE_REFRESH_NEEDED(addr_status, updated) \
+    (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_try < now)
+#define NEGATIVE_REFRESH_NEEDED(addr_status, updated) \
+    (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_try < now)
+#define NULL_CLEANUP_FLAGS     0
+
+       if (now - probed > PROBE_TTL
+           && (POSITIVE_REFRESH_NEEDED(addr_status, updated)
+               || NEGATIVE_REFRESH_NEEDED(addr_status, updated))) {
+           if (msg_verbose)
+               msg_info("PROBE %s status=%d probed=%ld updated=%ld",
+                        STR(addr), addr_status, now, updated);
+           if ((post = post_mail_fopen(strcmp(var_verify_sender, "<>") == 0 ?
+                                       "" : var_verify_sender, STR(addr),
+                                       NULL_CLEANUP_FLAGS,
+                                       DEL_REQ_FLAG_VERIFY)) != 0
+               && post_mail_fclose(post) == 0
+               && (updated != 0 || var_verify_neg_cache != 0)) {
+               put_buf = vstring_alloc(10);
+               verify_make_entry(put_buf, addr_status, now, updated, text);
+               if (msg_verbose)
+                   msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
+                            STR(addr), addr_status, now, updated, text);
+               dict_put(verify_map, STR(addr), STR(put_buf));
+           }
+       }
+    }
+    vstring_free(addr);
+    if (get_buf)
+       vstring_free(get_buf);
+    if (put_buf)
+       vstring_free(put_buf);
+}
+
+/* verify_service - perform service for client */
+
+static void verify_service(VSTREAM *client_stream, char *unused_service,
+                                  char **argv)
+{
+    VSTRING *request = vstring_alloc(10);
+
+    /*
+     * Sanity check. This service takes no command-line arguments.
+     */
+    if (argv[0])
+       msg_fatal("unexpected command-line argument: %s", argv[0]);
+
+    /*
+     * This routine runs whenever a client connects to the socket dedicated
+     * to the address verification service. All connection-management stuff
+     * is handled by the common code in multi_server.c.
+     */
+    if (attr_scan(client_stream,
+                 ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+                 ATTR_TYPE_STR, MAIL_ATTR_REQ, request,
+                 ATTR_TYPE_END) == 1) {
+       if (STREQ(STR(request), VRFY_REQ_UPDATE)) {
+           verify_update_service(client_stream);
+       } else if (STREQ(STR(request), VRFY_REQ_QUERY)) {
+           verify_query_service(client_stream);
+       } else {
+           msg_warn("unrecognized request: \"%s\", ignored", STR(request));
+           attr_print(client_stream, ATTR_FLAG_NONE,
+                      ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_BAD,
+                      ATTR_TYPE_END);
+       }
+    }
+    vstream_fflush(client_stream);
+    vstring_free(request);
+}
+
+/* post_jail_init - post-jail initialization */
+
+static void post_jail_init(char *unused_name, char **unused_argv)
+{
+
+    /*
+     * If the database is in volatile memory only, prevent automatic process
+     * suicide after a limited number of client requests or after a limited
+     * amount of idle time.
+     */
+    if (*var_verify_map == 0) {
+       var_use_limit = 0;
+       var_idle_limit = 0;
+    }
+}
+
+/* pre_jail_init - pre-jail initialization */
+
+static void pre_jail_init(char *unused_name, char **unused_argv)
+{
+    mode_t  saved_mask;
+
+    /*
+     * Keep state in persistent (external) or volatile (internal) map.
+     */
+#define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
+
+    if (*var_verify_map) {
+       saved_mask = umask(022);
+       verify_map = dict_open(var_verify_map,
+                              O_CREAT | O_RDWR,
+                              VERIFY_DICT_OPEN_FLAGS);
+       (void) umask(saved_mask);
+    } else {
+       verify_map = dict_ht_open("verify", htable_create(0), myfree);
+    }
+
+    /*
+     * Never, ever, get killed by a master signal, as that would corrupt the
+     * database when we're in the middle of an update.
+     */
+    setsid();
+}
+
+/* main - pass control to the single-threaded skeleton */
+
+int     main(int argc, char **argv)
+{
+    static CONFIG_STR_TABLE str_table[] = {
+       VAR_VERIFY_MAP, DEF_VERIFY_MAP, &var_verify_map, 0, 0,
+       VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
+       0,
+    };
+    static CONFIG_TIME_TABLE time_table[] = {
+       VAR_VERIFY_POS_EXP, DEF_VERIFY_POS_EXP, &var_verify_pos_exp, 1, 0,
+       VAR_VERIFY_POS_TRY, DEF_VERIFY_POS_TRY, &var_verify_pos_try, 1, 0,
+       VAR_VERIFY_NEG_EXP, DEF_VERIFY_NEG_EXP, &var_verify_neg_exp, 1, 0,
+       VAR_VERIFY_NEG_TRY, DEF_VERIFY_NEG_TRY, &var_verify_neg_try, 1, 0,
+       0,
+    };
+
+    multi_server_main(argc, argv, verify_service,
+                     MAIL_SERVER_STR_TABLE, str_table,
+                     MAIL_SERVER_TIME_TABLE, time_table,
+                     MAIL_SERVER_PRE_INIT, pre_jail_init,
+                     MAIL_SERVER_POST_INIT, post_jail_init,
+                     MAIL_SERVER_SOLITARY,
+                     0);
+}
index da2dc414be3ff2b4a0fe2c2420de73b54454d9bc..ecfc44fc0a888be285920fb046d301c8a7fbc405 100644 (file)
@@ -83,6 +83,8 @@ mailbox.o: ../../include/mbox_open.h
 mailbox.o: ../../include/safe_open.h
 mailbox.o: ../../include/defer.h
 mailbox.o: ../../include/bounce.h
+mailbox.o: ../../include/deliver_request.h
+mailbox.o: ../../include/recipient_list.h
 mailbox.o: ../../include/sent.h
 mailbox.o: ../../include/mail_params.h
 mailbox.o: ../../include/virtual8_maps.h
@@ -90,8 +92,6 @@ mailbox.o: ../../include/maps.h
 mailbox.o: ../../include/dict.h
 mailbox.o: ../../include/argv.h
 mailbox.o: virtual.h
-mailbox.o: ../../include/deliver_request.h
-mailbox.o: ../../include/recipient_list.h
 mailbox.o: ../../include/mbox_conf.h
 maildir.o: maildir.c
 maildir.o: ../../include/sys_defs.h
@@ -107,12 +107,12 @@ maildir.o: ../../include/get_hostname.h
 maildir.o: ../../include/sane_fsops.h
 maildir.o: ../../include/mail_copy.h
 maildir.o: ../../include/bounce.h
+maildir.o: ../../include/deliver_request.h
+maildir.o: ../../include/recipient_list.h
 maildir.o: ../../include/defer.h
 maildir.o: ../../include/sent.h
 maildir.o: ../../include/mail_params.h
 maildir.o: virtual.h
-maildir.o: ../../include/deliver_request.h
-maildir.o: ../../include/recipient_list.h
 maildir.o: ../../include/maps.h
 maildir.o: ../../include/dict.h
 maildir.o: ../../include/argv.h
@@ -125,10 +125,10 @@ recipient.o: ../../include/stringops.h
 recipient.o: ../../include/vstring.h
 recipient.o: ../../include/vbuf.h
 recipient.o: ../../include/bounce.h
-recipient.o: virtual.h
-recipient.o: ../../include/vstream.h
 recipient.o: ../../include/deliver_request.h
+recipient.o: ../../include/vstream.h
 recipient.o: ../../include/recipient_list.h
+recipient.o: virtual.h
 recipient.o: ../../include/maps.h
 recipient.o: ../../include/dict.h
 recipient.o: ../../include/argv.h
@@ -137,12 +137,12 @@ unknown.o: unknown.c
 unknown.o: ../../include/sys_defs.h
 unknown.o: ../../include/msg.h
 unknown.o: ../../include/bounce.h
-unknown.o: virtual.h
-unknown.o: ../../include/vstream.h
-unknown.o: ../../include/vbuf.h
-unknown.o: ../../include/vstring.h
 unknown.o: ../../include/deliver_request.h
+unknown.o: ../../include/vstring.h
+unknown.o: ../../include/vbuf.h
+unknown.o: ../../include/vstream.h
 unknown.o: ../../include/recipient_list.h
+unknown.o: virtual.h
 unknown.o: ../../include/maps.h
 unknown.o: ../../include/dict.h
 unknown.o: ../../include/argv.h
index 442dc3e7a5cc5ae2a963d3b914733f7d607e511d..87a8e691f6a27b0430b3409ae6d3c26f429607d3 100644 (file)
@@ -93,6 +93,13 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     if (msg_verbose)
        MSG_LOG_STATE(myname, state);
 
+    /*
+     * Don't deliver trace-only requests.
+     */
+    if (DEL_REQ_TRACE_ONLY(state.request->flags))
+       return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+                    "delivers to mailbox"));
+
     /*
      * Initialize. Assume the operation will fail. Set the delivered
      * attribute to reflect the final recipient.
@@ -136,10 +143,12 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     } else if (mail_copy_status != 0) {
        deliver_status = (errno == EDQUOT || errno == EFBIG ?
                          bounce_append : defer_append)
-           (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+           (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
             "mailbox %s: %s", usr_attr.mailbox, vstring_str(why));
     } else {
-       deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox");
+       deliver_status = sent(BOUNCE_FLAGS(state.request),
+                             SENT_ATTR(state.msg_attr),
+                             "delivered to mailbox");
     }
     vstring_free(why);
     return (deliver_status);
@@ -178,7 +187,8 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
        if (dict_errno == 0)
            return (NO);
 
-       *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       *statusp = defer_append(BOUNCE_FLAGS(state.request),
+                               BOUNCE_ATTR(state.msg_attr),
                                "%s: lookup %s: %m",
                          virtual_mailbox_maps->title, state.msg_attr.user);
        return (YES);
@@ -193,13 +203,15 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      */
     uid_res = virtual8_maps_find(virtual_uid_maps, state.msg_attr.user);
     if (uid_res == 0) {
-       *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       *statusp = defer_append(BOUNCE_FLAGS(state.request),
+                               BOUNCE_ATTR(state.msg_attr),
                                "recipient %s: uid not found in %s",
                              state.msg_attr.user, virtual_uid_maps->title);
        RETURN(YES);
     }
     if ((n = atol(uid_res)) < var_virt_minimum_uid) {
-       *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       *statusp = defer_append(BOUNCE_FLAGS(state.request),
+                               BOUNCE_ATTR(state.msg_attr),
                                "recipient %s: bad uid %s in %s",
                     state.msg_attr.user, uid_res, virtual_uid_maps->title);
        RETURN(YES);
@@ -211,13 +223,15 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      */
     gid_res = virtual8_maps_find(virtual_gid_maps, state.msg_attr.user);
     if (gid_res == 0) {
-       *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       *statusp = defer_append(BOUNCE_FLAGS(state.request),
+                               BOUNCE_ATTR(state.msg_attr),
                                "recipient %s: gid not found in %s",
                              state.msg_attr.user, virtual_gid_maps->title);
        RETURN(YES);
     }
     if ((n = atol(gid_res)) <= 0) {
-       *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+       *statusp = defer_append(BOUNCE_FLAGS(state.request),
+                               BOUNCE_ATTR(state.msg_attr),
                                "recipient %s: bad gid %s in %s",
                     state.msg_attr.user, gid_res, virtual_gid_maps->title);
        RETURN(YES);
index de2637160e0e1092bb9ae1a2d2b272c602465fa0..1ae9ce55e97d505854b680e579f5204d7111d623 100644 (file)
@@ -90,6 +90,13 @@ int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
     if (msg_verbose)
        MSG_LOG_STATE(myname, state);
 
+    /*
+     * Don't deliver trace-only requests.
+     */
+    if (DEL_REQ_TRACE_ONLY(state.request->flags))
+       return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+                    "delivers to maildir"));
+
     /*
      * Initialize. Assume the operation will fail. Set the delivered
      * attribute to reflect the final recipient.
@@ -160,11 +167,13 @@ int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
     } else if (mail_copy_status != 0) {
        deliver_status = (errno == EDQUOT || errno == EFBIG ?
                          bounce_append : defer_append)
-           (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+           (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
             "maildir delivery failed: %s", vstring_str(why));
 
     } else {
-       deliver_status = sent(SENT_ATTR(state.msg_attr), "maildir");
+       deliver_status = sent(BOUNCE_FLAGS(state.request),
+                             SENT_ATTR(state.msg_attr),
+                             "delivered to maildir");
     }
     vstring_free(buf);
     vstring_free(why);
index 8989046e0d18b4dc01792e548dc8749a39e1003a..b372c507b191a59e4938dfea8f53399d642445da 100644 (file)
@@ -58,7 +58,7 @@ int     deliver_unknown(LOCAL_STATE state)
     if (msg_verbose)
        MSG_LOG_STATE(myname, state);
 
-    return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+    return (bounce_append(BOUNCE_FLAGS(state.request),
+                         BOUNCE_ATTR(state.msg_attr),
                          "unknown user: \"%s\"", state.msg_attr.user));
-
 }
index 844441d5a9859c9af48037a664ed9b54e27442de..9145d58760f2edba31a4b4bf87c40583af18b615 100644 (file)
@@ -93,6 +93,8 @@ typedef struct LOCAL_STATE {
  /*
   * Bundle up some often-user attributes.
   */
+#define BOUNCE_FLAGS(request)  DEL_REQ_TRACE_FLAGS((request)->flags)
+
 #define BOUNCE_ATTR(attr)      attr.queue_id, attr.orig_rcpt, attr.recipient, \
                                        attr.relay, attr.arrival_time
 #define SENT_ATTR(attr)                attr.queue_id, attr.orig_rcpt, attr.recipient, \