From 8862f350363fd582f41a32990974409d20e1f13e Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sun, 22 Dec 2002 00:00:00 -0500 Subject: [PATCH] postfix-2.0.0-20021222 --- postfix/.indent.pro | 1 + postfix/HISTORY | 115 +- postfix/Makefile.in | 3 +- .../README_FILES/SENDER_VERIFICATION_README | 109 + postfix/RELEASE_NOTES | 1832 +---------------- postfix/RELEASE_NOTES-1.1 | 1087 ++++++++++ postfix/RELEASE_NOTES-2.0 | 819 ++++++++ postfix/conf/main.cf | 2 +- postfix/conf/master.cf | 2 + postfix/conf/post-install | 34 +- postfix/conf/postfix-files | 5 + postfix/conf/postfix-script | 2 +- postfix/conf/sample-smtpd.cf | 33 + postfix/conf/sample-verify.cf | 81 + postfix/html/Makefile.in | 11 +- postfix/html/backstage.html | 13 +- postfix/html/bounce.8.html | 50 +- postfix/html/postsuper.1.html | 4 +- postfix/html/sendmail.1.html | 52 +- postfix/html/smtp.8.html | 3 + postfix/html/smtpd.8.html | 26 +- postfix/html/trace.8.html | 1 + postfix/html/uce.html | 38 + postfix/html/verify.8.html | 152 ++ postfix/man/Makefile.in | 9 +- postfix/man/man1/postsuper.1 | 2 +- postfix/man/man1/sendmail.1 | 11 +- postfix/man/man8/bounce.8 | 5 +- postfix/man/man8/smtp.8 | 2 + postfix/man/man8/smtpd.8 | 6 + postfix/man/man8/trace.8 | 1 + postfix/man/man8/verify.8 | 139 ++ postfix/proto/Makefile.in | 16 +- postfix/src/bounce/Makefile.in | 40 +- postfix/src/bounce/bounce.c | 61 +- postfix/src/bounce/bounce_append_service.c | 44 +- postfix/src/bounce/bounce_notify_service.c | 42 +- postfix/src/bounce/bounce_notify_util.c | 77 +- postfix/src/bounce/bounce_notify_verp.c | 31 +- postfix/src/bounce/bounce_one_service.c | 21 +- postfix/src/bounce/bounce_service.h | 24 +- postfix/src/bounce/bounce_trace_service.c | 126 ++ postfix/src/bounce/bounce_warn_service.c | 225 ++ postfix/src/cleanup/Makefile.in | 2 + postfix/src/error/error.c | 4 +- postfix/src/global/Makefile.in | 95 +- postfix/src/global/bounce.c | 225 +- postfix/src/global/bounce.h | 14 +- postfix/src/global/bounce_log.c | 203 +- postfix/src/global/bounce_log.h | 15 +- postfix/src/global/defer.c | 118 +- postfix/src/global/defer.h | 1 + postfix/src/global/deliver_request.h | 38 +- postfix/src/global/log_adhoc.c | 127 ++ postfix/src/global/log_adhoc.h | 43 + postfix/src/global/mail_params.c | 12 + postfix/src/global/mail_params.h | 72 +- postfix/src/global/mail_proto.h | 5 + postfix/src/global/mail_queue.h | 1 + postfix/src/global/mail_version.h | 4 +- postfix/src/global/post_mail.c | 156 +- postfix/src/global/post_mail.h | 6 +- postfix/src/global/sent.c | 104 +- postfix/src/global/sent.h | 11 +- postfix/src/global/trace.c | 199 ++ postfix/src/global/trace.h | 51 + postfix/src/global/verify.c | 159 ++ postfix/src/global/verify.h | 48 + postfix/src/global/verify_clnt.c | 327 +++ postfix/src/global/verify_clnt.h | 55 + postfix/src/lmtp/lmtp_chat.c | 4 +- postfix/src/lmtp/lmtp_proto.c | 42 +- postfix/src/lmtp/lmtp_trouble.c | 13 +- postfix/src/local/Makefile.in | 64 +- postfix/src/local/alias.c | 25 +- postfix/src/local/command.c | 15 +- postfix/src/local/dotforward.c | 12 +- postfix/src/local/file.c | 16 +- postfix/src/local/forward.c | 13 +- postfix/src/local/include.c | 21 +- postfix/src/local/indirect.c | 14 +- postfix/src/local/local.c | 2 +- postfix/src/local/local.h | 4 +- postfix/src/local/mailbox.c | 13 +- postfix/src/local/maildir.c | 13 +- postfix/src/local/recipient.c | 9 +- postfix/src/local/resolve.c | 4 +- postfix/src/local/token.c | 6 +- postfix/src/local/unknown.c | 7 +- postfix/src/nqmgr/Makefile.in | 14 +- postfix/src/nqmgr/qmgr.h | 1 + postfix/src/nqmgr/qmgr_active.c | 13 + postfix/src/nqmgr/qmgr_deliver.c | 4 +- postfix/src/nqmgr/qmgr_message.c | 21 +- postfix/src/pickup/pickup.c | 9 +- postfix/src/pipe/pipe.c | 37 +- postfix/src/postsuper/postsuper.c | 6 +- postfix/src/qmgr/Makefile.in | 14 +- postfix/src/qmgr/qmgr.h | 1 + postfix/src/qmgr/qmgr_active.c | 13 + postfix/src/qmgr/qmgr_deliver.c | 4 +- postfix/src/qmgr/qmgr_message.c | 21 +- postfix/src/sendmail/Makefile.in | 2 + postfix/src/sendmail/sendmail.c | 107 +- postfix/src/smtp/smtp.c | 4 + postfix/src/smtp/smtp_chat.c | 6 +- postfix/src/smtp/smtp_proto.c | 48 +- postfix/src/smtp/smtp_trouble.c | 13 +- postfix/src/smtpd/Makefile.in | 3 + postfix/src/smtpd/smtpd.c | 14 + postfix/src/smtpd/smtpd_chat.c | 4 +- postfix/src/smtpd/smtpd_check.c | 127 +- postfix/src/trivial-rewrite/resolve.c | 4 +- postfix/src/trivial-rewrite/transport.c | 9 +- postfix/src/verify/.indent.pro | 1 + postfix/src/verify/Makefile.in | 80 + postfix/src/verify/verify.c | 517 +++++ postfix/src/virtual/Makefile.in | 20 +- postfix/src/virtual/mailbox.c | 28 +- postfix/src/virtual/maildir.c | 13 +- postfix/src/virtual/unknown.c | 4 +- postfix/src/virtual/virtual.h | 2 + 122 files changed, 6528 insertions(+), 2385 deletions(-) create mode 100644 postfix/README_FILES/SENDER_VERIFICATION_README create mode 100644 postfix/RELEASE_NOTES-1.1 create mode 100644 postfix/RELEASE_NOTES-2.0 create mode 100644 postfix/conf/sample-verify.cf create mode 120000 postfix/html/trace.8.html create mode 100644 postfix/html/verify.8.html create mode 100644 postfix/man/man8/trace.8 create mode 100644 postfix/man/man8/verify.8 create mode 100644 postfix/src/bounce/bounce_trace_service.c create mode 100644 postfix/src/bounce/bounce_warn_service.c create mode 100644 postfix/src/global/log_adhoc.c create mode 100644 postfix/src/global/log_adhoc.h create mode 100644 postfix/src/global/trace.c create mode 100644 postfix/src/global/trace.h create mode 100644 postfix/src/global/verify.c create mode 100644 postfix/src/global/verify.h create mode 100644 postfix/src/global/verify_clnt.c create mode 100644 postfix/src/global/verify_clnt.h create mode 120000 postfix/src/verify/.indent.pro create mode 100644 postfix/src/verify/Makefile.in create mode 100644 postfix/src/verify/verify.c diff --git a/postfix/.indent.pro b/postfix/.indent.pro index e66ba4755..16ca497d1 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -108,6 +108,7 @@ -TPIPE_ATTR -TPIPE_PARAMS -TPLMYSQL +-TPOST_MAIL_STATE -TQMGR_ENTRY -TQMGR_JOB -TQMGR_MESSAGE diff --git a/postfix/HISTORY b/postfix/HISTORY index ab10336ee..900f0a54f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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, diff --git a/postfix/Makefile.in b/postfix/Makefile.in index 7395b3a25..882c8206f 100644 --- a/postfix/Makefile.in +++ b/postfix/Makefile.in @@ -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 index 000000000..c1454f777 --- /dev/null +++ b/postfix/README_FILES/SENDER_VERIFICATION_README @@ -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. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index e9f8e9f93..5ab2ba5e2 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -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 . Earlier Postfix versions -broke long lines by inserting 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 . 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 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 index 000000000..c6f4611d5 --- /dev/null +++ b/postfix/RELEASE_NOTES-1.1 @@ -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 . 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 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 index 000000000..3c95d2bf6 --- /dev/null +++ b/postfix/RELEASE_NOTES-2.0 @@ -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 . Earlier +Postfix versions broke long lines by inserting 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. diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index b2c9bfc70..c5ebc9987 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -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. diff --git a/postfix/conf/master.cf b/postfix/conf/master.cf index 82983792d..1955bd4d0 100644 --- a/postfix/conf/master.cf +++ b/postfix/conf/master.cf @@ -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 diff --git a/postfix/conf/post-install b/postfix/conf/post-install index 88fae3a76..9b176f7f8 100644 --- a/postfix/conf/post-install +++ b/postfix/conf/post-install @@ -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 </dev/null || { + echo Editing $config_directory/master.cf, adding missing entry for verify service + cat >>$config_directory/master.cf </dev/null && { + echo Editing $config_directory/master.cf, setting verify process limit to 1 + ed $config_directory/master.cf < 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 index 000000000..75094bf06 --- /dev/null +++ b/postfix/conf/sample-verify.cf @@ -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 diff --git a/postfix/html/Makefile.in b/postfix/html/Makefile.in index ca3515cb2..4ed7cb70b 100644 --- a/postfix/html/Makefile.in +++ b/postfix/html/Makefile.in @@ -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 >$@ diff --git a/postfix/html/backstage.html b/postfix/html/backstage.html index 5ee7aeef8..99ab2a1bd 100644 --- a/postfix/html/backstage.html +++ b/postfix/html/backstage.html @@ -40,9 +40,9 @@ limits as specified in the master.cf configuration file.

-

  • The bounce or defer daemon is called -upon left and right by other daemon processes, in order to maintain -per-message log files with non-delivery status information. +
  • The bounce, defer, or trace daemon +is called upon left and right by other daemon processes, in order +to maintain per-message log files with delivery status information.

    @@ -66,6 +66,13 @@ destinations.

    +

  • The verify daemon maintains the +address verification cache that is used by the +\fBreject_unverified_sender\fR and \fBreject_unverified_recipient\fR +UCE restrictions. + +

    +

  • The spawn 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, diff --git a/postfix/html/bounce.8.html b/postfix/html/bounce.8.html index 548369f71..8ff624661 100644 --- a/postfix/html/bounce.8.html +++ b/postfix/html/bounce.8.html @@ -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 master.cf file (either bounce or defer). This program - expects to be run from the master(8) process manager. + the master.cf file (either bounce, defer or trace). This + program expects to be run from the master(8) process man- + ager. The bounce daemon processes two types of service requests: - o Append a recipient status record to a per-message + o Append a recipient status record to a per-message log file. - o Post a bounce message, with a copy of a log file - and of the corresponding message. When the bounce + o 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. STANDARDS @@ -43,36 +44,41 @@ BOUNCE(8) BOUNCE(8) Problems and transactions are logged to syslogd(8). BUGS - 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. CONFIGURATION PARAMETERS - The following main.cf parameters are especially relevant - to this program. See the Postfix main.cf file for syntax - details and for default values. Use the postfix reload + The following main.cf parameters are especially relevant + to this program. See the Postfix main.cf file for syntax + details and for default values. Use the postfix reload command after a configuration change. bounce_notice_recipient - The recipient of single bounce postmaster notices. + The recipient of single bounce postmaster notices. 2bounce_notice_recipient - The recipient of double bounce postmaster notices. + The recipient of double bounce postmaster notices. delay_notice_recipient The recipient of "delayed mail" postmaster notices. bounce_size_limit - Limit the amount of original message context that + Limit the amount of original message context that is sent in a non-delivery notification. + backwards_bounce_logfile_compatibility + Controls whether the logfile will be readable by + old Postfix versions that used the ad-hoc logfile + format of &lt;address&gt;: text. + mail_name - 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. notify_classes - Notify the postmaster of bounced mail when this - parameter includes the bounce class. For privacy + Notify the postmaster of bounced mail when this + parameter includes the bounce class. For privacy reasons, the message body is not included. SEE ALSO @@ -81,7 +87,7 @@ BOUNCE(8) BOUNCE(8) syslogd(8) system logging LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/postsuper.1.html b/postfix/html/postsuper.1.html index 2eb68f224..ed012cfb1 100644 --- a/postfix/html/postsuper.1.html +++ b/postfix/html/postsuper.1.html @@ -15,8 +15,8 @@ POSTSUPER(1) POSTSUPER(1) By default, postsuper performs the operations requested with the -s and -p command-line options on all Postfix queue directories - this includes the incoming, active and - deferred directories with mail files and the bounce, defer - and flush directories with log files. + deferred directories with mail files and the bounce, + defer, trace and flush directories with log files. Options: diff --git a/postfix/html/sendmail.1.html b/postfix/html/sendmail.1.html index b96c79529..788233b26 100644 --- a/postfix/html/sendmail.1.html +++ b/postfix/html/sendmail.1.html @@ -138,17 +138,22 @@ SENDMAIL(1) SENDMAIL(1) This mode of operation is implemented by running the smtpd(8) daemon. + -bv 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. + -f sender Set the envelope sender address. This is the address where delivery problems are sent to, unless - the message contains an Errors-To: message header. + the message contains an Errors-To: message header. -h hop_count (ignored) - Hop count limit. Use the hopcount_limit configura- + Hop count limit. Use the hopcount_limit configura- tion parameter instead. - -i When reading a message from standard input, don't - treat a line with only a . character as the end of + -i When reading a message from standard input, don't + treat a line with only a . character as the end of input. -m (ignored) @@ -158,61 +163,60 @@ SENDMAIL(1) SENDMAIL(1) Backwards compatibility. -oAalias_database - Non-default alias database. Specify pathname or + Non-default alias database. Specify pathname or type:pathname. See postalias(1) for details. -o7 (ignored) -o8 (ignored) To send 8-bit or binary content, use an appropriate - MIME encapsulation and specify the appropriate -B + MIME encapsulation and specify the appropriate -B command-line option. - -oi When reading a message from standard input, don't - treat a line with only a . character as the end of + -oi When reading a message from standard input, don't + treat a line with only a . character as the end of input. -om (ignored) - The sender is never eliminated from alias etc. + The sender is never eliminated from alias etc. expansions. -o x value (ignored) - Set option x to value. Use the equivalent configu- + Set option x to value. Use the equivalent configu- ration parameter in main.cf instead. -r sender Set the envelope sender address. This is the address where delivery problems are sent to, unless - the message contains an Errors-To: message header. + the message contains an Errors-To: message header. - -q Attempt to deliver all queued mail. This is imple- + -q Attempt to deliver all queued mail. This is imple- mented by executing the postqueue(1) command. -qinterval (ignored) - The interval between queue runs. Use the + The interval between queue runs. Use the queue_run_delay configuration parameter instead. -qRsite - Schedule immediate delivery of all mail that is + Schedule immediate delivery of all mail that is queued for the named site. This option accepts only - site names that are eligible for the "fast flush" - service, and is implemented by executing the + site names that are eligible for the "fast flush" + service, and is implemented by executing the postqueue(1) command. See flush(8) for more infor- mation about the "fast flush" service. -qSsite - This command is not implemented. Use the slower + This command is not implemented. Use the slower sendmail -q command instead. - -t Extract recipients from message headers. This - requires that no recipients be specified on the + -t Extract recipients from message headers. This + requires that no recipients be specified on the command line. - -v Enable verbose logging for debugging purposes. Mul- - tiple -v options make the software increasingly - verbose. For compatibility with mailx and other - mail submission software, a single -v option pro- - duces no output. + -v Send an email report of all delivery attempts (mail + delivery always happens in the background). When + multiple -v options are given, enable verbose log- + ging for debugging purposes. SECURITY By design, this program is not set-user (or group) id. diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 7e6267be3..d33b3af53 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -264,6 +264,9 @@ SMTP(8) SMTP(8) received, a warning is logged that the mail may be delivered multiple times. + smtp_rset_timeout + Timeout for sending the RSET command. + smtp_quit_timeout Timeout for sending the QUIT command, and for receiving the server response. diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 350f24942..c481f9155 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -344,15 +344,19 @@ SMTPD(8) SMTPD(8) maps_rbl_reject_code Response code when a request is RBL blacklisted. + multi_recipient_bounce_reject_code + Response code when a multi-recipient bounce is + blocked. + rbl_reply_maps - 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 reject_rbl_* and - reject_rhsbl_* restrictions. See also: + reject_rhsbl_* restrictions. See also: default_rbl_reply and smtpd_expansion_filter. reject_code - Response code when the client matches a reject + Response code when the client matches a reject restriction. relay_domains_reject_code @@ -360,7 +364,7 @@ SMTPD(8) SMTPD(8) mail relay policy. unknown_address_reject_code - Response code when a client violates the + Response code when a client violates the reject_unknown_address restriction. unknown_client_reject_code @@ -369,9 +373,17 @@ SMTPD(8) SMTPD(8) tion. unknown_hostname_reject_code - Response code when a client violates the + Response code when a client violates the reject_unknown_hostname restriction. + unverified_sender_reject_code + Response code when a sender address is known to be + undeliverable. + + unverified_recipient_reject_code + Response code when a recipient address is known to + be undeliverable. + SEE ALSO trivial-rewrite(8) address resolver cleanup(8) message canonicalization @@ -379,7 +391,7 @@ SMTPD(8) SMTPD(8) syslogd(8) system logging LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/trace.8.html b/postfix/html/trace.8.html new file mode 120000 index 000000000..4de6cc212 --- /dev/null +++ b/postfix/html/trace.8.html @@ -0,0 +1 @@ +bounce.8.html \ No newline at end of file diff --git a/postfix/html/uce.html b/postfix/html/uce.html index 03055c963..eee2d501d 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -686,6 +686,20 @@ is always 450 in case of a temporary DNS error.

    + + +

    reject_unverified_sender
    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 verify(8) +server. The unverified_sender_reject_code 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. + +

    +

    reject_rhsbl_sender domain.tld
    Reject the @@ -956,6 +970,16 @@ restriction at the end of all recipient restrictions.

    + + +

    reject_multi_recipient_bounce
    Reject the request +when the envelope sender is the null address, and the message has +multiple envelope recipients. The multi_recipient_bounce_reject_code + parameter specifies the response code for rejected requests +(default: 550). + +

    +

    reject_unknown_recipient_domain
    Reject the request @@ -966,6 +990,20 @@ is always 450 in case of a temporary DNS error.

    + + +

    reject_unverified_recipient
    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 verify(8) +server. The unverified_recipient_reject_code 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. + +

    +

    reject_rhsbl_recipient domain.tld
    Reject the diff --git a/postfix/html/verify.8.html b/postfix/html/verify.8.html new file mode 100644 index 000000000..f86eeb0db --- /dev/null +++ b/postfix/html/verify.8.html @@ -0,0 +1,152 @@ +
    +VERIFY(8)                                               VERIFY(8)
    +
    +NAME
    +       verify - Postfix address verification server
    +
    +SYNOPSIS
    +       verify [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  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:
    +
    +       VRFY_ADDR_UPDATE address status text
    +              Update the status of the specified address.
    +
    +       VRFY_ADDR_QUERY address
    +              Look up  the  status  and  text  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:
    +
    +       VRFYSTAT_OK
    +              The request completed normally.
    +
    +       VRFYSTAT_BAD
    +              The server rejected the request (bad request  name,
    +              bad request parameter value).
    +
    +       VRFYSTAT_FAIL
    +              The request failed.
    +
    +       The recipient status is one of:
    +
    +       DEL_RCPT_STAT_OK
    +              The address is deliverable.
    +
    +       DEL_RCPT_STAT_DEFER
    +              The  address  is  undeliverable  due to a temporary
    +              problem.
    +
    +       DEL_RCPT_STAT_BOUNCE
    +              The address is undeliverable  due  to  a  permanent
    +              problem.
    +
    +       DEL_RCPT_STAT_TODO
    +              The address status is being determined.
    +
    +SECURITY
    +       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 syslogd(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
    +       See  the  Postfix  main.cf file for syntax details and for
    +       default values. Use the postfix  reload  command  after  a
    +       configuration change.
    +
    +       address_verify_map
    +              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 postfix reload
    +              or postfix stop.
    +
    +              To recover from a  corrupted  address  verification
    +              database, delete the file and do postfix reload.
    +
    +       address_verify_sender
    +              The sender address to use for probe messages. Spec-
    +              ify an empty value (address_verify_sender =) or  <>
    +              if you want to use the null sender address.
    +
    +       address_verify_positive_expire_time
    +              The  amount  of time after which a known to be good
    +              address expires.
    +
    +       address_verify_positive_refresh_time
    +              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).
    +
    +       address_verify_negative_cache
    +              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.
    +
    +       address_verify_negative_expire_time
    +              The amount of time after which a  rejected  address
    +              expires.
    +
    +       address_verify_negative_refresh_time
    +              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
    +       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
    +
    +                                                        VERIFY(8)
    +
    diff --git a/postfix/man/Makefile.in b/postfix/man/Makefile.in index 279950201..3a54be60c 100644 --- a/postfix/man/Makefile.in +++ b/postfix/man/Makefile.in @@ -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 $? >$@ diff --git a/postfix/man/man1/postsuper.1 b/postfix/man/man1/postsuper.1 index 3d98b8b0a..4884c7202 100644 --- a/postfix/man/man1/postsuper.1 +++ b/postfix/man/man1/postsuper.1 @@ -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" diff --git a/postfix/man/man1/sendmail.1 b/postfix/man/man1/sendmail.1 index 785ded049..6e7f76e6b 100644 --- a/postfix/man/man1/sendmail.1 +++ b/postfix/man/man1/sendmail.1 @@ -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 diff --git a/postfix/man/man8/bounce.8 b/postfix/man/man8/bounce.8 index a1afc3faa..f36529add 100644 --- a/postfix/man/man8/bounce.8 +++ b/postfix/man/man8/bounce.8 @@ -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
    : text\fR. .IP \fBmail_name\fR Use this mail system name in the introductory text at the start of a bounce message. diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index 15bee3add..64fa7fae7 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -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. diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index e15f7919c..1b7d59fa3 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -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 index 000000000..411dfa138 --- /dev/null +++ b/postfix/man/man8/trace.8 @@ -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 index 000000000..6eb33a196 --- /dev/null +++ b/postfix/man/man8/verify.8 @@ -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 diff --git a/postfix/proto/Makefile.in b/postfix/proto/Makefile.in index 503ae4368..fadc14678 100644 --- a/postfix/proto/Makefile.in +++ b/postfix/proto/Makefile.in @@ -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/^/# /' >$@ diff --git a/postfix/src/bounce/Makefile.in b/postfix/src/bounce/Makefile.in index bd8451ea5..aafc24afb 100644 --- a/postfix/src/bounce/Makefile.in +++ b/postfix/src/bounce/Makefile.in @@ -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 diff --git a/postfix/src/bounce/bounce.c b/postfix/src/bounce/bounce.c index 83a0273ab..a4f77b2b9 100644 --- a/postfix/src/bounce/bounce.c +++ b/postfix/src/bounce/bounce.c @@ -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
    : 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); } diff --git a/postfix/src/bounce/bounce_append_service.c b/postfix/src/bounce/bounce_append_service.c index 82620f02b..3225b4787 100644 --- a/postfix/src/bounce/bounce_append_service.c +++ b/postfix/src/bounce/bounce_append_service.c @@ -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() @@ -39,6 +43,10 @@ #include #include +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + /* Utility library. */ #include @@ -48,9 +56,11 @@ /* Global library. */ +#include #include #include #include +#include /* 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 diff --git a/postfix/src/bounce/bounce_notify_service.c b/postfix/src/bounce/bounce_notify_service.c index 21652f6b0..8ce07c11c 100644 --- a/postfix/src/bounce/bounce_notify_service.c +++ b/postfix/src/bounce/bounce_notify_service.c @@ -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); diff --git a/postfix/src/bounce/bounce_notify_util.c b/postfix/src/bounce/bounce_notify_util.c index b8970025b..137c0c99d 100644 --- a/postfix/src/bounce/bounce_notify_util.c +++ b/postfix/src/bounce/bounce_notify_util.c @@ -21,11 +21,14 @@ /* 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) @@ -177,11 +180,11 @@ /* 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) diff --git a/postfix/src/bounce/bounce_notify_verp.c b/postfix/src/bounce/bounce_notify_verp.c index da4606397..0577ad4d0 100644 --- a/postfix/src/bounce/bounce_notify_verp.c +++ b/postfix/src/bounce/bounce_notify_verp.c @@ -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); diff --git a/postfix/src/bounce/bounce_one_service.c b/postfix/src/bounce/bounce_one_service.c index a654b8324..37210d6ce 100644 --- a/postfix/src/bounce/bounce_one_service.c +++ b/postfix/src/bounce/bounce_one_service.c @@ -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 diff --git a/postfix/src/bounce/bounce_service.h b/postfix/src/bounce/bounce_service.h index 22636e8c7..3c919e99b 100644 --- a/postfix/src/bounce/bounce_service.h +++ b/postfix/src/bounce/bounce_service.h @@ -21,22 +21,32 @@ /* * 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 index 000000000..4a142ffee --- /dev/null +++ b/postfix/src/bounce/bounce_trace_service.c @@ -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 +#include +#include +#include +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include +#include +#include +#include +#include + +/* 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 index 000000000..bbc3df298 --- /dev/null +++ b/postfix/src/bounce/bounce_warn_service.c @@ -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 +#include +#include +#include +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Utility library. */ + +#include +#include +#include + +/* Global library. */ + +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in index b5fc13992..362990e16 100644 --- a/postfix/src/cleanup/Makefile.in +++ b/postfix/src/cleanup/Makefile.in @@ -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 diff --git a/postfix/src/error/error.c b/postfix/src/error/error.c index 23a0e2553..72a7f4a10 100644 --- a/postfix/src/error/error.c +++ b/postfix/src/error/error.c @@ -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); diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index b9c37aa01..319924c46 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -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 diff --git a/postfix/src/global/bounce.c b/postfix/src/global/bounce.c index 8aa513966..e05c4e88c 100644 --- a/postfix/src/global/bounce.c +++ b/postfix/src/global/bounce.c @@ -65,7 +65,10 @@ /* 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. /* @@ -90,6 +93,15 @@ /* .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. @@ -138,7 +150,6 @@ #include #include /* 44BSD stdarg.h uses abort() */ -#include #include #include @@ -153,10 +164,13 @@ /* Global library. */ -#include "mail_params.h" -#include "mail_proto.h" -#include "defer.h" -#include "bounce.h" +#include +#include +#include +#include +#include +#include +#include /* 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); } diff --git a/postfix/src/global/bounce.h b/postfix/src/global/bounce.h index caaccbfb7..b8bb11757 100644 --- a/postfix/src/global/bounce.h +++ b/postfix/src/global/bounce.h @@ -17,6 +17,11 @@ #include #include + /* + * Global library. + */ +#include + /* * 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. diff --git a/postfix/src/global/bounce_log.c b/postfix/src/global/bounce_log.c index a063ede95..fb9dea27b 100644 --- a/postfix/src/global/bounce_log.c +++ b/postfix/src/global/bounce_log.c @@ -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; @@ -30,9 +32,12 @@ /* 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(). /* @@ -87,8 +92,10 @@ /* 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 @@ -120,30 +127,45 @@ /* Global library. */ +#include +#include #include #include /* 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 * (: 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); } diff --git a/postfix/src/global/bounce_log.h b/postfix/src/global/bounce_log.h index a478b7486..e09da9bac 100644 --- a/postfix/src/global/bounce_log.h +++ b/postfix/src/global/bounce_log.h @@ -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) diff --git a/postfix/src/global/defer.c b/postfix/src/global/defer.c index 324d9fc13..974eaaadf 100644 --- a/postfix/src/global/defer.c +++ b/postfix/src/global/defer.c @@ -45,7 +45,10 @@ /* 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. @@ -67,6 +70,15 @@ /* .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. @@ -127,12 +139,15 @@ /* 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 +#include +#include +#include +#include +#include +#include +#include +#include #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 */ diff --git a/postfix/src/global/defer.h b/postfix/src/global/defer.h index acc7bfb91..3bb8827f6 100644 --- a/postfix/src/global/defer.h +++ b/postfix/src/global/defer.h @@ -21,6 +21,7 @@ * Global library. */ #include +#include /* * External interface. diff --git a/postfix/src/global/deliver_request.h b/postfix/src/global/deliver_request.h index c7435afa7..124204a60 100644 --- a/postfix/src/global/deliver_request.h +++ b/postfix/src/global/deliver_request.h @@ -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 index 000000000..e42df7483 --- /dev/null +++ b/postfix/src/global/log_adhoc.c @@ -0,0 +1,127 @@ +/*++ +/* NAME +/* log_adhoc 3 +/* SUMMARY +/* ad-hoc delivery event logging +/* SYNOPSIS +/* #include +/* +/* 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 +#include /* 44BSD stdarg.h uses abort() */ +#include +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include + +/* 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 index 000000000..7e3108cfb --- /dev/null +++ b/postfix/src/global/log_adhoc.h @@ -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 +/* DESCRIPTION +/* .nf + + /* + * System library. + */ +#include +#include + + /* + * 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 diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c index 62c849a82..6d8389974 100644 --- a/postfix/src/global/mail_params.c +++ b/postfix/src/global/mail_params.c @@ -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; @@ -98,6 +100,8 @@ /* 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, }; diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index e2e7894c7..1da702a1e 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -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 diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index 6f6ab8ced..2b55f5cf8 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -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. diff --git a/postfix/src/global/mail_queue.h b/postfix/src/global/mail_queue.h index f18fb4516..b3d692821 100644 --- a/postfix/src/global/mail_queue.h +++ b/postfix/src/global/mail_queue.h @@ -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" diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index d27282ccd..bbc64e6fb 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,10 +20,10 @@ * 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; /* diff --git a/postfix/src/global/post_mail.c b/postfix/src/global/post_mail.c index 02e3faf0e..88a10943c 100644 --- a/postfix/src/global/post_mail.c +++ b/postfix/src/global/post_mail.c @@ -6,15 +6,28 @@ /* SYNOPSIS /* #include /* -/* 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; @@ -50,6 +63,12 @@ /* 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. /* @@ -71,17 +90,26 @@ /* .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\fR. +/* \fB\fR. +/* .IP trace_flags +/* Message tracing flags as specified in \fB\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\fR. @@ -116,6 +144,8 @@ #include #include #include +#include +#include /* Global library. */ @@ -127,10 +157,24 @@ #include #include + /* + * 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); } diff --git a/postfix/src/global/post_mail.h b/postfix/src/global/post_mail.h index 264afc77b..6863d4c63 100644 --- a/postfix/src/global/post_mail.h +++ b/postfix/src/global/post_mail.h @@ -24,8 +24,10 @@ /* * 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); diff --git a/postfix/src/global/sent.c b/postfix/src/global/sent.c index 37c1f2078..b2db87b85 100644 --- a/postfix/src/global/sent.c +++ b/postfix/src/global/sent.c @@ -6,7 +6,9 @@ /* SYNOPSIS /* #include /* -/* 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; @@ -23,11 +27,29 @@ /* 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 @@ -78,41 +100,73 @@ /* Global library. */ -#include "sent.h" +#include +#include +#include +#include +#include +#include + +/* 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); + } } diff --git a/postfix/src/global/sent.h b/postfix/src/global/sent.h index 92c441427..c552423d5 100644 --- a/postfix/src/global/sent.h +++ b/postfix/src/global/sent.h @@ -17,12 +17,19 @@ #include #include + /* + * Global library. + */ +#include + /* * 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 index 000000000..c517a4bee --- /dev/null +++ b/postfix/src/global/trace.c @@ -0,0 +1,199 @@ +/*++ +/* NAME +/* trace 3 +/* SUMMARY +/* user requested delivery tracing +/* SYNOPSIS +/* #include +/* +/* 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 +#include +#include /* 44BSD stdarg.h uses abort() */ +#include +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include +#include +#include +#include +#include +#include + +/* 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 index 000000000..b024c3209 --- /dev/null +++ b/postfix/src/global/trace.h @@ -0,0 +1,51 @@ +#ifndef _TRACE_H_INCLUDED_ +#define _TRACE_H_INCLUDED_ + +/*++ +/* NAME +/* trace 3h +/* SUMMARY +/* update user message delivery record +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * System library. + */ +#include +#include + + /* + * Global library. + */ +#include + + /* + * 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 index 000000000..6effb49d6 --- /dev/null +++ b/postfix/src/global/verify.c @@ -0,0 +1,159 @@ +/*++ +/* NAME +/* verify 3 +/* SUMMARY +/* update verify database +/* SYNOPSIS +/* #include +/* +/* 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 +#include +#include /* 44BSD stdarg.h uses abort() */ +#include +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include +#include +#include +#include +#include + +/* 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 index 000000000..1ecd4daa4 --- /dev/null +++ b/postfix/src/global/verify.h @@ -0,0 +1,48 @@ +#ifndef _VERIFY_H_INCLUDED_ +#define _VERIFY_H_INCLUDED_ + +/*++ +/* NAME +/* verify 3h +/* SUMMARY +/* update user message delivery record +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * System library. + */ +#include +#include + + /* + * Global library. + */ +#include + + /* + * 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 index 000000000..31532a357 --- /dev/null +++ b/postfix/src/global/verify_clnt.c @@ -0,0 +1,327 @@ +/*++ +/* NAME +/* verify_clnt 3 +/* SUMMARY +/* address verification client interface +/* SYNOPSIS +/* #include +/* +/* 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 +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include + +/* Global library. */ + +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..ebcac033e --- /dev/null +++ b/postfix/src/global/verify_clnt.h @@ -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 +/* DESCRIPTION +/* .nf + + /* + * System library. + */ +#include + + /* + * Global library. + */ +#include + + /* + * 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 diff --git a/postfix/src/lmtp/lmtp_chat.c b/postfix/src/lmtp/lmtp_chat.c index 40f594716..dfbeb4943 100644 --- a/postfix/src/lmtp/lmtp_chat.c +++ b/postfix/src/lmtp/lmtp_chat.c @@ -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; diff --git a/postfix/src/lmtp/lmtp_proto.c b/postfix/src/lmtp/lmtp_proto.c index ee990474b..b4afc37d0 100644 --- a/postfix/src/lmtp/lmtp_proto.c +++ b/postfix/src/lmtp/lmtp_proto.c @@ -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, diff --git a/postfix/src/lmtp/lmtp_trouble.c b/postfix/src/lmtp/lmtp_trouble.c index 9a15d4d8e..4c2916e3d 100644 --- a/postfix/src/lmtp/lmtp_trouble.c +++ b/postfix/src/lmtp/lmtp_trouble.c @@ -126,7 +126,6 @@ #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, diff --git a/postfix/src/local/Makefile.in b/postfix/src/local/Makefile.in index 15539ceed..96dcf6b9e 100644 --- a/postfix/src/local/Makefile.in +++ b/postfix/src/local/Makefile.in @@ -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 diff --git a/postfix/src/local/alias.c b/postfix/src/local/alias.c index 362b26df8..14b51eac9 100644 --- a/postfix/src/local/alias.c +++ b/postfix/src/local/alias.c @@ -87,6 +87,7 @@ #include #include #include +#include /* 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); diff --git a/postfix/src/local/command.c b/postfix/src/local/command.c index 9cbd1f706..50f8f9d85 100644 --- a/postfix/src/local/command.c +++ b/postfix/src/local/command.c @@ -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; diff --git a/postfix/src/local/dotforward.c b/postfix/src/local/dotforward.c index 6d0890fb2..307082169 100644 --- a/postfix/src/local/dotforward.c +++ b/postfix/src/local/dotforward.c @@ -78,6 +78,7 @@ #include #include #include +#include /* 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)); diff --git a/postfix/src/local/file.c b/postfix/src/local/file.c index 96663d3c4..7e5b73f66 100644 --- a/postfix/src/local/file.c +++ b/postfix/src/local/file.c @@ -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); } /* diff --git a/postfix/src/local/forward.c b/postfix/src/local/forward.c index 77ebc9282..9a9b148ca 100644 --- a/postfix/src/local/forward.c +++ b/postfix/src/local/forward.c @@ -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); diff --git a/postfix/src/local/include.c b/postfix/src/local/include.c index 0bac66ef9..53d31a447 100644 --- a/postfix/src/local/include.c +++ b/postfix/src/local/include.c @@ -68,6 +68,7 @@ #include #include #include +#include /* 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) diff --git a/postfix/src/local/indirect.c b/postfix/src/local/indirect.c index 88e63eb84..4b81777f0 100644 --- a/postfix/src/local/indirect.c +++ b/postfix/src/local/indirect.c @@ -49,6 +49,7 @@ #include #include #include +#include /* 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); } diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c index 4465de5d9..b0615286d 100644 --- a/postfix/src/local/local.c +++ b/postfix/src/local/local.c @@ -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); diff --git a/postfix/src/local/local.h b/postfix/src/local/local.h index ef1e256fb..32ad86d02 100644 --- a/postfix/src/local/local.h +++ b/postfix/src/local/local.h @@ -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 diff --git a/postfix/src/local/mailbox.c b/postfix/src/local/mailbox.c index e867988fa..7cbd8d7f0 100644 --- a/postfix/src/local/mailbox.c +++ b/postfix/src/local/mailbox.c @@ -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); diff --git a/postfix/src/local/maildir.c b/postfix/src/local/maildir.c index 02899263f..6ff172d4c 100644 --- a/postfix/src/local/maildir.c +++ b/postfix/src/local/maildir.c @@ -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); diff --git a/postfix/src/local/recipient.c b/postfix/src/local/recipient.c index e0b6443f4..761d58420 100644 --- a/postfix/src/local/recipient.c +++ b/postfix/src/local/recipient.c @@ -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)); /* diff --git a/postfix/src/local/resolve.c b/postfix/src/local/resolve.c index e718ddb26..f495b6d81 100644 --- a/postfix/src/local/resolve.c +++ b/postfix/src/local/resolve.c @@ -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)); diff --git a/postfix/src/local/token.c b/postfix/src/local/token.c index c427eb704..1da680c01 100644 --- a/postfix/src/local/token.c +++ b/postfix/src/local/token.c @@ -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 diff --git a/postfix/src/local/unknown.c b/postfix/src/local/unknown.c index 18774e44f..062a32888 100644 --- a/postfix/src/local/unknown.c +++ b/postfix/src/local/unknown.c @@ -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)); } diff --git a/postfix/src/nqmgr/Makefile.in b/postfix/src/nqmgr/Makefile.in index 771cac507..1b1b139b8 100644 --- a/postfix/src/nqmgr/Makefile.in +++ b/postfix/src/nqmgr/Makefile.in @@ -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 diff --git a/postfix/src/nqmgr/qmgr.h b/postfix/src/nqmgr/qmgr.h index 76bd52b3e..54d91e588 100644 --- a/postfix/src/nqmgr/qmgr.h +++ b/postfix/src/nqmgr/qmgr.h @@ -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 */ diff --git a/postfix/src/nqmgr/qmgr_active.c b/postfix/src/nqmgr/qmgr_active.c index dd0044b4c..67f574253 100644 --- a/postfix/src/nqmgr/qmgr_active.c +++ b/postfix/src/nqmgr/qmgr_active.c @@ -102,6 +102,7 @@ #include #include #include +#include #include #include @@ -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. diff --git a/postfix/src/nqmgr/qmgr_deliver.c b/postfix/src/nqmgr/qmgr_deliver.c index 759ab9fef..3405c5b76 100644 --- a/postfix/src/nqmgr/qmgr_deliver.c +++ b/postfix/src/nqmgr/qmgr_deliver.c @@ -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, diff --git a/postfix/src/nqmgr/qmgr_message.c b/postfix/src/nqmgr/qmgr_message.c index 83b7d5c9e..7d77c849c 100644 --- a/postfix/src/nqmgr/qmgr_message.c +++ b/postfix/src/nqmgr/qmgr_message.c @@ -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; } } diff --git a/postfix/src/pickup/pickup.c b/postfix/src/pickup/pickup.c index b8f697b28..281ee54ac 100644 --- a/postfix/src/pickup/pickup.c +++ b/postfix/src/pickup/pickup.c @@ -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) { diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c index 9cec20901..8dc0fe7f0 100644 --- a/postfix/src/pipe/pipe.c +++ b/postfix/src/pipe/pipe.c @@ -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 diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c index 46876ee9d..1565d2a17 100644 --- a/postfix/src/postsuper/postsuper.c +++ b/postfix/src/postsuper/postsuper.c @@ -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. diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in index 35212640b..e128810a7 100644 --- a/postfix/src/qmgr/Makefile.in +++ b/postfix/src/qmgr/Makefile.in @@ -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 diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h index f8beea116..e553e1793 100644 --- a/postfix/src/qmgr/qmgr.h +++ b/postfix/src/qmgr/qmgr.h @@ -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 */ diff --git a/postfix/src/qmgr/qmgr_active.c b/postfix/src/qmgr/qmgr_active.c index dd0044b4c..3e25b6323 100644 --- a/postfix/src/qmgr/qmgr_active.c +++ b/postfix/src/qmgr/qmgr_active.c @@ -102,6 +102,7 @@ #include #include #include +#include #include #include @@ -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. diff --git a/postfix/src/qmgr/qmgr_deliver.c b/postfix/src/qmgr/qmgr_deliver.c index 1986a0748..189baa5be 100644 --- a/postfix/src/qmgr/qmgr_deliver.c +++ b/postfix/src/qmgr/qmgr_deliver.c @@ -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, diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index 011f6020a..16a0c2245 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -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; } } diff --git a/postfix/src/sendmail/Makefile.in b/postfix/src/sendmail/Makefile.in index e6e96aa0f..50d16cca4 100644 --- a/postfix/src/sendmail/Makefile.in +++ b/postfix/src/sendmail/Makefile.in @@ -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 diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index 954bd0717..00785b831 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -114,6 +114,10 @@ /* .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 @@ -168,10 +172,9 @@ /* 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 @@ -319,6 +322,7 @@ #include #include #include +#include /* Application-specific. */ @@ -333,7 +337,7 @@ #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. */ diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 86b825ebe..420006b02 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -205,6 +205,8 @@ /* 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, diff --git a/postfix/src/smtp/smtp_chat.c b/postfix/src/smtp/smtp_chat.c index 092a5d197..566af74d6 100644 --- a/postfix/src/smtp/smtp_chat.c +++ b/postfix/src/smtp/smtp_chat.c @@ -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; diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index b5c3007a5..0ad53abeb 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -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; + } } } } diff --git a/postfix/src/smtp/smtp_trouble.c b/postfix/src/smtp/smtp_trouble.c index ef78e51f3..6269c7c4f 100644 --- a/postfix/src/smtp/smtp_trouble.c +++ b/postfix/src/smtp/smtp_trouble.c @@ -115,7 +115,6 @@ #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, diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 2f923e29a..7550d3d73 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -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 diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 3d4d294db..7db37ba26 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -265,6 +265,8 @@ /* 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 @@ -284,6 +286,10 @@ /* .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, }; diff --git a/postfix/src/smtpd/smtpd_chat.c b/postfix/src/smtpd/smtpd_chat.c index 692a52c6e..176933669 100644 --- a/postfix/src/smtpd/smtpd_chat.c +++ b/postfix/src/smtpd/smtpd_chat.c @@ -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; diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 450c3208e..7e3e5ca8e 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -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 @@ -137,6 +139,14 @@ /* 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. @@ -315,6 +325,7 @@ #include #include #include +#include /* 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, diff --git a/postfix/src/trivial-rewrite/resolve.c b/postfix/src/trivial-rewrite/resolve.c index 7a579df88..0be7fb623 100644 --- a/postfix/src/trivial-rewrite/resolve.c +++ b/postfix/src/trivial-rewrite/resolve.c @@ -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); diff --git a/postfix/src/trivial-rewrite/transport.c b/postfix/src/trivial-rewrite/transport.c index fa6080258..504a777d0 100644 --- a/postfix/src/trivial-rewrite/transport.c +++ b/postfix/src/trivial-rewrite/transport.c @@ -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 index 000000000..5c837eca6 --- /dev/null +++ b/postfix/src/verify/.indent.pro @@ -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 index 000000000..169affba0 --- /dev/null +++ b/postfix/src/verify/Makefile.in @@ -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 index 000000000..cc8e59530 --- /dev/null +++ b/postfix/src/verify/verify.c @@ -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 +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include +#include +#include +#include +#include + +/* Single server skeleton. */ + +#include + +/* 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); +} diff --git a/postfix/src/virtual/Makefile.in b/postfix/src/virtual/Makefile.in index da2dc414b..ecfc44fc0 100644 --- a/postfix/src/virtual/Makefile.in +++ b/postfix/src/virtual/Makefile.in @@ -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 diff --git a/postfix/src/virtual/mailbox.c b/postfix/src/virtual/mailbox.c index 442dc3e7a..87a8e691f 100644 --- a/postfix/src/virtual/mailbox.c +++ b/postfix/src/virtual/mailbox.c @@ -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); diff --git a/postfix/src/virtual/maildir.c b/postfix/src/virtual/maildir.c index de2637160..1ae9ce55e 100644 --- a/postfix/src/virtual/maildir.c +++ b/postfix/src/virtual/maildir.c @@ -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); diff --git a/postfix/src/virtual/unknown.c b/postfix/src/virtual/unknown.c index 8989046e0..b372c507b 100644 --- a/postfix/src/virtual/unknown.c +++ b/postfix/src/virtual/unknown.c @@ -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)); - } diff --git a/postfix/src/virtual/virtual.h b/postfix/src/virtual/virtual.h index 844441d5a..9145d5876 100644 --- a/postfix/src/virtual/virtual.h +++ b/postfix/src/virtual/virtual.h @@ -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, \ -- 2.47.3